- Python 75.3%
- Svelte 13.3%
- TypeScript 4.8%
- PLpgSQL 4.1%
- CSS 1.4%
- Other 1.1%
|
All checks were successful
Build and Deploy Svelte App / build-and-deploy (push) Successful in 51s
Cortina is a creative studio (media, interactive, linear film/video), not a hardware supplier, builder, or general-services contractor. Three gates now keep the review queue to genuine creative opportunities; everything else stays in the pipeline (full recall) but drops to the archive band. - Out-of-scope gate: hardware/equipment supply, construction/renovation, and non-media services (security, cleaning, catering, facilities, auditing, marketing) archive the record unless a creative-production signal is present. Covers the user's examples (passenger lift, smart-classroom equipment) plus showcase/lighting supply, and includes common non-English terms (ES/FR/IT/ PT/DE/PL) since World Bank/TED notices are multilingual. - Capability gate: an opportunity must actually involve Cortina work — a media/interactive/film capability or a museum-exhibition code. A venue term alone (a grant, land acquisition, survey, or supply contract merely located at a museum/park) is not an opportunity. - Sector-context gate now also caps capability points, so a bare AV/film match with no museum/cultural context can't reach the review band. New taxonomy families in config/taxonomy/exclusions.yaml: hardware_construction (+ multilingual), creative_production (+ multilingual). Loaded by taxonomy.py, matched in rules.py, applied in scoring.py. 52 tests passing (new cases: passenger lift and smart-classroom excluded; interactive exhibit with equipment kept). Effect on the current data: the review queue is small but precise — the free non-US sources presently offer few open museum-media bids, and most are past deadline or historical awards. SAM.gov (US federal, the richest source of US museum interactive/AV/film RFPs) still needs an api.data.gov key to add volume. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .claude | ||
| .forgejo/workflows | ||
| config | ||
| docs | ||
| figma_assets | ||
| fixtures/sources | ||
| migrations | ||
| packages | ||
| pb | ||
| scripts | ||
| src | ||
| static | ||
| workers | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| package-lock.json | ||
| package.json | ||
| pyproject.toml | ||
| README.md | ||
| requirements-optional.txt | ||
| requirements.txt | ||
| svelte.config.js | ||
| tsconfig.json | ||
| vite.config.ts | ||
Museum Interactive & Film Opportunity Dashboard
Internal Cortina system that continuously discovers, normalizes, scores, and alerts on public opportunities for museum interactive design, AV/multimedia exhibits, film/documentary production, immersive installations, and adjacent exhibit-design work that may carry a media subcontract.
Built on the Cortina Svelte Base Template: a static SvelteKit site deployed to Azure Blob via Forgejo Actions, reading data from PocketBase. The collection engine is Python (adapters → normalize → dedupe → score) and pushes results into PocketBase.
free public sources ──► Python collectors (workers/) ──► SQLite/Postgres pipeline
│
▼ workers.cli push-pb
PocketBase
▲
SvelteKit site (src/) reads/writes REST
deployed static to Azure Blob ($web/<AZURE_DESTINATION>)
Two feeds
- Bid now — published RFPs/RFQs/RFIs/ITBs/tenders Cortina can respond to
- Shape & track — grants, awards, plans, and other early signals (3–24 months out)
Site (SvelteKit, repo root)
npm install # uses the Cortina registry for @cortina components
npm run dev # http://localhost:5173
npm run build # static build/ (what the pipeline uploads)
Pages: overview (/), feed (/feed), detail (/opportunity?id=…),
watchlist (/organizations), source health (/sources).
PocketBase config comes from .env (gitignored), inlined at build time by
vite.config.ts via loadEnv — never from static/config.json
(remoteBaseUrl there is reserved for the CMS). The shared instance is
https://cortina-pocketbase.eastus.azurecontainer.io; all collections are
prefixed rfp_dashboard_. The site authenticates as a regular application
user (POCKETBASE_USER_EMAIL/POCKETBASE_USER_PASSWORD); admin credentials
are used only by scripts/pb_apply_schema.py for schema management. Copy
.env.example to .env and fill in credentials before npm run dev.
Collectors + PocketBase (Python)
py -3.11 -m venv .venv
.venv\Scripts\python -m pip install -r requirements.txt
.venv\Scripts\python -m pytest # 49 tests, fixture-based
.venv\Scripts\python scripts\seed_demo.py # fixtures through the real pipeline
.venv\Scripts\python -m workers.cli run --source sam-gov
.venv\Scripts\python -m workers.cli run-due --loop # scheduled collection
# push pipeline results into PocketBase
.venv\Scripts\python scripts\pb_apply_schema.py # one-time: create collections
.venv\Scripts\python -m workers.cli push-pb # sync opportunities/sources/orgs
PocketBase settings in .env: POCKETBASE_URL, POCKETBASE_ADMIN_EMAIL,
POCKETBASE_ADMIN_PASSWORD. Run PocketBase locally with
pocketbase serve (single binary, https://pocketbase.io/docs/) or
docker compose up (PocketBase + worker + scheduler).
Build pipeline (Forgejo Actions)
.forgejo/workflows/main.yml is active (the PocketBase variant: it writes
.env from Forgejo vars/secrets before building, since .env is gitignored
and vite.config.ts inlines those values). Every push to main builds the
site and uploads it to Azure Blob. Under repo Settings → Actions:
Variables:
AZURE_DESTINATION— folder on the cortinabuilds bucket (e.g.RFP-Dashboard)SOURCE— build output dir:buildSTORAGE_ACCOUNT_NAME,PACKAGE_TOKENPOCKETBASE_URL,POCKETBASE_USER_EMAIL
Secrets:
5. AZURE_STORAGE_SAS, POCKETBASE_USER_PASSWORD
These must be set in the repo (or org) Actions settings before a deploy will
succeed — an agent can't verify or set them. If unsure of values, check with
Alex. main.yml.bk (the non-PocketBase variant) and branch-deploy.yml /
tag_deploy.yml remain from the template.
Key documents
- docs/architecture.md — data flow and design decisions
- docs/legal.md — source policy, access classes A–E, crawler rules
- docs/runbook.md — operations, adding sources, troubleshooting
- pb/pb_schema.json — PocketBase collections
- packages/schemas/opportunity.schema.json — canonical schema
The earlier FastAPI + Next.js implementation is preserved in git history
(tag fastapi-nextjs-stack).
Ground rules (enforced in code)
- Recall first: nothing is hard-deleted by keyword; low-signal records score low.
- Search documents, not only titles (attachment text re-enters rules/scoring).
- Every claim links to a source URL with retrieval time (evidence array).
- Class D (paid) and E (blocked) sources cannot be enabled — validated at load.
- No invented budgets/deadlines/contacts; estimates are flagged and explained.
- Human-controlled outreach only; the system never contacts buyers.
museumis never a mandatory term; codes broaden and never gate retrieval.