Skip to content

feat(api): warehouse read API — games slice + gated deploy#86

Open
phenrickson wants to merge 11 commits into
mainfrom
feature/warehouse-api-games
Open

feat(api): warehouse read API — games slice + gated deploy#86
phenrickson wants to merge 11 commits into
mainfrom
feature/warehouse-api-games

Conversation

@phenrickson

Copy link
Copy Markdown
Owner

What this is

First slice of a warehouse read-API services layer: a gated FastAPI service
(bgg-warehouse-api) serving a single game's full profile from the warehouse's
materialized tables, so front-ends become pure HTTP consumers instead of reaching into
BigQuery directly.

What's included

  • config/bigquery.yaml — add predictions + analytics datasets
  • src/warehouse/bq.py — BigQuery client/dataset helper
  • src/warehouse/readers/games.pyget_game(id) = features + predictions + embedding + similar + provenance
  • services/warehouse_api/ — FastAPI app, /health, games router (GET /games/{id} + sub-resources)
  • services/warehouse_api/Dockerfile + .dockerignore
  • config/cloudbuild.warehouse-api.yaml + .github/workflows/deploy-warehouse-api.yml
  • Specs + plan under docs/superpowers/

Verification

  • 28 unit tests pass (reader with mocked BigQuery; router with mocked reader)
  • All 6 reader queries dry-run-validated against real schemas (a full game scans ~360 MB — unclustered serving tables; clusterBy game_id is a tracked follow-up)
  • Image builds; container /health → 200

What merging does

Deploys a new, standalone, gated Cloud Run service (--no-allow-unauthenticated),
scales to zero, no callers yet. Does not touch the data pipeline, Dataform, or
BigQuery data (separate cloudbuild file; no pipeline trigger paths touched). No version
bump, so no release is cut.

Follow-ups (separate PRs)

  • Gating (#PR2) — authoritative Terraform run.invoker binding. Merge after this PR (the service must exist first).
  • Front-end repoint (bgg-dash-viewer), games list/search, clusterBy game_id, other resource routers, and gating the predictive-models services.

🤖 Generated with Claude Code

phenrickson and others added 11 commits July 16, 2026 12:42
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Query SQL validated against real schemas via dry-run; a full game document
scans ~360MB (serving tables unclustered) — clusterBy game_id follow-up tracked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
/health plus games get-by-id and per-block sub-resources, over the games reader.
Cloud Run IAM handles caller auth; app uses ADC for BigQuery. Tests mock the reader.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
IAM + ID-token gating with an invoker Google Group as the grant surface; extensible
to the predictive-models services (all currently run.invoker: allUsers). Threads the
decision into the games plan (Task 7 + security follow-up).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… front-end)

Grant surface is the invoker group; day-one grant the owner's identity, not any
front-end SA. API knows nothing about its consumers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Image builds from repo root via uv sync --extra api; verified locally (docker run
-> /health 200). .dockerignore keeps credentials/.venv/.git out of the image.
Deps come from the root pyproject api extra; no service-local pyproject.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…binding

Task 7 reworked: compute deploy through a Cloud Build Actions workflow; run.invoker
gating as an authoritative google_cloud_run_v2_service_iam_binding applied by
terraform.yml (PR=plan, merge=apply). Two-merge ordering (service, then binding).
No local gcloud/terraform. Auth-pattern spec updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gated Cloud Run service (--no-allow-unauthenticated) built/deployed by
config/cloudbuild.warehouse-api.yaml, triggered by deploy-warehouse-api.yml on push
to main. Invoker gating lives in Terraform (separate PR).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rface

Access grants become a members-list edit -> PR -> apply via Actions (git-audited),
instead of manual Google Group membership (which is outside Actions). Group demoted
to an optional footnote.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant