feat(dev): local Supabase dev environment + Google-only local auth - #372

Merged
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev
Jul 22, 2026
Merged

feat(dev): local Supabase dev environment + Google-only local auth#372
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev

Conversation

@AndresL230

@AndresL230AndresL230 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A one-command local Supabase dev environment (rootless Podman) so the app runs full-stack against a local DB instead of the live staging DB — and teammates can reproduce it.

Contents

  • supabase/config.toml — local stack; analytics/edge-runtime disabled, auto_expose_new_tables=true (so migration-created tables are reachable by the Data API roles, matching hosted Supabase).
  • scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate): migrate → reload PostgREST → seed.
  • backend/.env.local.example + frontend/.env.local.example — turnkey local env with fixed, local-only keys (safe to commit).
  • backend/db/seed_local_catalog.py — pulls the real ~8k-course catalog from a remote Supabase over its REST API (read-only source; unencrypted catalog only).
  • docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
  • Migration guards (0021_gradebook, 0021_gradebook_curve, 0027_gradescope) — IF NOT EXISTS / user_coursesenrollments retargets so the chain replays cleanly from an empty DB. No-ops on already-migrated databases (staging/prod unaffected).
  • routes/auth.pyIS_LOCAL auto-approve — a first local Google sign-in skips the /pending wall. Strictly APP_ENV-gated; prod keeps the real approval gate.
  • Frontend mock removal — deletes lib/localData.ts + every IS_LOCAL_MODE branch (single source of truth; tsc clean).

Teammate setup

cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock" # fish
supabase start && scripts/local-up.sh
# then: (backend) python main.py (frontend) npm run dev → sign in with Google

Full guide: docs/local-supabase.md.

Notes

  • Rebased onto main (was originally cut from feat/streaming-tutor). The frontend mock removal and the auth.py auto-approve were re-resolved against main's versions during the rebase; conflicts were only in api.ts (re-stripped) and localData.ts (deleted).
  • Replay re-verified from empty against main's full setApplied 34 migration(s) including main's 0031, then storage buckets + seed + catalog pull, decryption, and the Google redirect all healthy; tsc clean.

Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a complete local Supabase setup with starter environment templates, seeded catalog support, and scripts to start or reset the local stack.
    • Added local Google OAuth sign-in with automatic approval for local development.
  • Bug Fixes
    • Local database migrations and indexes can now be safely rerun.
    • Improved avatar refresh behavior so updated profile images appear promptly.
  • Documentation
    • Added comprehensive local Supabase setup, configuration, OAuth, reset, and troubleshooting guidance.
  • Refactor
    • Removed mock-data local mode; local development now uses the real backend and services.

@AndresL230AndresL230 self-assigned this Jul 21, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging6765f49Commit Preview URL

Branch Preview URL
Jul 22 2026, 04:09 AM

@coderabbitai

coderabbitaiBot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 5fc87496-1065-4f97-a759-3ef2155194bb

📥 Commits

Reviewing files that changed from the base of the PR and between 73e989b and 6765f49.

📒 Files selected for processing (7)
  • backend/.env.local.example
  • backend/db/migrations/0021_gradebook.sql
  • backend/db/migrations/0027_gradescope.sql
  • backend/routes/auth.py
  • docs/local-supabase.md
  • scripts/lib/local-common.sh
  • scripts/local-up.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/.env.local.example
  • scripts/local-up.sh
  • backend/db/migrations/0027_gradescope.sql
  • docs/local-supabase.md
  • scripts/lib/local-common.sh

📝 Walkthrough

Walkthrough

The PR adds a local Supabase development stack, makes migrations replay-safe, adds catalog synchronization and local setup scripts, enables local OAuth approval, and removes frontend mock local mode in favor of real backend and Supabase integrations.

Changes

Local Supabase development

