feat: add Docker Compose local dev stack #5
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "4-add-docker-compose-local-dev-stack-fully"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Fully self-contained 4-service Docker Compose stack (postgres, keycloak, api, app) for local development. Zero external dependencies — works offline. Production URLs are preserved as fallback defaults when env vars are unset.
Changes
docker-compose.yml— 4-service stack with health checks, properdepends_onordering, and named volumes for persistencedev/realm-export.json— Keycloak realm with PKCE client config and 3 test users (testuser, testadmin, emptyuser)dev/seed-data.py— Python script that authenticates via Keycloak direct grant and seeds 7 Denver locations + 10 codes via the API.env.example— Documents allVITE_*env vars for referencesrc/lib/api.js—API_BASEnow readsVITE_API_URLwith production URL as fallbacksrc/lib/keycloak.js— Keycloak config now readsVITE_KEYCLOAK_URL,VITE_KEYCLOAK_REALM,VITE_KEYCLOAK_CLIENT_IDwith production fallbacksTest Plan
docker compose up -d— all 4 services should start and become healthyhttp://localhost:5173— app loads, Keycloak login redirects tolocalhost:8080testuser/testpass— should authenticate and reach home screenpython dev/seed-data.py— should create locations and codes for testuser/testadminReview Checklist
docker compose configvalidates successfullyRelated
Closes #4
Self-Review
Reviewed full diff (6 files, +404/-4). No issues found.
Verified:
api.jsandkeycloak.jschanges are minimal -- env var reads with production fallback defaults onlydocker-compose.ymlvalidates (docker compose configpassed), health checks use correct patterns (pg_isready, exec tcp for keycloak)dev/realm-export.jsonis valid Keycloak realm export with PKCE S256, public client, 3 test users with correct role mappingsdev/seed-data.pyuses correct API endpoints (POST /locations, POST /locations/{id}/codes, PATCH /codes/{id}/redeem), includes service readiness wait.env.examplecovered by existing.gitignoreexception (!.env.example)PR #5 Review
DOMAIN REVIEW
Tech stack identified: Docker Compose (dev infra), SvelteKit/JS (frontend config), Python (seed script), Keycloak realm JSON (OIDC config).
Docker Compose (
docker-compose.yml)pg_isready, named volume for persistence. Good.start-dev --import-realmis correct for dev. Healthcheck usesexec 3<>/dev/tcp/localhost/8080instead of curl -- correct, since curl is not available in the Keycloak image.start_period: 30sgives Keycloak time to boot. Good.../mcd-tracker-apiassumes the API repo is checked out as a sibling directory. This is correct per repo layout conventions.depends_onusesservice_healthyconditions for both postgres and keycloak. The API runs Alembic migrations on startup (confirmed inmcd_tracker_api/main.py:35), so no separate migration step needed. Environment variables match theMCD_TRACKER_prefix in the API's pydantic settings config. Good.apiservice has nohealthcheckdefined. Theappservice depends onapiwith a bare- api(no health condition), so the app container starts as soon as the API container is running, not necessarily ready. For a dev stack this is acceptable -- the Vite dev server will just show connection errors until the API is up. Not a blocker.node:22-alpine, bind-mounts the source code, and uses a named volume fornode_modulesto avoid platform-specific binary conflicts.npm install && npm run dev -- --hostis the standard pattern. Good.mcd_tracker_dev(postgres) andadmin/admin(keycloak admin) are dev-only credentials, plaintext in a dev compose file. This is acceptable -- these are local dev fixtures, not production secrets.SvelteKit config changes
src/lib/api.jsline 11:import.meta.env.VITE_API_URL || 'https://mcd-tracker.tail5b443a.ts.net'-- production fallback preserved. Correct.src/lib/keycloak.jslines 12-14: All threeVITE_KEYCLOAK_*vars with production fallbacks. Correct.Keycloak realm export (
dev/realm-export.json)mcd-tracker).mcd-tracker-app:publicClient: true,standardFlowEnabled: true,directAccessGrantsEnabled: true(needed for seed script's resource owner password grant). PKCE configured withS256. Good.http://localhost:5173/*andcapacitor://localhost/*. Web origins match. Good.sslRequired: "none"is correct for local dev (no TLS on localhost).temporary: falsepasswords. Role assignments look correct (testadmin gets bothuserandadmin).Seed script (
dev/seed-data.py)grant_type: password) with the Keycloak token endpoint. Correct auth flow for scripted seeding.POST /locations,POST /locations/{id}/codes,PATCH /codes/{id}/redeem-- these match the API router structure (confirmed:locations_routerandcodes_routerare included inmain.py).requestsimport check with helpful error message..env.exampleVITE_*vars..gitignoreexcludes.envand.env.*but explicitly includes!.env.example. Good.BLOCKERS
None.
This PR adds dev infrastructure (Docker Compose, realm config, seed script) and minimal config changes to existing source files (env var with fallback). No new user-facing functionality requiring test coverage. The source changes (2 files, 6 lines changed) are purely additive env-var reads with fallback defaults -- no behavioral change in production.
NITS
Seed script health check URL mismatch:
wait_for_services()indev/seed-data.pyline 149 checks{API_URL}/health, but the actual API health endpoint is/healthz(see/home/ldraney/mcd-tracker-api/src/mcd_tracker_api/routes/health.py:15). The wait loop still passes because404 < 500, so the script won't fail. But it does not actually validate the API is healthy (the DB connectivity check in/healthzis never exercised). Should be changed to/healthz.API service has no healthcheck: Adding a healthcheck to the
apiservice and usingcondition: service_healthyin theappservice'sdepends_onwould prevent the app from starting before the API is ready. Low priority for a dev stack.api.jsdoc comment stale: Line 4-5 insrc/lib/api.jsstill says the hardcoded URL as if it is the only target. Consider updating the comment to mention the env var override.Seed script
testadminsection is not DRY: Lines 206-211 duplicate the auth + location creation pattern thatseed_user()already handles. Could callseed_userwith a subset of locations, or parameterizeseed_userto accept a location list. Minor.f-string without interpolation: Line 206 of
dev/seed-data.pyusesf"\nSeeding data for 'testadmin'..."but there is nothing to interpolate. Plain string would be cleaner.SOP COMPLIANCE
4-add-docker-compose-local-dev-stack-fullyreferences issue #4).envis gitignored,.env.examplecommitted correctly)PROCESS OBSERVATIONS
apiservice'sbuild: ../mcd-tracker-apirequires the API repo to be checked out alongside this repo. This is documented implicitly but could benefit from a note in the README or a comment in docker-compose.yml for onboarding.VERDICT: APPROVED
Clean, well-structured local dev stack. Production fallbacks are preserved. No behavioral changes to production code paths. The health endpoint URL mismatch in the seed script (nit #1) is the most actionable item but is non-blocking since the script still functions correctly.