# Checkpoint ## Major Tasks Completed 1. Docker deployment scaffolded for all 6 apps in the monorepo. 2. Split API images into app-specific Dockerfiles: - `apps/edr-freight-api/Dockerfile` - `apps/edr-passenger-api/Dockerfile` 3. Kept shared Vite/nginx image: - `infrastructure/docker/Dockerfile.web` - `infrastructure/nginx/spa.conf` 4. Updated `docker-compose.yaml` to run all 6 services (apps only, no Postgres service in compose). 5. Added/updated deployment scripts: - `scripts/deploy/create-npmrc.sh` - `scripts/deploy/sync-env-from-server.sh` 6. Added self-hosted GitHub Actions deployment workflow: - Consolidated into one file: `.github/workflows/deploy.yml` 7. Deployment workflow now: - uses a single checkout (`prepare` job), - deploys services via parallel matrix, - sets compose project names per branch/environment, - passes explicit `docker compose --project-name`. 8. Environment sync script now: - supports branch slug paths, - validates each service env file exists, - requires `PORT` in each env file, - exports per-service port vars to `GITHUB_ENV`. 9. `docker-compose.yaml` now reads per-service ports via variables exported from env sync. 10. Passenger startup flow fixed to run: - `prisma:generate`, - `prisma:migrate`, - `prisma:seed`, before API startup. 11. Passenger seed TypeScript issues fixed in `apps/edr-passenger-api/prisma/seed.ts` so it compiles under strict checks. 12. Added deployment runbook: - `DEPLOYMENT.md` ## Passenger Web Migration to Next.js 13. Passenger web apps migrated from Vite/SPA to Next.js: - Updated `apps/edr-passenger-web/portal/next.config.js` and `apps/edr-passenger-web/backoffice/next.config.js`: - Removed `output: 'export'` to enable server mode - Preserved `transpilePackages` for @edr/* shared packages 14. Created dedicated Next.js Dockerfile: - `infrastructure/docker/Dockerfile.passenger-web` - Uses Node.js server (not nginx) for better Next.js support - Builds with turbo, runs `npx next start` in the final stage - Accepts build args: `APP_PACKAGE`, `APP_PATH`, `NEXT_PUBLIC_API_URL` 15. Updated docker-compose.yaml: - `passenger-portal` and `passenger-backoffice` now use `infrastructure/docker/Dockerfile.passenger-web` - Port mappings are fully dynamic: both host and container ports use `${PASSENGER_PORTAL_PORT}` / `${PASSENGER_BACKOFFICE_PORT}`, driven by `PORT` in the service env file - `NEXT_PUBLIC_API_URL` build arg sourced directly from the service env file (no separate build env file needed) 16. Updated DEPLOYMENT.md to reflect all of the above. ## Port Mapping Fix (Latest) 17. Fixed passenger web port mapping mismatch (`0.0.0.0:8003->5184/tcp`): - Container port was hardcoded (`5174`/`5184`); host port came from `PORT` in the env file via the sync script - Both sides of the mapping now use `${PASSENGER_PORTAL_PORT:-5174}` / `${PASSENGER_BACKOFFICE_PORT:-5184}` - Removed hardcoded `PORT` build arg from docker-compose.yaml (runtime `env_file` supplies it to Next.js) ## NEXT_PUBLIC_API_URL Build-Time Fix (Latest) 18. Fixed passenger web apps using `localhost:4000` instead of the configured API URL: - Root cause: `NEXT_PUBLIC_*` vars are baked into the JS bundle at build time; setting them in the runtime `env_file` has no effect - `sync-env-from-server.sh` now extracts any `NEXT_PUBLIC_*` vars from the service `.env` and writes them to `GITHUB_ENV` before the build step - `docker-compose.yaml` build arg renamed from `PASSENGER_NEXT_PUBLIC_API_URL` to `NEXT_PUBLIC_API_URL` to match the key used in the service env files directly ## Key Files to Review - `.github/workflows/deploy.yml` - `docker-compose.yaml` - `scripts/deploy/sync-env-from-server.sh` - `scripts/deploy/create-npmrc.sh` - `apps/edr-passenger-api/docker-entrypoint.sh` - `apps/edr-passenger-api/prisma/seed.ts` - `infrastructure/docker/Dockerfile.passenger-web` (NEW) - `apps/edr-freight-api/Dockerfile` (MODIFIED — pnpm store cache) - `apps/edr-passenger-api/Dockerfile` (MODIFIED — prisma generate in /deploy + pnpm store cache) - `apps/edr-payment-api/Dockerfile` (MODIFIED — pnpm store cache) - `infrastructure/docker/Dockerfile.web` (MODIFIED — pnpm store cache) - `apps/edr-passenger-web/portal/next.config.js` (MODIFIED) - `apps/edr-passenger-web/backoffice/next.config.js` (MODIFIED) - `DEPLOYMENT.md` (MODIFIED) ## Backoffice Pages — Completion 19. All backoffice pages are now fully implemented and connected to the API: - `live/page.tsx` — replaced stub with real LiveTrackingPage using `liveApi` (trips, crowd signals, delay/status stats) - `notifications/page.tsx` — replaced hardcoded mock + broken `Table` import with real page using `notificationsApi` (templates list, send form, notification history tab) ## Prisma Client Missing After `pnpm deploy` (Latest) 20. Fixed passenger API crash in Docker (`TypeError: Cannot convert undefined or null to object` at `class-validator` `IsEnum`, triggered by `dist/modules/fare-engine/currency.dto.js`): - Root cause: `currency.dto.ts` imports the `Currency` enum (a runtime value) from `@prisma/client`. The generated Prisma client is an output of `prisma generate`, not a package in the pnpm store, so `pnpm deploy` did not copy it into `/deploy`. At runtime `Currency` resolved to `undefined` → `@IsEnum(undefined)` → `Object.entries(undefined)` throws at module load. - Prisma 6 + pnpm writes the client to `node_modules/.pnpm/@prisma+client@.../node_modules/.prisma/client`, **not** root `node_modules/.prisma`. The old `cp` rescue in the Dockerfile guarded on `[ -d node_modules/.prisma ]` (root) which never existed → silently skipped. - Fix in `apps/edr-passenger-api/Dockerfile`: replaced the broken `cp` with `RUN cd /deploy && npm run prisma:generate` after `pnpm deploy`, regenerating the client into the exact runtime-resolve path (`/deploy/node_modules/.prisma/client`). Safe because deploy has no `--prod` flag (so the `prisma` CLI ships) and `package.json` declares the schema path. - Affected 16 passenger-api files importing from `@prisma/client`; `currency.dto.js` just loaded first. payment-api unaffected (TypeORM, no Prisma). ## pnpm Store Build Cache Fix (Latest) 21. Fixed Docker builds re-downloading all dependencies every pipeline run: - Root cause: install steps used `--mount=type=cache,id=pnpm,target=/pnpm/store`, but nothing set pnpm's store-dir to `/pnpm/store`. Default store (`~/.local/share/pnpm/store`) was never under the mount → BuildKit cached an empty dir → full re-download each build. The two web Dockerfiles had the mount but it was dead; the two API Dockerfiles (freight, payment) had no mount at all. - Fix: added `ENV PNPM_HOME="/pnpm"` (+ PATH) to the `base` stage of all 5 Dockerfiles so the store resolves to `/pnpm/store`, matching the mount. Added the cache mount to every `pnpm install` and `pnpm deploy` step that lacked it. - Files: `apps/edr-freight-api/Dockerfile`, `apps/edr-passenger-api/Dockerfile`, `apps/edr-payment-api/Dockerfile`, `infrastructure/docker/Dockerfile.web`, `infrastructure/docker/Dockerfile.passenger-web`. - Caveat: BuildKit cache mounts live on the runner host; persists only while the same self-hosted runner/builder is reused and not pruned (`docker builder prune` wipes it). ## Next Actions 1. Run full CI on all target branches (`main`, `dev`, `staging`) and verify matrix job behavior. 2. Validate server env directory layout matches script expectations: - `/home//environment/edr///...` 3. Confirm each service env file includes valid `PORT` and service-specific runtime vars. 4. Verify branch-specific compose project names produce isolated containers/networks/volumes on runner. 5. Smoke test all 6 deployed services behind real environment URLs. ## Open Risks / Notes 1. Passenger seed runs on every container start; confirm this is desired for production-like environments. 2. Prisma warns about `package.json#prisma` deprecation (Prisma 7 migration pending). 3. Matrix parallelism increases runner load; ensure self-hosted runner capacity is sufficient. 4. Port collisions are prevented by env-driven mapping, but bad env values can still cause runtime conflicts. 5. Passenger web uses Next.js server mode (not static export): - Requires Node.js at runtime (previously could use pure static hosting) - `NEXT_PUBLIC_API_URL` must be set in the service env file (`passenger-portal.env` / `passenger-backoffice.env`) — the sync script forwards it to the build automatically - Each portal/backoffice instance runs its own Node.js process (watch container memory usage) 6. Freight web still uses Vite+nginx (different from passenger web) — maintain both Dockerfiles separately