Layer / File(s)Summary
Environment and service configuration
.gitignore, backend/.env.local.example, frontend/.env.local.example, supabase/*, docs/local-supabase.md
Adds local environment templates, Supabase service configuration, ignored local secrets, and setup/troubleshooting documentation.
Replay-safe database migrations
backend/db/migrations/*
Retargets curve-policy columns and constraints to enrollments and makes gradebook and Gradescope schema changes rerunnable.
Local stack automation
scripts/*
Adds startup/reset workflows for migrations, storage buckets, PostgREST reloads, readiness checks, and demo seeding.
Catalog synchronization
backend/db/seed_local_catalog.py
Fetches remote courses and offerings with pagination and upserts them into local Supabase in batches.
Local OAuth approval
backend/routes/auth.py
Auto-approves newly created Google OAuth users when APP_ENV is local.
Real frontend integrations
frontend/src/lib/*, frontend/src/components/*, frontend/src/context/*, frontend/src/middleware*
Removes mock local mode, routes operations through real APIs and Supabase, updates profile refresh behavior, and keeps middleware protection active.
Frontend documentation
frontend/README.md
Documents backend proxy routing and points local development instructions to the local Supabase guide.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Browser
participant Next.js
participant Backend
participant Supabase
Browser->>Next.js: Request API or sign-in route
Next.js->>Backend: Proxy API request
Backend->>Supabase: Read or update application data
Supabase-->>Backend: Return data or auth state
Backend-->>Next.js: Return response
Next.js-->>Browser: Render real backend result
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

🖥️ Running this locally

This PR lets you run the whole app against a local Supabase (rootless Podman) instead of the live staging DB. Full guide: docs/local-supabase.md.

One-time setup

# 1. Podman + its rootless API socket (Arch/CachyOS shown; use your distro's pkg mgr)
sudo pacman -S --needed podman
systemctl --user enable --now podman.socket
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock"# fish (bash/zsh: export in your rc)# 2. Supabase CLI (AUR here; also: brew install supabase/tap/supabase, scoop, etc.)
paru -S supabase-bin
# 3. Env — fixed local-only keys are prefilled; just add your Gemini key
cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local

Bring the stack up

supabase start # Postgres + PostgREST + Storage + Studio, in Podman
scripts/local-up.sh # apply migrations → create storage buckets → seed demo data (idempotent)# optional: load the real ~8k-course catalog (read-only pull from staging)cd backend && python -m db.seed_local_catalog

Run it + sign in

cd backend && python main.py # :5000cd frontend && npm run dev # :3000

Open http://localhost:3000 and sign in with Google — the first local sign-in is auto-approved (no /pending wall). For real Google OAuth locally, add http://localhost:5000/api/auth/google/callback to your OAuth client's authorized redirect URIs.

Handy

AndresL230and others added 3 commits July 21, 2026 02:53
…l auth
Run the full app against a containerized Supabase (rootless Podman) instead of the
live staging DB, and let teammates reproduce it with one script.
- supabase/config.toml — local stack; analytics/edge-runtime disabled,
auto_expose_new_tables=true (required so migration-created tables are reachable
by the Data API roles, matching hosted Supabase).
- scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate):
migrate -> reload PostgREST schema -> seed.
- backend/.env.local.example + frontend/.env.local.example — turnkey local env with
fixed, local-only keys (safe to commit); un-ignored via !.env.local.example.
- backend/db/seed_local_catalog.py — pull the real ~8k-course catalog from a remote
Supabase over its REST API (read-only source; unencrypted catalog only).
- docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
- migrations 0021_gradebook / 0021_gradebook_curve / 0027_gradescope — IF NOT EXISTS
and user_courses->enrollments retarget guards so the chain replays cleanly from an
empty DB. These are no-ops on already-migrated databases (staging/prod unaffected).
- routes/auth.py — IS_LOCAL auto-approve so a first local Google sign-in skips the
/pending wall. Strictly APP_ENV-gated; staging/prod keep the real approval gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app now runs against a real local Supabase backend, so the mock-data path
(lib/localData.ts + all IS_LOCAL_MODE branches) is dead weight and a footgun —
having two ways to "run locally" masked real backend behavior.
Deletes src/lib/localData.ts and removes every IS_LOCAL_MODE branch across api.ts,
UserContext, SignInModal (the local-user-001 dev shortcut), Admin/Social/Learn,
ReportIssueFlow, useAchievementUnlockWatcher, and the middleware short-circuit +
its test stub. The real backend-fetch path is now the sole behavior. tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SignInModal: drop the `if (!API_URL)` guard so an empty (same-origin)
NEXT_PUBLIC_API_URL no longer aborts local Google sign-in as "not configured"
— this was silently blocking the PR's whole point.
- Storage buckets: create cosmetic-assets / issues-media-files / avatars + a
permissive local RLS policy in the bring-up scripts, so cosmetic and issue
uploads work in local dev after the mock removal (buckets weren't created locally).
- 0027_gradescope: guard the gradescope_course_links DROP on the old `user_id`
shape and make the CREATE `IF NOT EXISTS`, so it can't CASCADE-delete data on a
ledger-less replay; 0021_gradebook_curve: document the intentional redundant CHECK.
- seed_local_catalog: paginate until an empty page (robust to source max-rows caps)
and route local writes through db.connection.table() instead of a raw httpx client
(httpx kept only for the unavoidable cross-project source read).
- auth.py: fold is_approved into the new-user insert (drops the redundant UPDATE).
- Extract the duplicated migrate -> reload -> seed block into scripts/lib/local-common.sh.
- Docs: remove stale NEXT_PUBLIC_LOCAL_MODE references from frontend/README.md and
frontend/.env.example, and the dead /api/auth/dev-login comment in .env.local.example.
Verified: fresh replay still "Applied 33 migration(s)", buckets created, seed +
catalog pull succeed, decryption + Google redirect healthy, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndresL230
AndresL230force-pushed the feat/local-supabase-dev branch from e2d9666 to 73e989bCompareJuly 21, 2026 06:59
@AndresL230
AndresL230 changed the base branch from feat/streaming-tutor to mainJuly 21, 2026 06:59
AndresL230and others added 2 commits July 21, 2026 03:23
- auth.py: gate the local auto-approve on APP_ENV=="local" instead of the broader
IS_LOCAL (which includes APP_ENV=test) — it was auto-approving new users under the
test suite and failing the #285 approval-gate regression. All 7 auth-stub tests pass.
- 0027_gradescope: add IF NOT EXISTS to idx_gradescope_links_enrollment, and make the
old-shape gradescope_course_links DROP RAISE loudly if the table holds rows rather than
silently CASCADE-deleting them (the fresh-replay path is empty, so still lossless).
- 0021_gradebook: make gradebook_categories (+ its index) and the assignments indexes
idempotent (IF NOT EXISTS) so a ledger-less re-run doesn't abort mid-chain.
- scripts/lib/local-common.sh: fail fast with a clear message if backend/venv is missing.
- Setup docs/messaging: document creating backend/venv, and clarify that Google OAuth creds
are required to sign in locally (optional only to bring the stack up) — local-up.sh banner,
.env.local.example, docs/local-supabase.md.
Re-verified: Applied 34 migration(s) from empty, storage buckets + seed + catalog pull,
decryption, and the Google redirect all healthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The build-command config for the frontend-staging Worker was fixed
(npm run cf:build restored; the broken 'wrangler deploy --env staging'
skipped the OpenNext build). Empty commit to re-run CI with the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

feat(auth): local dev auth bypasses (open whitelist + auto-approve)

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(dev): local Supabase dev environment + Google-only local auth - #372

Merged
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev
Jul 22, 2026
Merged

feat(dev): local Supabase dev environment + Google-only local auth#372
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev

Conversation

@AndresL230

@AndresL230AndresL230 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A one-command local Supabase dev environment (rootless Podman) so the app runs full-stack against a local DB instead of the live staging DB — and teammates can reproduce it.

Contents

  • supabase/config.toml — local stack; analytics/edge-runtime disabled, auto_expose_new_tables=true (so migration-created tables are reachable by the Data API roles, matching hosted Supabase).
  • scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate): migrate → reload PostgREST → seed.
  • backend/.env.local.example + frontend/.env.local.example — turnkey local env with fixed, local-only keys (safe to commit).
  • backend/db/seed_local_catalog.py — pulls the real ~8k-course catalog from a remote Supabase over its REST API (read-only source; unencrypted catalog only).
  • docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
  • Migration guards (0021_gradebook, 0021_gradebook_curve, 0027_gradescope) — IF NOT EXISTS / user_coursesenrollments retargets so the chain replays cleanly from an empty DB. No-ops on already-migrated databases (staging/prod unaffected).
  • routes/auth.pyIS_LOCAL auto-approve — a first local Google sign-in skips the /pending wall. Strictly APP_ENV-gated; prod keeps the real approval gate.
  • Frontend mock removal — deletes lib/localData.ts + every IS_LOCAL_MODE branch (single source of truth; tsc clean).

Teammate setup

cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock" # fish
supabase start && scripts/local-up.sh
# then: (backend) python main.py (frontend) npm run dev → sign in with Google

Full guide: docs/local-supabase.md.

Notes

  • Rebased onto main (was originally cut from feat/streaming-tutor). The frontend mock removal and the auth.py auto-approve were re-resolved against main's versions during the rebase; conflicts were only in api.ts (re-stripped) and localData.ts (deleted).
  • Replay re-verified from empty against main's full setApplied 34 migration(s) including main's 0031, then storage buckets + seed + catalog pull, decryption, and the Google redirect all healthy; tsc clean.

Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a complete local Supabase setup with starter environment templates, seeded catalog support, and scripts to start or reset the local stack.
    • Added local Google OAuth sign-in with automatic approval for local development.
  • Bug Fixes
    • Local database migrations and indexes can now be safely rerun.
    • Improved avatar refresh behavior so updated profile images appear promptly.
  • Documentation
    • Added comprehensive local Supabase setup, configuration, OAuth, reset, and troubleshooting guidance.
  • Refactor
    • Removed mock-data local mode; local development now uses the real backend and services.

@AndresL230AndresL230 self-assigned this Jul 21, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging6765f49Commit Preview URL

Branch Preview URL
Jul 22 2026, 04:09 AM

@coderabbitai

coderabbitaiBot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 5fc87496-1065-4f97-a759-3ef2155194bb

📥 Commits

Reviewing files that changed from the base of the PR and between 73e989b and 6765f49.

📒 Files selected for processing (7)
  • backend/.env.local.example
  • backend/db/migrations/0021_gradebook.sql
  • backend/db/migrations/0027_gradescope.sql
  • backend/routes/auth.py
  • docs/local-supabase.md
  • scripts/lib/local-common.sh
  • scripts/local-up.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/.env.local.example
  • scripts/local-up.sh
  • backend/db/migrations/0027_gradescope.sql
  • docs/local-supabase.md
  • scripts/lib/local-common.sh

📝 Walkthrough

Walkthrough

The PR adds a local Supabase development stack, makes migrations replay-safe, adds catalog synchronization and local setup scripts, enables local OAuth approval, and removes frontend mock local mode in favor of real backend and Supabase integrations.

Changes

Local Supabase development

Layer / File(s)Summary
Environment and service configuration
.gitignore, backend/.env.local.example, frontend/.env.local.example, supabase/*, docs/local-supabase.md
Adds local environment templates, Supabase service configuration, ignored local secrets, and setup/troubleshooting documentation.
Replay-safe database migrations
backend/db/migrations/*
Retargets curve-policy columns and constraints to enrollments and makes gradebook and Gradescope schema changes rerunnable.
Local stack automation
scripts/*
Adds startup/reset workflows for migrations, storage buckets, PostgREST reloads, readiness checks, and demo seeding.
Catalog synchronization
backend/db/seed_local_catalog.py
Fetches remote courses and offerings with pagination and upserts them into local Supabase in batches.
Local OAuth approval
backend/routes/auth.py
Auto-approves newly created Google OAuth users when APP_ENV is local.
Real frontend integrations
frontend/src/lib/*, frontend/src/components/*, frontend/src/context/*, frontend/src/middleware*
Removes mock local mode, routes operations through real APIs and Supabase, updates profile refresh behavior, and keeps middleware protection active.
Frontend documentation
frontend/README.md
Documents backend proxy routing and points local development instructions to the local Supabase guide.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Browser
participant Next.js
participant Backend
participant Supabase
Browser->>Next.js: Request API or sign-in route
Next.js->>Backend: Proxy API request
Backend->>Supabase: Read or update application data
Supabase-->>Backend: Return data or auth state
Backend-->>Next.js: Return response
Next.js-->>Browser: Render real backend result
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

🖥️ Running this locally

This PR lets you run the whole app against a local Supabase (rootless Podman) instead of the live staging DB. Full guide: docs/local-supabase.md.

One-time setup

# 1. Podman + its rootless API socket (Arch/CachyOS shown; use your distro's pkg mgr)
sudo pacman -S --needed podman
systemctl --user enable --now podman.socket
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock"# fish (bash/zsh: export in your rc)# 2. Supabase CLI (AUR here; also: brew install supabase/tap/supabase, scoop, etc.)
paru -S supabase-bin
# 3. Env — fixed local-only keys are prefilled; just add your Gemini key
cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local

Bring the stack up

supabase start # Postgres + PostgREST + Storage + Studio, in Podman
scripts/local-up.sh # apply migrations → create storage buckets → seed demo data (idempotent)# optional: load the real ~8k-course catalog (read-only pull from staging)cd backend && python -m db.seed_local_catalog

Run it + sign in

cd backend && python main.py # :5000cd frontend && npm run dev # :3000

Open http://localhost:3000 and sign in with Google — the first local sign-in is auto-approved (no /pending wall). For real Google OAuth locally, add http://localhost:5000/api/auth/google/callback to your OAuth client's authorized redirect URIs.

Handy

AndresL230and others added 3 commits July 21, 2026 02:53
…l auth
Run the full app against a containerized Supabase (rootless Podman) instead of the
live staging DB, and let teammates reproduce it with one script.
- supabase/config.toml — local stack; analytics/edge-runtime disabled,
auto_expose_new_tables=true (required so migration-created tables are reachable
by the Data API roles, matching hosted Supabase).
- scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate):
migrate -> reload PostgREST schema -> seed.
- backend/.env.local.example + frontend/.env.local.example — turnkey local env with
fixed, local-only keys (safe to commit); un-ignored via !.env.local.example.
- backend/db/seed_local_catalog.py — pull the real ~8k-course catalog from a remote
Supabase over its REST API (read-only source; unencrypted catalog only).
- docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
- migrations 0021_gradebook / 0021_gradebook_curve / 0027_gradescope — IF NOT EXISTS
and user_courses->enrollments retarget guards so the chain replays cleanly from an
empty DB. These are no-ops on already-migrated databases (staging/prod unaffected).
- routes/auth.py — IS_LOCAL auto-approve so a first local Google sign-in skips the
/pending wall. Strictly APP_ENV-gated; staging/prod keep the real approval gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app now runs against a real local Supabase backend, so the mock-data path
(lib/localData.ts + all IS_LOCAL_MODE branches) is dead weight and a footgun —
having two ways to "run locally" masked real backend behavior.
Deletes src/lib/localData.ts and removes every IS_LOCAL_MODE branch across api.ts,
UserContext, SignInModal (the local-user-001 dev shortcut), Admin/Social/Learn,
ReportIssueFlow, useAchievementUnlockWatcher, and the middleware short-circuit +
its test stub. The real backend-fetch path is now the sole behavior. tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SignInModal: drop the `if (!API_URL)` guard so an empty (same-origin)
NEXT_PUBLIC_API_URL no longer aborts local Google sign-in as "not configured"
— this was silently blocking the PR's whole point.
- Storage buckets: create cosmetic-assets / issues-media-files / avatars + a
permissive local RLS policy in the bring-up scripts, so cosmetic and issue
uploads work in local dev after the mock removal (buckets weren't created locally).
- 0027_gradescope: guard the gradescope_course_links DROP on the old `user_id`
shape and make the CREATE `IF NOT EXISTS`, so it can't CASCADE-delete data on a
ledger-less replay; 0021_gradebook_curve: document the intentional redundant CHECK.
- seed_local_catalog: paginate until an empty page (robust to source max-rows caps)
and route local writes through db.connection.table() instead of a raw httpx client
(httpx kept only for the unavoidable cross-project source read).
- auth.py: fold is_approved into the new-user insert (drops the redundant UPDATE).
- Extract the duplicated migrate -> reload -> seed block into scripts/lib/local-common.sh.
- Docs: remove stale NEXT_PUBLIC_LOCAL_MODE references from frontend/README.md and
frontend/.env.example, and the dead /api/auth/dev-login comment in .env.local.example.
Verified: fresh replay still "Applied 33 migration(s)", buckets created, seed +
catalog pull succeed, decryption + Google redirect healthy, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndresL230
AndresL230force-pushed the feat/local-supabase-dev branch from e2d9666 to 73e989bCompareJuly 21, 2026 06:59
@AndresL230
AndresL230 changed the base branch from feat/streaming-tutor to mainJuly 21, 2026 06:59
AndresL230and others added 2 commits July 21, 2026 03:23
- auth.py: gate the local auto-approve on APP_ENV=="local" instead of the broader
IS_LOCAL (which includes APP_ENV=test) — it was auto-approving new users under the
test suite and failing the #285 approval-gate regression. All 7 auth-stub tests pass.
- 0027_gradescope: add IF NOT EXISTS to idx_gradescope_links_enrollment, and make the
old-shape gradescope_course_links DROP RAISE loudly if the table holds rows rather than
silently CASCADE-deleting them (the fresh-replay path is empty, so still lossless).
- 0021_gradebook: make gradebook_categories (+ its index) and the assignments indexes
idempotent (IF NOT EXISTS) so a ledger-less re-run doesn't abort mid-chain.
- scripts/lib/local-common.sh: fail fast with a clear message if backend/venv is missing.
- Setup docs/messaging: document creating backend/venv, and clarify that Google OAuth creds
are required to sign in locally (optional only to bring the stack up) — local-up.sh banner,
.env.local.example, docs/local-supabase.md.
Re-verified: Applied 34 migration(s) from empty, storage buckets + seed + catalog pull,
decryption, and the Google redirect all healthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The build-command config for the frontend-staging Worker was fixed
(npm run cf:build restored; the broken 'wrangler deploy --env staging'
skipped the OpenNext build). Empty commit to re-run CI with the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

feat(auth): local dev auth bypasses (open whitelist + auto-approve)

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(dev): local Supabase dev environment + Google-only local auth - #372

Merged
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev
Jul 22, 2026
Merged

feat(dev): local Supabase dev environment + Google-only local auth#372
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev

Conversation

@AndresL230

@AndresL230AndresL230 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A one-command local Supabase dev environment (rootless Podman) so the app runs full-stack against a local DB instead of the live staging DB — and teammates can reproduce it.

Contents

  • supabase/config.toml — local stack; analytics/edge-runtime disabled, auto_expose_new_tables=true (so migration-created tables are reachable by the Data API roles, matching hosted Supabase).
  • scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate): migrate → reload PostgREST → seed.
  • backend/.env.local.example + frontend/.env.local.example — turnkey local env with fixed, local-only keys (safe to commit).
  • backend/db/seed_local_catalog.py — pulls the real ~8k-course catalog from a remote Supabase over its REST API (read-only source; unencrypted catalog only).
  • docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
  • Migration guards (0021_gradebook, 0021_gradebook_curve, 0027_gradescope) — IF NOT EXISTS / user_coursesenrollments retargets so the chain replays cleanly from an empty DB. No-ops on already-migrated databases (staging/prod unaffected).
  • routes/auth.pyIS_LOCAL auto-approve — a first local Google sign-in skips the /pending wall. Strictly APP_ENV-gated; prod keeps the real approval gate.
  • Frontend mock removal — deletes lib/localData.ts + every IS_LOCAL_MODE branch (single source of truth; tsc clean).

Teammate setup

cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock" # fish
supabase start && scripts/local-up.sh
# then: (backend) python main.py (frontend) npm run dev → sign in with Google

Full guide: docs/local-supabase.md.

Notes

  • Rebased onto main (was originally cut from feat/streaming-tutor). The frontend mock removal and the auth.py auto-approve were re-resolved against main's versions during the rebase; conflicts were only in api.ts (re-stripped) and localData.ts (deleted).
  • Replay re-verified from empty against main's full setApplied 34 migration(s) including main's 0031, then storage buckets + seed + catalog pull, decryption, and the Google redirect all healthy; tsc clean.

Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a complete local Supabase setup with starter environment templates, seeded catalog support, and scripts to start or reset the local stack.
    • Added local Google OAuth sign-in with automatic approval for local development.
  • Bug Fixes
    • Local database migrations and indexes can now be safely rerun.
    • Improved avatar refresh behavior so updated profile images appear promptly.
  • Documentation
    • Added comprehensive local Supabase setup, configuration, OAuth, reset, and troubleshooting guidance.
  • Refactor
    • Removed mock-data local mode; local development now uses the real backend and services.

@AndresL230AndresL230 self-assigned this Jul 21, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging6765f49Commit Preview URL

Branch Preview URL
Jul 22 2026, 04:09 AM

@coderabbitai

coderabbitaiBot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 5fc87496-1065-4f97-a759-3ef2155194bb

📥 Commits

Reviewing files that changed from the base of the PR and between 73e989b and 6765f49.

📒 Files selected for processing (7)
  • backend/.env.local.example
  • backend/db/migrations/0021_gradebook.sql
  • backend/db/migrations/0027_gradescope.sql
  • backend/routes/auth.py
  • docs/local-supabase.md
  • scripts/lib/local-common.sh
  • scripts/local-up.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/.env.local.example
  • scripts/local-up.sh
  • backend/db/migrations/0027_gradescope.sql
  • docs/local-supabase.md
  • scripts/lib/local-common.sh

📝 Walkthrough

Walkthrough

The PR adds a local Supabase development stack, makes migrations replay-safe, adds catalog synchronization and local setup scripts, enables local OAuth approval, and removes frontend mock local mode in favor of real backend and Supabase integrations.

Changes

Local Supabase development

Layer / File(s)Summary
Environment and service configuration
.gitignore, backend/.env.local.example, frontend/.env.local.example, supabase/*, docs/local-supabase.md
Adds local environment templates, Supabase service configuration, ignored local secrets, and setup/troubleshooting documentation.
Replay-safe database migrations
backend/db/migrations/*
Retargets curve-policy columns and constraints to enrollments and makes gradebook and Gradescope schema changes rerunnable.
Local stack automation
scripts/*
Adds startup/reset workflows for migrations, storage buckets, PostgREST reloads, readiness checks, and demo seeding.
Catalog synchronization
backend/db/seed_local_catalog.py
Fetches remote courses and offerings with pagination and upserts them into local Supabase in batches.
Local OAuth approval
backend/routes/auth.py
Auto-approves newly created Google OAuth users when APP_ENV is local.
Real frontend integrations
frontend/src/lib/*, frontend/src/components/*, frontend/src/context/*, frontend/src/middleware*
Removes mock local mode, routes operations through real APIs and Supabase, updates profile refresh behavior, and keeps middleware protection active.
Frontend documentation
frontend/README.md
Documents backend proxy routing and points local development instructions to the local Supabase guide.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Browser
participant Next.js
participant Backend
participant Supabase
Browser->>Next.js: Request API or sign-in route
Next.js->>Backend: Proxy API request
Backend->>Supabase: Read or update application data
Supabase-->>Backend: Return data or auth state
Backend-->>Next.js: Return response
Next.js-->>Browser: Render real backend result
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

🖥️ Running this locally

This PR lets you run the whole app against a local Supabase (rootless Podman) instead of the live staging DB. Full guide: docs/local-supabase.md.

One-time setup

# 1. Podman + its rootless API socket (Arch/CachyOS shown; use your distro's pkg mgr)
sudo pacman -S --needed podman
systemctl --user enable --now podman.socket
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock"# fish (bash/zsh: export in your rc)# 2. Supabase CLI (AUR here; also: brew install supabase/tap/supabase, scoop, etc.)
paru -S supabase-bin
# 3. Env — fixed local-only keys are prefilled; just add your Gemini key
cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local

Bring the stack up

supabase start # Postgres + PostgREST + Storage + Studio, in Podman
scripts/local-up.sh # apply migrations → create storage buckets → seed demo data (idempotent)# optional: load the real ~8k-course catalog (read-only pull from staging)cd backend && python -m db.seed_local_catalog

Run it + sign in

cd backend && python main.py # :5000cd frontend && npm run dev # :3000

Open http://localhost:3000 and sign in with Google — the first local sign-in is auto-approved (no /pending wall). For real Google OAuth locally, add http://localhost:5000/api/auth/google/callback to your OAuth client's authorized redirect URIs.

Handy

AndresL230and others added 3 commits July 21, 2026 02:53
…l auth
Run the full app against a containerized Supabase (rootless Podman) instead of the
live staging DB, and let teammates reproduce it with one script.
- supabase/config.toml — local stack; analytics/edge-runtime disabled,
auto_expose_new_tables=true (required so migration-created tables are reachable
by the Data API roles, matching hosted Supabase).
- scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate):
migrate -> reload PostgREST schema -> seed.
- backend/.env.local.example + frontend/.env.local.example — turnkey local env with
fixed, local-only keys (safe to commit); un-ignored via !.env.local.example.
- backend/db/seed_local_catalog.py — pull the real ~8k-course catalog from a remote
Supabase over its REST API (read-only source; unencrypted catalog only).
- docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
- migrations 0021_gradebook / 0021_gradebook_curve / 0027_gradescope — IF NOT EXISTS
and user_courses->enrollments retarget guards so the chain replays cleanly from an
empty DB. These are no-ops on already-migrated databases (staging/prod unaffected).
- routes/auth.py — IS_LOCAL auto-approve so a first local Google sign-in skips the
/pending wall. Strictly APP_ENV-gated; staging/prod keep the real approval gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app now runs against a real local Supabase backend, so the mock-data path
(lib/localData.ts + all IS_LOCAL_MODE branches) is dead weight and a footgun —
having two ways to "run locally" masked real backend behavior.
Deletes src/lib/localData.ts and removes every IS_LOCAL_MODE branch across api.ts,
UserContext, SignInModal (the local-user-001 dev shortcut), Admin/Social/Learn,
ReportIssueFlow, useAchievementUnlockWatcher, and the middleware short-circuit +
its test stub. The real backend-fetch path is now the sole behavior. tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SignInModal: drop the `if (!API_URL)` guard so an empty (same-origin)
NEXT_PUBLIC_API_URL no longer aborts local Google sign-in as "not configured"
— this was silently blocking the PR's whole point.
- Storage buckets: create cosmetic-assets / issues-media-files / avatars + a
permissive local RLS policy in the bring-up scripts, so cosmetic and issue
uploads work in local dev after the mock removal (buckets weren't created locally).
- 0027_gradescope: guard the gradescope_course_links DROP on the old `user_id`
shape and make the CREATE `IF NOT EXISTS`, so it can't CASCADE-delete data on a
ledger-less replay; 0021_gradebook_curve: document the intentional redundant CHECK.
- seed_local_catalog: paginate until an empty page (robust to source max-rows caps)
and route local writes through db.connection.table() instead of a raw httpx client
(httpx kept only for the unavoidable cross-project source read).
- auth.py: fold is_approved into the new-user insert (drops the redundant UPDATE).
- Extract the duplicated migrate -> reload -> seed block into scripts/lib/local-common.sh.
- Docs: remove stale NEXT_PUBLIC_LOCAL_MODE references from frontend/README.md and
frontend/.env.example, and the dead /api/auth/dev-login comment in .env.local.example.
Verified: fresh replay still "Applied 33 migration(s)", buckets created, seed +
catalog pull succeed, decryption + Google redirect healthy, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndresL230
AndresL230force-pushed the feat/local-supabase-dev branch from e2d9666 to 73e989bCompareJuly 21, 2026 06:59
@AndresL230
AndresL230 changed the base branch from feat/streaming-tutor to mainJuly 21, 2026 06:59
AndresL230and others added 2 commits July 21, 2026 03:23
- auth.py: gate the local auto-approve on APP_ENV=="local" instead of the broader
IS_LOCAL (which includes APP_ENV=test) — it was auto-approving new users under the
test suite and failing the #285 approval-gate regression. All 7 auth-stub tests pass.
- 0027_gradescope: add IF NOT EXISTS to idx_gradescope_links_enrollment, and make the
old-shape gradescope_course_links DROP RAISE loudly if the table holds rows rather than
silently CASCADE-deleting them (the fresh-replay path is empty, so still lossless).
- 0021_gradebook: make gradebook_categories (+ its index) and the assignments indexes
idempotent (IF NOT EXISTS) so a ledger-less re-run doesn't abort mid-chain.
- scripts/lib/local-common.sh: fail fast with a clear message if backend/venv is missing.
- Setup docs/messaging: document creating backend/venv, and clarify that Google OAuth creds
are required to sign in locally (optional only to bring the stack up) — local-up.sh banner,
.env.local.example, docs/local-supabase.md.
Re-verified: Applied 34 migration(s) from empty, storage buckets + seed + catalog pull,
decryption, and the Google redirect all healthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The build-command config for the frontend-staging Worker was fixed
(npm run cf:build restored; the broken 'wrangler deploy --env staging'
skipped the OpenNext build). Empty commit to re-run CI with the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

feat(auth): local dev auth bypasses (open whitelist + auto-approve)

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(dev): local Supabase dev environment + Google-only local auth - #372

Merged
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev
Jul 22, 2026
Merged

feat(dev): local Supabase dev environment + Google-only local auth#372
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev

Conversation

@AndresL230

@AndresL230AndresL230 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A one-command local Supabase dev environment (rootless Podman) so the app runs full-stack against a local DB instead of the live staging DB — and teammates can reproduce it.

Contents

  • supabase/config.toml — local stack; analytics/edge-runtime disabled, auto_expose_new_tables=true (so migration-created tables are reachable by the Data API roles, matching hosted Supabase).
  • scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate): migrate → reload PostgREST → seed.
  • backend/.env.local.example + frontend/.env.local.example — turnkey local env with fixed, local-only keys (safe to commit).
  • backend/db/seed_local_catalog.py — pulls the real ~8k-course catalog from a remote Supabase over its REST API (read-only source; unencrypted catalog only).
  • docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
  • Migration guards (0021_gradebook, 0021_gradebook_curve, 0027_gradescope) — IF NOT EXISTS / user_coursesenrollments retargets so the chain replays cleanly from an empty DB. No-ops on already-migrated databases (staging/prod unaffected).
  • routes/auth.pyIS_LOCAL auto-approve — a first local Google sign-in skips the /pending wall. Strictly APP_ENV-gated; prod keeps the real approval gate.
  • Frontend mock removal — deletes lib/localData.ts + every IS_LOCAL_MODE branch (single source of truth; tsc clean).

Teammate setup

cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock" # fish
supabase start && scripts/local-up.sh
# then: (backend) python main.py (frontend) npm run dev → sign in with Google

Full guide: docs/local-supabase.md.

Notes

  • Rebased onto main (was originally cut from feat/streaming-tutor). The frontend mock removal and the auth.py auto-approve were re-resolved against main's versions during the rebase; conflicts were only in api.ts (re-stripped) and localData.ts (deleted).
  • Replay re-verified from empty against main's full setApplied 34 migration(s) including main's 0031, then storage buckets + seed + catalog pull, decryption, and the Google redirect all healthy; tsc clean.

Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a complete local Supabase setup with starter environment templates, seeded catalog support, and scripts to start or reset the local stack.
    • Added local Google OAuth sign-in with automatic approval for local development.
  • Bug Fixes
    • Local database migrations and indexes can now be safely rerun.
    • Improved avatar refresh behavior so updated profile images appear promptly.
  • Documentation
    • Added comprehensive local Supabase setup, configuration, OAuth, reset, and troubleshooting guidance.
  • Refactor
    • Removed mock-data local mode; local development now uses the real backend and services.

@AndresL230AndresL230 self-assigned this Jul 21, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging6765f49Commit Preview URL

Branch Preview URL
Jul 22 2026, 04:09 AM

@coderabbitai

coderabbitaiBot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 5fc87496-1065-4f97-a759-3ef2155194bb

📥 Commits

Reviewing files that changed from the base of the PR and between 73e989b and 6765f49.

📒 Files selected for processing (7)
  • backend/.env.local.example
  • backend/db/migrations/0021_gradebook.sql
  • backend/db/migrations/0027_gradescope.sql
  • backend/routes/auth.py
  • docs/local-supabase.md
  • scripts/lib/local-common.sh
  • scripts/local-up.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/.env.local.example
  • scripts/local-up.sh
  • backend/db/migrations/0027_gradescope.sql
  • docs/local-supabase.md
  • scripts/lib/local-common.sh

📝 Walkthrough

Walkthrough

The PR adds a local Supabase development stack, makes migrations replay-safe, adds catalog synchronization and local setup scripts, enables local OAuth approval, and removes frontend mock local mode in favor of real backend and Supabase integrations.

Changes

Local Supabase development

Layer / File(s)Summary
Environment and service configuration
.gitignore, backend/.env.local.example, frontend/.env.local.example, supabase/*, docs/local-supabase.md
Adds local environment templates, Supabase service configuration, ignored local secrets, and setup/troubleshooting documentation.
Replay-safe database migrations
backend/db/migrations/*
Retargets curve-policy columns and constraints to enrollments and makes gradebook and Gradescope schema changes rerunnable.
Local stack automation
scripts/*
Adds startup/reset workflows for migrations, storage buckets, PostgREST reloads, readiness checks, and demo seeding.
Catalog synchronization
backend/db/seed_local_catalog.py
Fetches remote courses and offerings with pagination and upserts them into local Supabase in batches.
Local OAuth approval
backend/routes/auth.py
Auto-approves newly created Google OAuth users when APP_ENV is local.
Real frontend integrations
frontend/src/lib/*, frontend/src/components/*, frontend/src/context/*, frontend/src/middleware*
Removes mock local mode, routes operations through real APIs and Supabase, updates profile refresh behavior, and keeps middleware protection active.
Frontend documentation
frontend/README.md
Documents backend proxy routing and points local development instructions to the local Supabase guide.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Browser
participant Next.js
participant Backend
participant Supabase
Browser->>Next.js: Request API or sign-in route
Next.js->>Backend: Proxy API request
Backend->>Supabase: Read or update application data
Supabase-->>Backend: Return data or auth state
Backend-->>Next.js: Return response
Next.js-->>Browser: Render real backend result
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

🖥️ Running this locally

This PR lets you run the whole app against a local Supabase (rootless Podman) instead of the live staging DB. Full guide: docs/local-supabase.md.

One-time setup

# 1. Podman + its rootless API socket (Arch/CachyOS shown; use your distro's pkg mgr)
sudo pacman -S --needed podman
systemctl --user enable --now podman.socket
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock"# fish (bash/zsh: export in your rc)# 2. Supabase CLI (AUR here; also: brew install supabase/tap/supabase, scoop, etc.)
paru -S supabase-bin
# 3. Env — fixed local-only keys are prefilled; just add your Gemini key
cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local

Bring the stack up

supabase start # Postgres + PostgREST + Storage + Studio, in Podman
scripts/local-up.sh # apply migrations → create storage buckets → seed demo data (idempotent)# optional: load the real ~8k-course catalog (read-only pull from staging)cd backend && python -m db.seed_local_catalog

Run it + sign in

cd backend && python main.py # :5000cd frontend && npm run dev # :3000

Open http://localhost:3000 and sign in with Google — the first local sign-in is auto-approved (no /pending wall). For real Google OAuth locally, add http://localhost:5000/api/auth/google/callback to your OAuth client's authorized redirect URIs.

Handy

AndresL230and others added 3 commits July 21, 2026 02:53
…l auth
Run the full app against a containerized Supabase (rootless Podman) instead of the
live staging DB, and let teammates reproduce it with one script.
- supabase/config.toml — local stack; analytics/edge-runtime disabled,
auto_expose_new_tables=true (required so migration-created tables are reachable
by the Data API roles, matching hosted Supabase).
- scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate):
migrate -> reload PostgREST schema -> seed.
- backend/.env.local.example + frontend/.env.local.example — turnkey local env with
fixed, local-only keys (safe to commit); un-ignored via !.env.local.example.
- backend/db/seed_local_catalog.py — pull the real ~8k-course catalog from a remote
Supabase over its REST API (read-only source; unencrypted catalog only).
- docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
- migrations 0021_gradebook / 0021_gradebook_curve / 0027_gradescope — IF NOT EXISTS
and user_courses->enrollments retarget guards so the chain replays cleanly from an
empty DB. These are no-ops on already-migrated databases (staging/prod unaffected).
- routes/auth.py — IS_LOCAL auto-approve so a first local Google sign-in skips the
/pending wall. Strictly APP_ENV-gated; staging/prod keep the real approval gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app now runs against a real local Supabase backend, so the mock-data path
(lib/localData.ts + all IS_LOCAL_MODE branches) is dead weight and a footgun —
having two ways to "run locally" masked real backend behavior.
Deletes src/lib/localData.ts and removes every IS_LOCAL_MODE branch across api.ts,
UserContext, SignInModal (the local-user-001 dev shortcut), Admin/Social/Learn,
ReportIssueFlow, useAchievementUnlockWatcher, and the middleware short-circuit +
its test stub. The real backend-fetch path is now the sole behavior. tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SignInModal: drop the `if (!API_URL)` guard so an empty (same-origin)
NEXT_PUBLIC_API_URL no longer aborts local Google sign-in as "not configured"
— this was silently blocking the PR's whole point.
- Storage buckets: create cosmetic-assets / issues-media-files / avatars + a
permissive local RLS policy in the bring-up scripts, so cosmetic and issue
uploads work in local dev after the mock removal (buckets weren't created locally).
- 0027_gradescope: guard the gradescope_course_links DROP on the old `user_id`
shape and make the CREATE `IF NOT EXISTS`, so it can't CASCADE-delete data on a
ledger-less replay; 0021_gradebook_curve: document the intentional redundant CHECK.
- seed_local_catalog: paginate until an empty page (robust to source max-rows caps)
and route local writes through db.connection.table() instead of a raw httpx client
(httpx kept only for the unavoidable cross-project source read).
- auth.py: fold is_approved into the new-user insert (drops the redundant UPDATE).
- Extract the duplicated migrate -> reload -> seed block into scripts/lib/local-common.sh.
- Docs: remove stale NEXT_PUBLIC_LOCAL_MODE references from frontend/README.md and
frontend/.env.example, and the dead /api/auth/dev-login comment in .env.local.example.
Verified: fresh replay still "Applied 33 migration(s)", buckets created, seed +
catalog pull succeed, decryption + Google redirect healthy, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndresL230
AndresL230force-pushed the feat/local-supabase-dev branch from e2d9666 to 73e989bCompareJuly 21, 2026 06:59
@AndresL230
AndresL230 changed the base branch from feat/streaming-tutor to mainJuly 21, 2026 06:59
AndresL230and others added 2 commits July 21, 2026 03:23
- auth.py: gate the local auto-approve on APP_ENV=="local" instead of the broader
IS_LOCAL (which includes APP_ENV=test) — it was auto-approving new users under the
test suite and failing the #285 approval-gate regression. All 7 auth-stub tests pass.
- 0027_gradescope: add IF NOT EXISTS to idx_gradescope_links_enrollment, and make the
old-shape gradescope_course_links DROP RAISE loudly if the table holds rows rather than
silently CASCADE-deleting them (the fresh-replay path is empty, so still lossless).
- 0021_gradebook: make gradebook_categories (+ its index) and the assignments indexes
idempotent (IF NOT EXISTS) so a ledger-less re-run doesn't abort mid-chain.
- scripts/lib/local-common.sh: fail fast with a clear message if backend/venv is missing.
- Setup docs/messaging: document creating backend/venv, and clarify that Google OAuth creds
are required to sign in locally (optional only to bring the stack up) — local-up.sh banner,
.env.local.example, docs/local-supabase.md.
Re-verified: Applied 34 migration(s) from empty, storage buckets + seed + catalog pull,
decryption, and the Google redirect all healthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The build-command config for the frontend-staging Worker was fixed
(npm run cf:build restored; the broken 'wrangler deploy --env staging'
skipped the OpenNext build). Empty commit to re-run CI with the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

feat(auth): local dev auth bypasses (open whitelist + auto-approve)

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(dev): local Supabase dev environment + Google-only local auth - #372

Merged
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev
Jul 22, 2026
Merged

feat(dev): local Supabase dev environment + Google-only local auth#372
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev

Conversation

@AndresL230

@AndresL230AndresL230 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A one-command local Supabase dev environment (rootless Podman) so the app runs full-stack against a local DB instead of the live staging DB — and teammates can reproduce it.

Contents

  • supabase/config.toml — local stack; analytics/edge-runtime disabled, auto_expose_new_tables=true (so migration-created tables are reachable by the Data API roles, matching hosted Supabase).
  • scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate): migrate → reload PostgREST → seed.
  • backend/.env.local.example + frontend/.env.local.example — turnkey local env with fixed, local-only keys (safe to commit).
  • backend/db/seed_local_catalog.py — pulls the real ~8k-course catalog from a remote Supabase over its REST API (read-only source; unencrypted catalog only).
  • docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
  • Migration guards (0021_gradebook, 0021_gradebook_curve, 0027_gradescope) — IF NOT EXISTS / user_coursesenrollments retargets so the chain replays cleanly from an empty DB. No-ops on already-migrated databases (staging/prod unaffected).
  • routes/auth.pyIS_LOCAL auto-approve — a first local Google sign-in skips the /pending wall. Strictly APP_ENV-gated; prod keeps the real approval gate.
  • Frontend mock removal — deletes lib/localData.ts + every IS_LOCAL_MODE branch (single source of truth; tsc clean).

Teammate setup

cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock" # fish
supabase start && scripts/local-up.sh
# then: (backend) python main.py (frontend) npm run dev → sign in with Google

Full guide: docs/local-supabase.md.

Notes

  • Rebased onto main (was originally cut from feat/streaming-tutor). The frontend mock removal and the auth.py auto-approve were re-resolved against main's versions during the rebase; conflicts were only in api.ts (re-stripped) and localData.ts (deleted).
  • Replay re-verified from empty against main's full setApplied 34 migration(s) including main's 0031, then storage buckets + seed + catalog pull, decryption, and the Google redirect all healthy; tsc clean.

Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a complete local Supabase setup with starter environment templates, seeded catalog support, and scripts to start or reset the local stack.
    • Added local Google OAuth sign-in with automatic approval for local development.
  • Bug Fixes
    • Local database migrations and indexes can now be safely rerun.
    • Improved avatar refresh behavior so updated profile images appear promptly.
  • Documentation
    • Added comprehensive local Supabase setup, configuration, OAuth, reset, and troubleshooting guidance.
  • Refactor
    • Removed mock-data local mode; local development now uses the real backend and services.

@AndresL230AndresL230 self-assigned this Jul 21, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging6765f49Commit Preview URL

Branch Preview URL
Jul 22 2026, 04:09 AM

@coderabbitai

coderabbitaiBot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 5fc87496-1065-4f97-a759-3ef2155194bb

📥 Commits

Reviewing files that changed from the base of the PR and between 73e989b and 6765f49.

📒 Files selected for processing (7)
  • backend/.env.local.example
  • backend/db/migrations/0021_gradebook.sql
  • backend/db/migrations/0027_gradescope.sql
  • backend/routes/auth.py
  • docs/local-supabase.md
  • scripts/lib/local-common.sh
  • scripts/local-up.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/.env.local.example
  • scripts/local-up.sh
  • backend/db/migrations/0027_gradescope.sql
  • docs/local-supabase.md
  • scripts/lib/local-common.sh

📝 Walkthrough

Walkthrough

The PR adds a local Supabase development stack, makes migrations replay-safe, adds catalog synchronization and local setup scripts, enables local OAuth approval, and removes frontend mock local mode in favor of real backend and Supabase integrations.

Changes

Local Supabase development

Layer / File(s)Summary
Environment and service configuration
.gitignore, backend/.env.local.example, frontend/.env.local.example, supabase/*, docs/local-supabase.md
Adds local environment templates, Supabase service configuration, ignored local secrets, and setup/troubleshooting documentation.
Replay-safe database migrations
backend/db/migrations/*
Retargets curve-policy columns and constraints to enrollments and makes gradebook and Gradescope schema changes rerunnable.
Local stack automation
scripts/*
Adds startup/reset workflows for migrations, storage buckets, PostgREST reloads, readiness checks, and demo seeding.
Catalog synchronization
backend/db/seed_local_catalog.py
Fetches remote courses and offerings with pagination and upserts them into local Supabase in batches.
Local OAuth approval
backend/routes/auth.py
Auto-approves newly created Google OAuth users when APP_ENV is local.
Real frontend integrations
frontend/src/lib/*, frontend/src/components/*, frontend/src/context/*, frontend/src/middleware*
Removes mock local mode, routes operations through real APIs and Supabase, updates profile refresh behavior, and keeps middleware protection active.
Frontend documentation
frontend/README.md
Documents backend proxy routing and points local development instructions to the local Supabase guide.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Browser
participant Next.js
participant Backend
participant Supabase
Browser->>Next.js: Request API or sign-in route
Next.js->>Backend: Proxy API request
Backend->>Supabase: Read or update application data
Supabase-->>Backend: Return data or auth state
Backend-->>Next.js: Return response
Next.js-->>Browser: Render real backend result
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

🖥️ Running this locally

This PR lets you run the whole app against a local Supabase (rootless Podman) instead of the live staging DB. Full guide: docs/local-supabase.md.

One-time setup

# 1. Podman + its rootless API socket (Arch/CachyOS shown; use your distro's pkg mgr)
sudo pacman -S --needed podman
systemctl --user enable --now podman.socket
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock"# fish (bash/zsh: export in your rc)# 2. Supabase CLI (AUR here; also: brew install supabase/tap/supabase, scoop, etc.)
paru -S supabase-bin
# 3. Env — fixed local-only keys are prefilled; just add your Gemini key
cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local

Bring the stack up

supabase start # Postgres + PostgREST + Storage + Studio, in Podman
scripts/local-up.sh # apply migrations → create storage buckets → seed demo data (idempotent)# optional: load the real ~8k-course catalog (read-only pull from staging)cd backend && python -m db.seed_local_catalog

Run it + sign in

cd backend && python main.py # :5000cd frontend && npm run dev # :3000

Open http://localhost:3000 and sign in with Google — the first local sign-in is auto-approved (no /pending wall). For real Google OAuth locally, add http://localhost:5000/api/auth/google/callback to your OAuth client's authorized redirect URIs.

Handy

AndresL230and others added 3 commits July 21, 2026 02:53
…l auth
Run the full app against a containerized Supabase (rootless Podman) instead of the
live staging DB, and let teammates reproduce it with one script.
- supabase/config.toml — local stack; analytics/edge-runtime disabled,
auto_expose_new_tables=true (required so migration-created tables are reachable
by the Data API roles, matching hosted Supabase).
- scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate):
migrate -> reload PostgREST schema -> seed.
- backend/.env.local.example + frontend/.env.local.example — turnkey local env with
fixed, local-only keys (safe to commit); un-ignored via !.env.local.example.
- backend/db/seed_local_catalog.py — pull the real ~8k-course catalog from a remote
Supabase over its REST API (read-only source; unencrypted catalog only).
- docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
- migrations 0021_gradebook / 0021_gradebook_curve / 0027_gradescope — IF NOT EXISTS
and user_courses->enrollments retarget guards so the chain replays cleanly from an
empty DB. These are no-ops on already-migrated databases (staging/prod unaffected).
- routes/auth.py — IS_LOCAL auto-approve so a first local Google sign-in skips the
/pending wall. Strictly APP_ENV-gated; staging/prod keep the real approval gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app now runs against a real local Supabase backend, so the mock-data path
(lib/localData.ts + all IS_LOCAL_MODE branches) is dead weight and a footgun —
having two ways to "run locally" masked real backend behavior.
Deletes src/lib/localData.ts and removes every IS_LOCAL_MODE branch across api.ts,
UserContext, SignInModal (the local-user-001 dev shortcut), Admin/Social/Learn,
ReportIssueFlow, useAchievementUnlockWatcher, and the middleware short-circuit +
its test stub. The real backend-fetch path is now the sole behavior. tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SignInModal: drop the `if (!API_URL)` guard so an empty (same-origin)
NEXT_PUBLIC_API_URL no longer aborts local Google sign-in as "not configured"
— this was silently blocking the PR's whole point.
- Storage buckets: create cosmetic-assets / issues-media-files / avatars + a
permissive local RLS policy in the bring-up scripts, so cosmetic and issue
uploads work in local dev after the mock removal (buckets weren't created locally).
- 0027_gradescope: guard the gradescope_course_links DROP on the old `user_id`
shape and make the CREATE `IF NOT EXISTS`, so it can't CASCADE-delete data on a
ledger-less replay; 0021_gradebook_curve: document the intentional redundant CHECK.
- seed_local_catalog: paginate until an empty page (robust to source max-rows caps)
and route local writes through db.connection.table() instead of a raw httpx client
(httpx kept only for the unavoidable cross-project source read).
- auth.py: fold is_approved into the new-user insert (drops the redundant UPDATE).
- Extract the duplicated migrate -> reload -> seed block into scripts/lib/local-common.sh.
- Docs: remove stale NEXT_PUBLIC_LOCAL_MODE references from frontend/README.md and
frontend/.env.example, and the dead /api/auth/dev-login comment in .env.local.example.
Verified: fresh replay still "Applied 33 migration(s)", buckets created, seed +
catalog pull succeed, decryption + Google redirect healthy, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndresL230
AndresL230force-pushed the feat/local-supabase-dev branch from e2d9666 to 73e989bCompareJuly 21, 2026 06:59
@AndresL230
AndresL230 changed the base branch from feat/streaming-tutor to mainJuly 21, 2026 06:59
AndresL230and others added 2 commits July 21, 2026 03:23
- auth.py: gate the local auto-approve on APP_ENV=="local" instead of the broader
IS_LOCAL (which includes APP_ENV=test) — it was auto-approving new users under the
test suite and failing the #285 approval-gate regression. All 7 auth-stub tests pass.
- 0027_gradescope: add IF NOT EXISTS to idx_gradescope_links_enrollment, and make the
old-shape gradescope_course_links DROP RAISE loudly if the table holds rows rather than
silently CASCADE-deleting them (the fresh-replay path is empty, so still lossless).
- 0021_gradebook: make gradebook_categories (+ its index) and the assignments indexes
idempotent (IF NOT EXISTS) so a ledger-less re-run doesn't abort mid-chain.
- scripts/lib/local-common.sh: fail fast with a clear message if backend/venv is missing.
- Setup docs/messaging: document creating backend/venv, and clarify that Google OAuth creds
are required to sign in locally (optional only to bring the stack up) — local-up.sh banner,
.env.local.example, docs/local-supabase.md.
Re-verified: Applied 34 migration(s) from empty, storage buckets + seed + catalog pull,
decryption, and the Google redirect all healthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The build-command config for the frontend-staging Worker was fixed
(npm run cf:build restored; the broken 'wrangler deploy --env staging'
skipped the OpenNext build). Empty commit to re-run CI with the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

feat(auth): local dev auth bypasses (open whitelist + auto-approve)

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(dev): local Supabase dev environment + Google-only local auth - #372

Merged
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev
Jul 22, 2026
Merged

feat(dev): local Supabase dev environment + Google-only local auth#372
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev

Conversation

@AndresL230

@AndresL230AndresL230 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A one-command local Supabase dev environment (rootless Podman) so the app runs full-stack against a local DB instead of the live staging DB — and teammates can reproduce it.

Contents

  • supabase/config.toml — local stack; analytics/edge-runtime disabled, auto_expose_new_tables=true (so migration-created tables are reachable by the Data API roles, matching hosted Supabase).
  • scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate): migrate → reload PostgREST → seed.
  • backend/.env.local.example + frontend/.env.local.example — turnkey local env with fixed, local-only keys (safe to commit).
  • backend/db/seed_local_catalog.py — pulls the real ~8k-course catalog from a remote Supabase over its REST API (read-only source; unencrypted catalog only).
  • docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
  • Migration guards (0021_gradebook, 0021_gradebook_curve, 0027_gradescope) — IF NOT EXISTS / user_coursesenrollments retargets so the chain replays cleanly from an empty DB. No-ops on already-migrated databases (staging/prod unaffected).
  • routes/auth.pyIS_LOCAL auto-approve — a first local Google sign-in skips the /pending wall. Strictly APP_ENV-gated; prod keeps the real approval gate.
  • Frontend mock removal — deletes lib/localData.ts + every IS_LOCAL_MODE branch (single source of truth; tsc clean).

Teammate setup

cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock" # fish
supabase start && scripts/local-up.sh
# then: (backend) python main.py (frontend) npm run dev → sign in with Google

Full guide: docs/local-supabase.md.

Notes

  • Rebased onto main (was originally cut from feat/streaming-tutor). The frontend mock removal and the auth.py auto-approve were re-resolved against main's versions during the rebase; conflicts were only in api.ts (re-stripped) and localData.ts (deleted).
  • Replay re-verified from empty against main's full setApplied 34 migration(s) including main's 0031, then storage buckets + seed + catalog pull, decryption, and the Google redirect all healthy; tsc clean.

Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a complete local Supabase setup with starter environment templates, seeded catalog support, and scripts to start or reset the local stack.
    • Added local Google OAuth sign-in with automatic approval for local development.
  • Bug Fixes
    • Local database migrations and indexes can now be safely rerun.
    • Improved avatar refresh behavior so updated profile images appear promptly.
  • Documentation
    • Added comprehensive local Supabase setup, configuration, OAuth, reset, and troubleshooting guidance.
  • Refactor
    • Removed mock-data local mode; local development now uses the real backend and services.

@AndresL230AndresL230 self-assigned this Jul 21, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging6765f49Commit Preview URL

Branch Preview URL
Jul 22 2026, 04:09 AM

@coderabbitai

coderabbitaiBot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 5fc87496-1065-4f97-a759-3ef2155194bb

📥 Commits

Reviewing files that changed from the base of the PR and between 73e989b and 6765f49.

📒 Files selected for processing (7)
  • backend/.env.local.example
  • backend/db/migrations/0021_gradebook.sql
  • backend/db/migrations/0027_gradescope.sql
  • backend/routes/auth.py
  • docs/local-supabase.md
  • scripts/lib/local-common.sh
  • scripts/local-up.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/.env.local.example
  • scripts/local-up.sh
  • backend/db/migrations/0027_gradescope.sql
  • docs/local-supabase.md
  • scripts/lib/local-common.sh

📝 Walkthrough

Walkthrough

The PR adds a local Supabase development stack, makes migrations replay-safe, adds catalog synchronization and local setup scripts, enables local OAuth approval, and removes frontend mock local mode in favor of real backend and Supabase integrations.

Changes

Local Supabase development

Layer / File(s)Summary
Environment and service configuration
.gitignore, backend/.env.local.example, frontend/.env.local.example, supabase/*, docs/local-supabase.md
Adds local environment templates, Supabase service configuration, ignored local secrets, and setup/troubleshooting documentation.
Replay-safe database migrations
backend/db/migrations/*
Retargets curve-policy columns and constraints to enrollments and makes gradebook and Gradescope schema changes rerunnable.
Local stack automation
scripts/*
Adds startup/reset workflows for migrations, storage buckets, PostgREST reloads, readiness checks, and demo seeding.
Catalog synchronization
backend/db/seed_local_catalog.py
Fetches remote courses and offerings with pagination and upserts them into local Supabase in batches.
Local OAuth approval
backend/routes/auth.py
Auto-approves newly created Google OAuth users when APP_ENV is local.
Real frontend integrations
frontend/src/lib/*, frontend/src/components/*, frontend/src/context/*, frontend/src/middleware*
Removes mock local mode, routes operations through real APIs and Supabase, updates profile refresh behavior, and keeps middleware protection active.
Frontend documentation
frontend/README.md
Documents backend proxy routing and points local development instructions to the local Supabase guide.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Browser
participant Next.js
participant Backend
participant Supabase
Browser->>Next.js: Request API or sign-in route
Next.js->>Backend: Proxy API request
Backend->>Supabase: Read or update application data
Supabase-->>Backend: Return data or auth state
Backend-->>Next.js: Return response
Next.js-->>Browser: Render real backend result
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

🖥️ Running this locally

This PR lets you run the whole app against a local Supabase (rootless Podman) instead of the live staging DB. Full guide: docs/local-supabase.md.

One-time setup

# 1. Podman + its rootless API socket (Arch/CachyOS shown; use your distro's pkg mgr)
sudo pacman -S --needed podman
systemctl --user enable --now podman.socket
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock"# fish (bash/zsh: export in your rc)# 2. Supabase CLI (AUR here; also: brew install supabase/tap/supabase, scoop, etc.)
paru -S supabase-bin
# 3. Env — fixed local-only keys are prefilled; just add your Gemini key
cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local

Bring the stack up

supabase start # Postgres + PostgREST + Storage + Studio, in Podman
scripts/local-up.sh # apply migrations → create storage buckets → seed demo data (idempotent)# optional: load the real ~8k-course catalog (read-only pull from staging)cd backend && python -m db.seed_local_catalog

Run it + sign in

cd backend && python main.py # :5000cd frontend && npm run dev # :3000

Open http://localhost:3000 and sign in with Google — the first local sign-in is auto-approved (no /pending wall). For real Google OAuth locally, add http://localhost:5000/api/auth/google/callback to your OAuth client's authorized redirect URIs.

Handy

AndresL230and others added 3 commits July 21, 2026 02:53
…l auth
Run the full app against a containerized Supabase (rootless Podman) instead of the
live staging DB, and let teammates reproduce it with one script.
- supabase/config.toml — local stack; analytics/edge-runtime disabled,
auto_expose_new_tables=true (required so migration-created tables are reachable
by the Data API roles, matching hosted Supabase).
- scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate):
migrate -> reload PostgREST schema -> seed.
- backend/.env.local.example + frontend/.env.local.example — turnkey local env with
fixed, local-only keys (safe to commit); un-ignored via !.env.local.example.
- backend/db/seed_local_catalog.py — pull the real ~8k-course catalog from a remote
Supabase over its REST API (read-only source; unencrypted catalog only).
- docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
- migrations 0021_gradebook / 0021_gradebook_curve / 0027_gradescope — IF NOT EXISTS
and user_courses->enrollments retarget guards so the chain replays cleanly from an
empty DB. These are no-ops on already-migrated databases (staging/prod unaffected).
- routes/auth.py — IS_LOCAL auto-approve so a first local Google sign-in skips the
/pending wall. Strictly APP_ENV-gated; staging/prod keep the real approval gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app now runs against a real local Supabase backend, so the mock-data path
(lib/localData.ts + all IS_LOCAL_MODE branches) is dead weight and a footgun —
having two ways to "run locally" masked real backend behavior.
Deletes src/lib/localData.ts and removes every IS_LOCAL_MODE branch across api.ts,
UserContext, SignInModal (the local-user-001 dev shortcut), Admin/Social/Learn,
ReportIssueFlow, useAchievementUnlockWatcher, and the middleware short-circuit +
its test stub. The real backend-fetch path is now the sole behavior. tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SignInModal: drop the `if (!API_URL)` guard so an empty (same-origin)
NEXT_PUBLIC_API_URL no longer aborts local Google sign-in as "not configured"
— this was silently blocking the PR's whole point.
- Storage buckets: create cosmetic-assets / issues-media-files / avatars + a
permissive local RLS policy in the bring-up scripts, so cosmetic and issue
uploads work in local dev after the mock removal (buckets weren't created locally).
- 0027_gradescope: guard the gradescope_course_links DROP on the old `user_id`
shape and make the CREATE `IF NOT EXISTS`, so it can't CASCADE-delete data on a
ledger-less replay; 0021_gradebook_curve: document the intentional redundant CHECK.
- seed_local_catalog: paginate until an empty page (robust to source max-rows caps)
and route local writes through db.connection.table() instead of a raw httpx client
(httpx kept only for the unavoidable cross-project source read).
- auth.py: fold is_approved into the new-user insert (drops the redundant UPDATE).
- Extract the duplicated migrate -> reload -> seed block into scripts/lib/local-common.sh.
- Docs: remove stale NEXT_PUBLIC_LOCAL_MODE references from frontend/README.md and
frontend/.env.example, and the dead /api/auth/dev-login comment in .env.local.example.
Verified: fresh replay still "Applied 33 migration(s)", buckets created, seed +
catalog pull succeed, decryption + Google redirect healthy, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndresL230
AndresL230force-pushed the feat/local-supabase-dev branch from e2d9666 to 73e989bCompareJuly 21, 2026 06:59
@AndresL230
AndresL230 changed the base branch from feat/streaming-tutor to mainJuly 21, 2026 06:59
AndresL230and others added 2 commits July 21, 2026 03:23
- auth.py: gate the local auto-approve on APP_ENV=="local" instead of the broader
IS_LOCAL (which includes APP_ENV=test) — it was auto-approving new users under the
test suite and failing the #285 approval-gate regression. All 7 auth-stub tests pass.
- 0027_gradescope: add IF NOT EXISTS to idx_gradescope_links_enrollment, and make the
old-shape gradescope_course_links DROP RAISE loudly if the table holds rows rather than
silently CASCADE-deleting them (the fresh-replay path is empty, so still lossless).
- 0021_gradebook: make gradebook_categories (+ its index) and the assignments indexes
idempotent (IF NOT EXISTS) so a ledger-less re-run doesn't abort mid-chain.
- scripts/lib/local-common.sh: fail fast with a clear message if backend/venv is missing.
- Setup docs/messaging: document creating backend/venv, and clarify that Google OAuth creds
are required to sign in locally (optional only to bring the stack up) — local-up.sh banner,
.env.local.example, docs/local-supabase.md.
Re-verified: Applied 34 migration(s) from empty, storage buckets + seed + catalog pull,
decryption, and the Google redirect all healthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The build-command config for the frontend-staging Worker was fixed
(npm run cf:build restored; the broken 'wrangler deploy --env staging'
skipped the OpenNext build). Empty commit to re-run CI with the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

feat(auth): local dev auth bypasses (open whitelist + auto-approve)

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(dev): local Supabase dev environment + Google-only local auth - #372

Merged
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev
Jul 22, 2026
Merged

feat(dev): local Supabase dev environment + Google-only local auth#372
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev

Conversation

@AndresL230

@AndresL230AndresL230 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A one-command local Supabase dev environment (rootless Podman) so the app runs full-stack against a local DB instead of the live staging DB — and teammates can reproduce it.

Contents

  • supabase/config.toml — local stack; analytics/edge-runtime disabled, auto_expose_new_tables=true (so migration-created tables are reachable by the Data API roles, matching hosted Supabase).
  • scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate): migrate → reload PostgREST → seed.
  • backend/.env.local.example + frontend/.env.local.example — turnkey local env with fixed, local-only keys (safe to commit).
  • backend/db/seed_local_catalog.py — pulls the real ~8k-course catalog from a remote Supabase over its REST API (read-only source; unencrypted catalog only).
  • docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
  • Migration guards (0021_gradebook, 0021_gradebook_curve, 0027_gradescope) — IF NOT EXISTS / user_coursesenrollments retargets so the chain replays cleanly from an empty DB. No-ops on already-migrated databases (staging/prod unaffected).
  • routes/auth.pyIS_LOCAL auto-approve — a first local Google sign-in skips the /pending wall. Strictly APP_ENV-gated; prod keeps the real approval gate.
  • Frontend mock removal — deletes lib/localData.ts + every IS_LOCAL_MODE branch (single source of truth; tsc clean).

Teammate setup

cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock" # fish
supabase start && scripts/local-up.sh
# then: (backend) python main.py (frontend) npm run dev → sign in with Google

Full guide: docs/local-supabase.md.

Notes

  • Rebased onto main (was originally cut from feat/streaming-tutor). The frontend mock removal and the auth.py auto-approve were re-resolved against main's versions during the rebase; conflicts were only in api.ts (re-stripped) and localData.ts (deleted).
  • Replay re-verified from empty against main's full setApplied 34 migration(s) including main's 0031, then storage buckets + seed + catalog pull, decryption, and the Google redirect all healthy; tsc clean.

Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a complete local Supabase setup with starter environment templates, seeded catalog support, and scripts to start or reset the local stack.
    • Added local Google OAuth sign-in with automatic approval for local development.
  • Bug Fixes
    • Local database migrations and indexes can now be safely rerun.
    • Improved avatar refresh behavior so updated profile images appear promptly.
  • Documentation
    • Added comprehensive local Supabase setup, configuration, OAuth, reset, and troubleshooting guidance.
  • Refactor
    • Removed mock-data local mode; local development now uses the real backend and services.

@AndresL230AndresL230 self-assigned this Jul 21, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging6765f49Commit Preview URL

Branch Preview URL
Jul 22 2026, 04:09 AM

@coderabbitai

coderabbitaiBot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 5fc87496-1065-4f97-a759-3ef2155194bb

📥 Commits

Reviewing files that changed from the base of the PR and between 73e989b and 6765f49.

📒 Files selected for processing (7)
  • backend/.env.local.example
  • backend/db/migrations/0021_gradebook.sql
  • backend/db/migrations/0027_gradescope.sql
  • backend/routes/auth.py
  • docs/local-supabase.md
  • scripts/lib/local-common.sh
  • scripts/local-up.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/.env.local.example
  • scripts/local-up.sh
  • backend/db/migrations/0027_gradescope.sql
  • docs/local-supabase.md
  • scripts/lib/local-common.sh

📝 Walkthrough

Walkthrough

The PR adds a local Supabase development stack, makes migrations replay-safe, adds catalog synchronization and local setup scripts, enables local OAuth approval, and removes frontend mock local mode in favor of real backend and Supabase integrations.

Changes

Local Supabase development

Layer / File(s)Summary
Environment and service configuration
.gitignore, backend/.env.local.example, frontend/.env.local.example, supabase/*, docs/local-supabase.md
Adds local environment templates, Supabase service configuration, ignored local secrets, and setup/troubleshooting documentation.
Replay-safe database migrations
backend/db/migrations/*
Retargets curve-policy columns and constraints to enrollments and makes gradebook and Gradescope schema changes rerunnable.
Local stack automation
scripts/*
Adds startup/reset workflows for migrations, storage buckets, PostgREST reloads, readiness checks, and demo seeding.
Catalog synchronization
backend/db/seed_local_catalog.py
Fetches remote courses and offerings with pagination and upserts them into local Supabase in batches.
Local OAuth approval
backend/routes/auth.py
Auto-approves newly created Google OAuth users when APP_ENV is local.
Real frontend integrations
frontend/src/lib/*, frontend/src/components/*, frontend/src/context/*, frontend/src/middleware*
Removes mock local mode, routes operations through real APIs and Supabase, updates profile refresh behavior, and keeps middleware protection active.
Frontend documentation
frontend/README.md
Documents backend proxy routing and points local development instructions to the local Supabase guide.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Browser
participant Next.js
participant Backend
participant Supabase
Browser->>Next.js: Request API or sign-in route
Next.js->>Backend: Proxy API request
Backend->>Supabase: Read or update application data
Supabase-->>Backend: Return data or auth state
Backend-->>Next.js: Return response
Next.js-->>Browser: Render real backend result
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

🖥️ Running this locally

This PR lets you run the whole app against a local Supabase (rootless Podman) instead of the live staging DB. Full guide: docs/local-supabase.md.

One-time setup

# 1. Podman + its rootless API socket (Arch/CachyOS shown; use your distro's pkg mgr)
sudo pacman -S --needed podman
systemctl --user enable --now podman.socket
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock"# fish (bash/zsh: export in your rc)# 2. Supabase CLI (AUR here; also: brew install supabase/tap/supabase, scoop, etc.)
paru -S supabase-bin
# 3. Env — fixed local-only keys are prefilled; just add your Gemini key
cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local

Bring the stack up

supabase start # Postgres + PostgREST + Storage + Studio, in Podman
scripts/local-up.sh # apply migrations → create storage buckets → seed demo data (idempotent)# optional: load the real ~8k-course catalog (read-only pull from staging)cd backend && python -m db.seed_local_catalog

Run it + sign in

cd backend && python main.py # :5000cd frontend && npm run dev # :3000

Open http://localhost:3000 and sign in with Google — the first local sign-in is auto-approved (no /pending wall). For real Google OAuth locally, add http://localhost:5000/api/auth/google/callback to your OAuth client's authorized redirect URIs.

Handy

AndresL230and others added 3 commits July 21, 2026 02:53
…l auth
Run the full app against a containerized Supabase (rootless Podman) instead of the
live staging DB, and let teammates reproduce it with one script.
- supabase/config.toml — local stack; analytics/edge-runtime disabled,
auto_expose_new_tables=true (required so migration-created tables are reachable
by the Data API roles, matching hosted Supabase).
- scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate):
migrate -> reload PostgREST schema -> seed.
- backend/.env.local.example + frontend/.env.local.example — turnkey local env with
fixed, local-only keys (safe to commit); un-ignored via !.env.local.example.
- backend/db/seed_local_catalog.py — pull the real ~8k-course catalog from a remote
Supabase over its REST API (read-only source; unencrypted catalog only).
- docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
- migrations 0021_gradebook / 0021_gradebook_curve / 0027_gradescope — IF NOT EXISTS
and user_courses->enrollments retarget guards so the chain replays cleanly from an
empty DB. These are no-ops on already-migrated databases (staging/prod unaffected).
- routes/auth.py — IS_LOCAL auto-approve so a first local Google sign-in skips the
/pending wall. Strictly APP_ENV-gated; staging/prod keep the real approval gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app now runs against a real local Supabase backend, so the mock-data path
(lib/localData.ts + all IS_LOCAL_MODE branches) is dead weight and a footgun —
having two ways to "run locally" masked real backend behavior.
Deletes src/lib/localData.ts and removes every IS_LOCAL_MODE branch across api.ts,
UserContext, SignInModal (the local-user-001 dev shortcut), Admin/Social/Learn,
ReportIssueFlow, useAchievementUnlockWatcher, and the middleware short-circuit +
its test stub. The real backend-fetch path is now the sole behavior. tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SignInModal: drop the `if (!API_URL)` guard so an empty (same-origin)
NEXT_PUBLIC_API_URL no longer aborts local Google sign-in as "not configured"
— this was silently blocking the PR's whole point.
- Storage buckets: create cosmetic-assets / issues-media-files / avatars + a
permissive local RLS policy in the bring-up scripts, so cosmetic and issue
uploads work in local dev after the mock removal (buckets weren't created locally).
- 0027_gradescope: guard the gradescope_course_links DROP on the old `user_id`
shape and make the CREATE `IF NOT EXISTS`, so it can't CASCADE-delete data on a
ledger-less replay; 0021_gradebook_curve: document the intentional redundant CHECK.
- seed_local_catalog: paginate until an empty page (robust to source max-rows caps)
and route local writes through db.connection.table() instead of a raw httpx client
(httpx kept only for the unavoidable cross-project source read).
- auth.py: fold is_approved into the new-user insert (drops the redundant UPDATE).
- Extract the duplicated migrate -> reload -> seed block into scripts/lib/local-common.sh.
- Docs: remove stale NEXT_PUBLIC_LOCAL_MODE references from frontend/README.md and
frontend/.env.example, and the dead /api/auth/dev-login comment in .env.local.example.
Verified: fresh replay still "Applied 33 migration(s)", buckets created, seed +
catalog pull succeed, decryption + Google redirect healthy, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndresL230
AndresL230force-pushed the feat/local-supabase-dev branch from e2d9666 to 73e989bCompareJuly 21, 2026 06:59
@AndresL230
AndresL230 changed the base branch from feat/streaming-tutor to mainJuly 21, 2026 06:59
AndresL230and others added 2 commits July 21, 2026 03:23
- auth.py: gate the local auto-approve on APP_ENV=="local" instead of the broader
IS_LOCAL (which includes APP_ENV=test) — it was auto-approving new users under the
test suite and failing the #285 approval-gate regression. All 7 auth-stub tests pass.
- 0027_gradescope: add IF NOT EXISTS to idx_gradescope_links_enrollment, and make the
old-shape gradescope_course_links DROP RAISE loudly if the table holds rows rather than
silently CASCADE-deleting them (the fresh-replay path is empty, so still lossless).
- 0021_gradebook: make gradebook_categories (+ its index) and the assignments indexes
idempotent (IF NOT EXISTS) so a ledger-less re-run doesn't abort mid-chain.
- scripts/lib/local-common.sh: fail fast with a clear message if backend/venv is missing.
- Setup docs/messaging: document creating backend/venv, and clarify that Google OAuth creds
are required to sign in locally (optional only to bring the stack up) — local-up.sh banner,
.env.local.example, docs/local-supabase.md.
Re-verified: Applied 34 migration(s) from empty, storage buckets + seed + catalog pull,
decryption, and the Google redirect all healthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The build-command config for the frontend-staging Worker was fixed
(npm run cf:build restored; the broken 'wrangler deploy --env staging'
skipped the OpenNext build). Empty commit to re-run CI with the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

feat(auth): local dev auth bypasses (open whitelist + auto-approve)

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(dev): local Supabase dev environment + Google-only local auth - #372

Merged
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev
Jul 22, 2026
Merged

feat(dev): local Supabase dev environment + Google-only local auth#372
AndresL230 merged 5 commits into
mainfrom
feat/local-supabase-dev

Conversation

@AndresL230

@AndresL230AndresL230 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A one-command local Supabase dev environment (rootless Podman) so the app runs full-stack against a local DB instead of the live staging DB — and teammates can reproduce it.

Contents

  • supabase/config.toml — local stack; analytics/edge-runtime disabled, auto_expose_new_tables=true (so migration-created tables are reachable by the Data API roles, matching hosted Supabase).
  • scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate): migrate → reload PostgREST → seed.
  • backend/.env.local.example + frontend/.env.local.example — turnkey local env with fixed, local-only keys (safe to commit).
  • backend/db/seed_local_catalog.py — pulls the real ~8k-course catalog from a remote Supabase over its REST API (read-only source; unencrypted catalog only).
  • docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
  • Migration guards (0021_gradebook, 0021_gradebook_curve, 0027_gradescope) — IF NOT EXISTS / user_coursesenrollments retargets so the chain replays cleanly from an empty DB. No-ops on already-migrated databases (staging/prod unaffected).
  • routes/auth.pyIS_LOCAL auto-approve — a first local Google sign-in skips the /pending wall. Strictly APP_ENV-gated; prod keeps the real approval gate.
  • Frontend mock removal — deletes lib/localData.ts + every IS_LOCAL_MODE branch (single source of truth; tsc clean).

Teammate setup

cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock" # fish
supabase start && scripts/local-up.sh
# then: (backend) python main.py (frontend) npm run dev → sign in with Google

Full guide: docs/local-supabase.md.

Notes

  • Rebased onto main (was originally cut from feat/streaming-tutor). The frontend mock removal and the auth.py auto-approve were re-resolved against main's versions during the rebase; conflicts were only in api.ts (re-stripped) and localData.ts (deleted).
  • Replay re-verified from empty against main's full setApplied 34 migration(s) including main's 0031, then storage buckets + seed + catalog pull, decryption, and the Google redirect all healthy; tsc clean.

Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a complete local Supabase setup with starter environment templates, seeded catalog support, and scripts to start or reset the local stack.
    • Added local Google OAuth sign-in with automatic approval for local development.
  • Bug Fixes
    • Local database migrations and indexes can now be safely rerun.
    • Improved avatar refresh behavior so updated profile images appear promptly.
  • Documentation
    • Added comprehensive local Supabase setup, configuration, OAuth, reset, and troubleshooting guidance.
  • Refactor
    • Removed mock-data local mode; local development now uses the real backend and services.

@AndresL230AndresL230 self-assigned this Jul 21, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-staging6765f49Commit Preview URL

Branch Preview URL
Jul 22 2026, 04:09 AM

@coderabbitai

coderabbitaiBot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 5fc87496-1065-4f97-a759-3ef2155194bb

📥 Commits

Reviewing files that changed from the base of the PR and between 73e989b and 6765f49.

📒 Files selected for processing (7)
  • backend/.env.local.example
  • backend/db/migrations/0021_gradebook.sql
  • backend/db/migrations/0027_gradescope.sql
  • backend/routes/auth.py
  • docs/local-supabase.md
  • scripts/lib/local-common.sh
  • scripts/local-up.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/.env.local.example
  • scripts/local-up.sh
  • backend/db/migrations/0027_gradescope.sql
  • docs/local-supabase.md
  • scripts/lib/local-common.sh

📝 Walkthrough

Walkthrough

The PR adds a local Supabase development stack, makes migrations replay-safe, adds catalog synchronization and local setup scripts, enables local OAuth approval, and removes frontend mock local mode in favor of real backend and Supabase integrations.

Changes

Local Supabase development

Layer / File(s)Summary
Environment and service configuration
.gitignore, backend/.env.local.example, frontend/.env.local.example, supabase/*, docs/local-supabase.md
Adds local environment templates, Supabase service configuration, ignored local secrets, and setup/troubleshooting documentation.
Replay-safe database migrations
backend/db/migrations/*
Retargets curve-policy columns and constraints to enrollments and makes gradebook and Gradescope schema changes rerunnable.
Local stack automation
scripts/*
Adds startup/reset workflows for migrations, storage buckets, PostgREST reloads, readiness checks, and demo seeding.
Catalog synchronization
backend/db/seed_local_catalog.py
Fetches remote courses and offerings with pagination and upserts them into local Supabase in batches.
Local OAuth approval
backend/routes/auth.py
Auto-approves newly created Google OAuth users when APP_ENV is local.
Real frontend integrations
frontend/src/lib/*, frontend/src/components/*, frontend/src/context/*, frontend/src/middleware*
Removes mock local mode, routes operations through real APIs and Supabase, updates profile refresh behavior, and keeps middleware protection active.
Frontend documentation
frontend/README.md
Documents backend proxy routing and points local development instructions to the local Supabase guide.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Browser
participant Next.js
participant Backend
participant Supabase
Browser->>Next.js: Request API or sign-in route
Next.js->>Backend: Proxy API request
Backend->>Supabase: Read or update application data
Supabase-->>Backend: Return data or auth state
Backend-->>Next.js: Return response
Next.js-->>Browser: Render real backend result
Loading

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@AndresL230

Copy link
Copy Markdown
CollaboratorAuthor

🖥️ Running this locally

This PR lets you run the whole app against a local Supabase (rootless Podman) instead of the live staging DB. Full guide: docs/local-supabase.md.

One-time setup

# 1. Podman + its rootless API socket (Arch/CachyOS shown; use your distro's pkg mgr)
sudo pacman -S --needed podman
systemctl --user enable --now podman.socket
set -Ux DOCKER_HOST "unix:///run/user/"(id -u)"/podman/podman.sock"# fish (bash/zsh: export in your rc)# 2. Supabase CLI (AUR here; also: brew install supabase/tap/supabase, scoop, etc.)
paru -S supabase-bin
# 3. Env — fixed local-only keys are prefilled; just add your Gemini key
cp backend/.env.local.example backend/.env # then fill GEMINI_API_KEY
cp frontend/.env.local.example frontend/.env.local

Bring the stack up

supabase start # Postgres + PostgREST + Storage + Studio, in Podman
scripts/local-up.sh # apply migrations → create storage buckets → seed demo data (idempotent)# optional: load the real ~8k-course catalog (read-only pull from staging)cd backend && python -m db.seed_local_catalog

Run it + sign in

cd backend && python main.py # :5000cd frontend && npm run dev # :3000

Open http://localhost:3000 and sign in with Google — the first local sign-in is auto-approved (no /pending wall). For real Google OAuth locally, add http://localhost:5000/api/auth/google/callback to your OAuth client's authorized redirect URIs.

Handy

AndresL230and others added 3 commits July 21, 2026 02:53
…l auth
Run the full app against a containerized Supabase (rootless Podman) instead of the
live staging DB, and let teammates reproduce it with one script.
- supabase/config.toml — local stack; analytics/edge-runtime disabled,
auto_expose_new_tables=true (required so migration-created tables are reachable
by the Data API roles, matching hosted Supabase).
- scripts/local-up.sh (idempotent bring-up) + scripts/local-db-reset.sh (clean slate):
migrate -> reload PostgREST schema -> seed.
- backend/.env.local.example + frontend/.env.local.example — turnkey local env with
fixed, local-only keys (safe to commit); un-ignored via !.env.local.example.
- backend/db/seed_local_catalog.py — pull the real ~8k-course catalog from a remote
Supabase over its REST API (read-only source; unencrypted catalog only).
- docs/local-supabase.md — setup, run loop, sign-in, troubleshooting.
- migrations 0021_gradebook / 0021_gradebook_curve / 0027_gradescope — IF NOT EXISTS
and user_courses->enrollments retarget guards so the chain replays cleanly from an
empty DB. These are no-ops on already-migrated databases (staging/prod unaffected).
- routes/auth.py — IS_LOCAL auto-approve so a first local Google sign-in skips the
/pending wall. Strictly APP_ENV-gated; staging/prod keep the real approval gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app now runs against a real local Supabase backend, so the mock-data path
(lib/localData.ts + all IS_LOCAL_MODE branches) is dead weight and a footgun —
having two ways to "run locally" masked real backend behavior.
Deletes src/lib/localData.ts and removes every IS_LOCAL_MODE branch across api.ts,
UserContext, SignInModal (the local-user-001 dev shortcut), Admin/Social/Learn,
ReportIssueFlow, useAchievementUnlockWatcher, and the middleware short-circuit +
its test stub. The real backend-fetch path is now the sole behavior. tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SignInModal: drop the `if (!API_URL)` guard so an empty (same-origin)
NEXT_PUBLIC_API_URL no longer aborts local Google sign-in as "not configured"
— this was silently blocking the PR's whole point.
- Storage buckets: create cosmetic-assets / issues-media-files / avatars + a
permissive local RLS policy in the bring-up scripts, so cosmetic and issue
uploads work in local dev after the mock removal (buckets weren't created locally).
- 0027_gradescope: guard the gradescope_course_links DROP on the old `user_id`
shape and make the CREATE `IF NOT EXISTS`, so it can't CASCADE-delete data on a
ledger-less replay; 0021_gradebook_curve: document the intentional redundant CHECK.
- seed_local_catalog: paginate until an empty page (robust to source max-rows caps)
and route local writes through db.connection.table() instead of a raw httpx client
(httpx kept only for the unavoidable cross-project source read).
- auth.py: fold is_approved into the new-user insert (drops the redundant UPDATE).
- Extract the duplicated migrate -> reload -> seed block into scripts/lib/local-common.sh.
- Docs: remove stale NEXT_PUBLIC_LOCAL_MODE references from frontend/README.md and
frontend/.env.example, and the dead /api/auth/dev-login comment in .env.local.example.
Verified: fresh replay still "Applied 33 migration(s)", buckets created, seed +
catalog pull succeed, decryption + Google redirect healthy, tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndresL230
AndresL230force-pushed the feat/local-supabase-dev branch from e2d9666 to 73e989bCompareJuly 21, 2026 06:59
@AndresL230
AndresL230 changed the base branch from feat/streaming-tutor to mainJuly 21, 2026 06:59
AndresL230and others added 2 commits July 21, 2026 03:23
- auth.py: gate the local auto-approve on APP_ENV=="local" instead of the broader
IS_LOCAL (which includes APP_ENV=test) — it was auto-approving new users under the
test suite and failing the #285 approval-gate regression. All 7 auth-stub tests pass.
- 0027_gradescope: add IF NOT EXISTS to idx_gradescope_links_enrollment, and make the
old-shape gradescope_course_links DROP RAISE loudly if the table holds rows rather than
silently CASCADE-deleting them (the fresh-replay path is empty, so still lossless).
- 0021_gradebook: make gradebook_categories (+ its index) and the assignments indexes
idempotent (IF NOT EXISTS) so a ledger-less re-run doesn't abort mid-chain.
- scripts/lib/local-common.sh: fail fast with a clear message if backend/venv is missing.
- Setup docs/messaging: document creating backend/venv, and clarify that Google OAuth creds
are required to sign in locally (optional only to bring the stack up) — local-up.sh banner,
.env.local.example, docs/local-supabase.md.
Re-verified: Applied 34 migration(s) from empty, storage buckets + seed + catalog pull,
decryption, and the Google redirect all healthy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The build-command config for the frontend-staging Worker was fixed
(npm run cf:build restored; the broken 'wrangler deploy --env staging'
skipped the OpenNext build). Empty commit to re-run CI with the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

feat(auth): local dev auth bypasses (open whitelist + auto-approve)

1 participant

@AndresL230