-
Notifications
You must be signed in to change notification settings - Fork 8
feat(region-pages): bring f3-region-pages into the monorepo #302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
pstaylor-patrick
wants to merge
13
commits into
dev
Choose a base branch
from
feat/region-pages-into-monorepo
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
34feb1e
feat(region-pages): bring f3-region-pages into the monorepo (apps/regβ¦
pstaylor-patrick d3cb196
chore(region-pages): integrate into monorepo build (single lockfile, β¦
pstaylor-patrick eaa5af2
chore(region-pages): align deps to monorepo, prune cruft, squash migrβ¦
pstaylor-patrick 05ea827
fix(region-pages): make build resilient to absent DB (CI build job)
pstaylor-patrick 37b9a9c
fix(region-pages): revert turbo.json env change that broke other appsβ¦
pstaylor-patrick 80591b3
chore(region-pages): align local-dev with monorepo docker/env patterns
pstaylor-patrick f2cffc8
fix(region-pages): address PR review findings (Copilot)
pstaylor-patrick e468530
feat(region-pages): canonical-host redirect middleware + canonical taβ¦
pstaylor-patrick 9363fcc
feat(region-pages): add Cloud Run domain-mapping routing (drops ~$20/β¦
pstaylor-patrick 53451c5
infra(region-pages): reconcile to 100% Terraform + drift-detection CI
pstaylor-patrick 2f4a9d1
infra(region-pages): CI SA needs bucket storage.admin for plan IAM reβ¦
pstaylor-patrick 3d95140
chore(region-pages): move devDependencies to PNPM catalog; declare apβ¦
pstaylor-patrick 4e3837b
fix(map): stop redeclaring global jest in test setup (collides with @β¦
pstaylor-patrick File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| name: region-pages Terraform Drift | ||
|
|
||
| # Enforces the zero-drift rule for the region-pages GCP project: the committed | ||
| # Terraform under apps/region-pages/infra/terraform/cloud-run is the source of | ||
| # truth. This workflow runs `terraform plan` and fails if live infrastructure | ||
| # has drifted from the code β daily (catch console drift) and on every PR that | ||
| # touches the Terraform (catch drift before merge). | ||
| # | ||
| # Auth is keyless via the F3-Nation org Workload Identity pool (vars.WIF_PROVIDER, | ||
| # the same provider the deploy-* workflows use), impersonating the read-only | ||
| # github-actions-deploy@region-pages SA created in ci.tf. | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "0 13 * * *" # daily at 13:00 UTC (~7-8am Central) | ||
| pull_request: | ||
| paths: | ||
| - "apps/region-pages/infra/terraform/cloud-run/**" | ||
| - ".github/workflows/region-pages-terraform-drift.yml" | ||
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: region-pages-tf-drift | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| pull-requests: write | ||
|
|
||
| jobs: | ||
| drift: | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: apps/region-pages/infra/terraform/cloud-run | ||
| env: | ||
| # Plan only β never applied. secret_data and the image tag are ignored by | ||
| # the config (see secrets.tf / main.tf lifecycle blocks), so placeholders | ||
| # produce no diff and the workflow never touches real secret values. | ||
| TF_VAR_image: "ci-plan-placeholder" | ||
| TF_VAR_secret_values: >- | ||
| {"postgres-url":"x","f3-data-warehouse-url":"x","cloud-sql-warehouse-connection-name":"x","warehouse-db-user":"x","warehouse-db-password":"x","warehouse-db-name":"x","cron-secret":"x","slack-bot-auth-token":"x","slack-channel-id":"x"} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Authenticate to GCP (Workload Identity Federation) | ||
| uses: google-github-actions/auth@v2 | ||
| with: | ||
| workload_identity_provider: ${{ vars.WIF_PROVIDER }} | ||
| service_account: github-actions-deploy@region-pages.iam.gserviceaccount.com | ||
|
|
||
| - name: Set up Cloud SDK | ||
| uses: google-github-actions/setup-gcloud@v2 | ||
|
|
||
| - name: Set up Terraform | ||
| uses: hashicorp/setup-terraform@v3 | ||
| with: | ||
| terraform_version: "1.15.3" | ||
|
|
||
| - name: Terraform init | ||
| run: terraform init -input=false | ||
|
|
||
| - name: Terraform plan (detect drift) | ||
| id: plan | ||
| run: | | ||
| set +e | ||
| terraform plan -input=false -lock=false -no-color -detailed-exitcode | ||
| code=$? | ||
| set -e | ||
| echo "exitcode=$code" >> "$GITHUB_OUTPUT" | ||
| # 0 = in sync, 2 = drift detected, 1 = error | ||
| if [ "$code" = "1" ]; then | ||
| echo "::error::terraform plan failed." | ||
| exit 1 | ||
| elif [ "$code" = "2" ]; then | ||
| echo "::error::Drift detected β region-pages infrastructure no longer matches Terraform. Reconcile by applying the committed config or importing the change." | ||
| exit 2 | ||
| else | ||
| echo "No drift β region-pages matches Terraform." | ||
| fi | ||
|
|
||
| - name: Comment drift result on PR | ||
| if: github.event_name == 'pull_request' && always() | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const code = '${{ steps.plan.outputs.exitcode }}'; | ||
| const body = code === '0' | ||
| ? 'β **region-pages Terraform drift check:** in sync β live infrastructure matches the committed config.' | ||
| : code === '2' | ||
| ? 'β οΈ **region-pages Terraform drift check:** drift detected β `terraform plan` shows changes. Reconcile before merge (apply the committed config or import the out-of-band change).' | ||
| : 'β **region-pages Terraform drift check:** `terraform plan` errored. See the job logs.'; | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.issue.number, | ||
| body, | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -68,4 +68,4 @@ pr.md | |
| .eslintcache | ||
|
|
||
| # claude code | ||
| .claude/worktrees/ | ||
| .claude/worktrees/.secrets/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| node_modules | ||
| .next | ||
| .git | ||
| .github | ||
| .env | ||
| .env.* | ||
| !.env.example | ||
| npm-debug.log* | ||
| firebase-debug.log* | ||
| firebase-debug.*.log | ||
| .firebase | ||
| infra | ||
| coverage | ||
| .DS_Store | ||
| *.local | ||
| .secrets |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # ============================================================================= | ||
| # F3 Region Pages β Local Development Environment (example) | ||
| # ============================================================================= | ||
| # Copy to .env.local and fill in values. Aligns with the repo-wide local dev | ||
| # stack (root docker-compose.yml): Postgres on :5433. Start it first: | ||
| # | ||
| # docker compose up -d # from the monorepo root | ||
| # pnpm --filter f3-region-pages db:setup:local # migrate + seed | ||
| # | ||
| # env.ts loads .env.${NODE_ENV} (NODE_ENV defaults to "local" for db tooling; | ||
| # Next.js also auto-loads .env.local in dev). | ||
|
|
||
| # -- App database (region-pages' own schema; shared local Postgres) ----------- | ||
| # Its Drizzle migrations create the region-pages tables in this database. | ||
| POSTGRES_URL=postgresql://f3local:f3local@localhost:5433/f3nation | ||
|
|
||
| # -- F3 data warehouse (read-only source the ingest reads from) --------------- | ||
| # `direct` mode requires a real warehouse connection string (from GCP Secret | ||
| # Manager / a read replica). Point it at the warehouse you have access to. | ||
| WAREHOUSE_DB_CONNECTION_MODE=direct | ||
| F3_DATA_WAREHOUSE_URL=postgresql://USER:PASS@WAREHOUSE_HOST:5432/f3data | ||
|
|
||
| # -- Ingest cron endpoint (POST /api/ingest) ---------------------------------- | ||
| CRON_SECRET=local-dev-cron-secret-change-me | ||
|
|
||
| # -- Slack notifications (ingest success/failure/skip) β optional locally ------ | ||
| SLACK_BOT_AUTH_TOKEN=xoxb-... | ||
| SLACK_CHANNEL_ID= | ||
|
|
||
| NODE_ENV=local | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm familiar with the usage of |
||
|
|
||
| # -- Canonical domain / SEO (production) -------------------------------------- | ||
| # Base URL used for metadataBase, canonical tags, OpenGraph. Set to the canonical | ||
| # domain in prod (e.g. https://regions.f3nation.com); defaults to f3workouts.com. | ||
| # NEXT_PUBLIC_URL=https://regions.f3nation.com | ||
| # | ||
| # When set, src/middleware.ts 308-redirects any non-canonical host (e.g. | ||
| # f3regions.com, f3region.info) to this host, preserving path+query. Leave UNSET | ||
| # until regions.f3nation.com is cut over β middleware is inert without it. | ||
| # NEXT_PUBLIC_CANONICAL_HOST=regions.f3nation.com | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
|
||
| # dependencies | ||
| /node_modules | ||
| /.pnp | ||
| .pnp.* | ||
| .yarn/* | ||
| !.yarn/patches | ||
| !.yarn/plugins | ||
| !.yarn/releases | ||
| !.yarn/versions | ||
|
|
||
| # testing | ||
| /coverage | ||
|
|
||
| # next.js | ||
| /.next/ | ||
| /out/ | ||
|
|
||
| # production | ||
| /build | ||
|
|
||
| # misc | ||
| .DS_Store | ||
| *.pem | ||
|
|
||
| # debug | ||
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* | ||
| .pnpm-debug.log* | ||
|
|
||
| # env files (can opt-in for committing if needed) | ||
| .env* | ||
| !.env*.example | ||
|
|
||
| # vercel | ||
| .vercel | ||
|
|
||
| # typescript | ||
| *.tsbuildinfo | ||
| next-env.d.ts | ||
|
|
||
| firebase-debug.log | ||
| pr.md.context/**/logs.json | ||
| .context/logs.json | ||
| pr.md | ||
| tsconfig.tsbuildinfo | ||
| pglite-debug.log | ||
| .vscode/ | ||
| *.log |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # Ignore build directories | ||
| .next | ||
| node_modules | ||
| drizzle/migrations | ||
|
|
||
| # Ignore other common files | ||
| *.min.js | ||
| *.bundle.js | ||
| *.map | ||
| pnpm-lock.yaml |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "semi": true, | ||
| "singleQuote": true, | ||
| "trailingComma": "es5", | ||
| "tabWidth": 2, | ||
| "printWidth": 80 | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| CLAUDE.md |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # CLAUDE.md β LLM Context Index | ||
|
|
||
| > **Meta: This file MUST stay <8kb, compressed, LLM-friendly (not human-friendly). When editing, preserve density. Strip prose, use terse notation. This is a machine-readable index, not documentation.** | ||
|
|
||
| ## Stack | ||
|
|
||
| Next.js 15 / React 19 / TypeScript (strict, `@/*` = `./src/*`) / Drizzle ORM / PostgreSQL (Supabase) / TailwindCSS / Node 20.18.2 (`.nvmrc`) | ||
|
|
||
| ## Commands | ||
|
|
||
| ``` | ||
| dev # localhost:3000 | ||
| build # ~480 static pages | ||
| lint | format | typecheck | test | test:watch | test:coverage (70% threshold) | ||
| db:setup:local | db:migrate | db:push | db:seed | db:reset | db:generate:migration | ||
| ``` | ||
|
|
||
| ## Architecture | ||
|
|
||
| - RSC default; `'use client'` only for interactivity | ||
| - Build-aware cache keys via `NEXT_BUILD_ID` β see `src/utils/fetchWorkoutLocations.ts` / `getBuildAwareCacheKey()` | ||
| - ISR via `generateStaticParams()` in `[regionSlug]/page.tsx` | ||
| - Chunk error recovery: `src/components/ChunkErrorRecovery.tsx` | ||
|
|
||
| ## Key Files | ||
|
|
||
| ``` | ||
| drizzle/schema.ts # DB schema (regions, workouts, seedRuns) | ||
| drizzle/db.ts # DB instance | ||
| src/utils/fetchWorkoutLocations.ts # Central data fetch + caching | ||
| src/app/[regionSlug]/page.tsx # Region page (ISR) | ||
| src/app/api/ingest/route.ts # Cron ingest endpoint | ||
| src/components/ChunkErrorRecovery.tsx # Client chunk error recovery | ||
| ``` | ||
|
|
||
| ## API: POST /api/ingest | ||
|
|
||
| Upstash QStash cron. Bearer `CRON_SECRET`. Idempotent (20h window). Prunes stale data, seeds regions/workouts from warehouse, enriches metadata. Slack notifications on all outcomes (success/failure/skip). See `.context/slack.md`. | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:3000/api/ingest -H "Authorization: Bearer $CRON_SECRET" | ||
| ``` | ||
|
|
||
| ## Env (`.env.local.example`) | ||
|
|
||
| ``` | ||
| POSTGRES_URL # Supabase connection | ||
| F3_DATA_WAREHOUSE_URL # Warehouse connection | ||
| CRON_SECRET # Ingest auth | ||
| SLACK_BOT_AUTH_TOKEN # Bot OAuth token (xoxb-...) | ||
| SLACK_CHANNEL_ID # Notification channel | ||
| ``` | ||
|
|
||
| ## Agent Skills (`.agents/skills/`) | ||
|
|
||
| - `vercel-react-best-practices` β 57 React/Next.js perf rules (8 categories). Use when writing/reviewing components. | ||
| - `vercel-composition-patterns` β Composition patterns for scalable components. Use for boolean-prop refactors, reusable APIs, React 19 patterns. | ||
|
|
||
| ## Context Index (`.context/`) | ||
|
|
||
| | File | Topic | | ||
| | ---------- | ------------------------------------------------------------------------------------------------------- | | ||
| | `slack.md` | Slack bot integration: `sendSlackNotification`, env vars, notification triggers, warehouse Slack tables | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # Contributing to F3 Region Pages | ||
|
|
||
| Thank you for your interest in contributing to the F3 Region Pages project! This guide will help you get started with the development environment setup and basic workflow. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - [Node.js](https://nodejs.org/) >= 24.14.1 (monorepo `engines.node`; see root `.nvmrc`) | ||
| - [pnpm](https://pnpm.io/) (the monorepo package manager) | ||
| - [Docker](https://www.docker.com/) (for the shared local database β root `docker-compose.yml`) | ||
| - [Docker](https://www.docker.com/) (for local database setup) | ||
|
|
||
| ## Development Environment Setup | ||
|
|
||
| 1. **Clone the repository** | ||
|
|
||
| ```bash | ||
| git clone https://github.com/F3-Nation/f3-region-pages.git | ||
| cd f3-region-pages | ||
| ``` | ||
|
|
||
| 2. **Set up Node.js environment** | ||
|
|
||
| ```bash | ||
| nvm install # Installs the version specified in the root .nvmrc (24.14.1) | ||
| nvm use # Switches to the project's Node.js version | ||
| ``` | ||
|
|
||
| 3. **Install development dependencies** | ||
|
|
||
| ```bash | ||
| npm i -D # Shorthand for npm install --save-dev | ||
| ``` | ||
|
|
||
| 4. **Set up local database** | ||
|
|
||
| ```bash | ||
| npm run db:setup:local # Starts Supabase, sets up environment, and seeds database | ||
| ``` | ||
|
|
||
| 5. **Start the development server** | ||
|
|
||
| ```bash | ||
| npm run dev # Starts Next.js development server | ||
| ``` | ||
|
|
||
| The application will be available at [http://localhost:3000](http://localhost:3000) | ||
|
|
||
| ## Available Scripts | ||
|
|
||
| - `npm run dev` - Start development server | ||
| - `npm run build` - Build for production | ||
| - `npm run test` - Run tests | ||
| - `npm run lint` - Run linting | ||
| - `pnpm db:setup:local` - One-shot local DB setup (starts the shared Postgres via root `docker compose`, migrates, seeds) | ||
| - `pnpm db:reset` - Reset the database | ||
| - `pnpm db:migrate` - Run database migrations | ||
| - `pnpm db:seed` - Seed the database with initial data | ||
|
|
||
| ## Workflow | ||
|
|
||
| 1. Create a new branch for your feature or bugfix | ||
| 2. Make your changes | ||
| 3. Write tests for your changes | ||
| 4. Run tests and make sure they pass | ||
| 5. Submit a pull request | ||
|
|
||
| ## Code Style and Guidelines | ||
|
|
||
| This project follows the Next.js conventions and uses TypeScript. Please ensure your code is properly typed and follows the existing patterns in the codebase. | ||
|
|
||
| ## Need Help? | ||
|
|
||
| If you have any questions or need help, please open an issue on the GitHub repository. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This
.env.local.examplefile is used to create the local dev's.envfile for this app. Could this URL be changed to point to a valid PG DB that's running locally in Docker?