No description
  • Python 75.3%
  • Svelte 13.3%
  • TypeScript 4.8%
  • PLpgSQL 4.1%
  • CSS 1.4%
  • Other 1.1%
Find a file
BrendanLipton b314f4b5f6
All checks were successful
Build and Deploy Svelte App / build-and-deploy (push) Successful in 51s
Constrain scoring to Cortina's work: creative media, not hardware
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>
2026-09-18 07:29:47 -04:00
.claude Adapt to Cortina Svelte Base Template + PocketBase; activate main.yml 2026-09-17 10:05:17 -04:00
.forgejo/workflows Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
config Constrain scoring to Cortina's work: creative media, not hardware 2026-09-18 07:29:47 -04:00
docs Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
figma_assets Initial commit: Museum Interactive & Film Opportunity Dashboard 2026-09-17 09:41:48 -04:00
fixtures/sources Wire up real collection: fix live adapters, add sector-aware scoring 2026-09-17 13:55:16 -04:00
migrations Initial commit: Museum Interactive & Film Opportunity Dashboard 2026-09-17 09:41:48 -04:00
packages Clean summaries, seed real watchlist, drop past-deadline bids 2026-09-17 14:08:59 -04:00
pb Clean summaries, seed real watchlist, drop past-deadline bids 2026-09-17 14:08:59 -04:00
scripts Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
src Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
static Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
workers Constrain scoring to Cortina's work: creative media, not hardware 2026-09-18 07:29:47 -04:00
.env.example Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
.gitignore Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
docker-compose.yml Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
package-lock.json Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
package.json Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
pyproject.toml Initial commit: Museum Interactive & Film Opportunity Dashboard 2026-09-17 09:41:48 -04:00
README.md Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00
requirements-optional.txt Initial commit: Museum Interactive & Film Opportunity Dashboard 2026-09-17 09:41:48 -04:00
requirements.txt Initial commit: Museum Interactive & Film Opportunity Dashboard 2026-09-17 09:41:48 -04:00
svelte.config.js Initial commit 2026-09-04 18:15:59 +00:00
tsconfig.json Initial commit 2026-09-04 18:15:59 +00:00
vite.config.ts Align PocketBase usage with Cortina agent conventions 2026-09-17 10:33:35 -04:00

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:

  1. AZURE_DESTINATION — folder on the cortinabuilds bucket (e.g. RFP-Dashboard)
  2. SOURCE — build output dir: build
  3. STORAGE_ACCOUNT_NAME, PACKAGE_TOKEN
  4. POCKETBASE_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

The earlier FastAPI + Next.js implementation is preserved in git history (tag fastapi-nextjs-stack).

Ground rules (enforced in code)

  1. Recall first: nothing is hard-deleted by keyword; low-signal records score low.
  2. Search documents, not only titles (attachment text re-enters rules/scoring).
  3. Every claim links to a source URL with retrieval time (evidence array).
  4. Class D (paid) and E (blocked) sources cannot be enabled — validated at load.
  5. No invented budgets/deadlines/contacts; estimates are flagged and explained.
  6. Human-controlled outreach only; the system never contacts buyers.
  7. museum is never a mandatory term; codes broaden and never gate retrieval.