This commit is contained in:
2025-12-26 20:54:20 +01:00
parent 904feb41b8
commit 6389be4f0c
26 changed files with 745 additions and 195 deletions

View File

@@ -13,13 +13,13 @@ npm run docker:dev:build
This will:
- Start PostgreSQL database on port 5432
- Start API on port 3000 (with debugger on 9229)
- Start Website on port 3001
- Start API on port 3001 (container port 3000, debugger 9229)
- Start Website on port 3000
- Enable hot-reloading for both apps
Access:
- Website: http://localhost:3001
- API: http://localhost:3000
- Website: http://localhost:3000
- API: http://localhost:3001
- Database: localhost:5432
### Production
@@ -54,16 +54,93 @@ Access:
- `npm run docker:prod:logs` - View logs
- `npm run docker:prod:clean` - Stop and remove volumes
### Testing (Docker)
The goal of Docker-backed tests is to catch *wiring* issues between Website ↔ API (wrong hostnames/ports/env vars, missing CORS for credentialed requests, etc.) in a deterministic environment.
- `npm run test:docker:website` - Start a dedicated test stack (ports `3100/3101`) and run Playwright smoke tests against it.
- Uses [`docker-compose.test.yml`](docker-compose.test.yml:1).
- Runs the Website in Docker and talks to an **API mock** container.
- Validates that pages render and that core API fetches succeed (hostname + CORS + routing).
Supporting scripts:
- `npm run docker:test:deps` - Install monorepo deps inside a reusable Docker volume (one-shot).
- `npm run docker:test:up` - Bring up the test stack.
- `npm run docker:test:wait` - Wait for `http://localhost:3100` and `http://localhost:3101/health` to be ready.
- `npm run docker:test:down` - Tear the test stack down (including volumes).
## Environment Variables
### “Mock vs Real” (Website & API)
There is **no** `AUTOMATION_MODE` equivalent for the Website/API runtime.
- **Website “mock vs real”** is controlled purely by *which API base URL you point it at* via [`getWebsiteApiBaseUrl()`](apps/website/lib/config/apiBaseUrl.ts:6):
- Browser calls use `NEXT_PUBLIC_API_BASE_URL`
- Server/Next.js calls use `API_BASE_URL ?? NEXT_PUBLIC_API_BASE_URL`
- **API “mock vs real”** is controlled by API runtime env:
- Persistence: `GRIDPILOT_API_PERSISTENCE=postgres|inmemory` in [`AppModule`](apps/api/src/app.module.ts:25)
- Optional bootstrapping: `GRIDPILOT_API_BOOTSTRAP=0|1` in [`AppModule`](apps/api/src/app.module.ts:35)
Practical presets:
- **Website + real API (Docker dev)**: `npm run docker:dev:build` (Website `3000`, API `3001`, Postgres required).
- Website browser → API: `NEXT_PUBLIC_API_BASE_URL=http://localhost:3001`
- Website container → API container: `API_BASE_URL=http://api:3000`
- **Website + mock API (Docker smoke)**: `npm run test:docker:website` (Website `3100`, API mock `3101`).
- API mock is defined inline in [`docker-compose.test.yml`](docker-compose.test.yml:24)
- Website browser → API mock: `NEXT_PUBLIC_API_BASE_URL=http://localhost:3101`
- Website container → API mock container: `API_BASE_URL=http://api:3000`
### Website ↔ API Connection
The website talks to the API via `fetch()` in [`BaseApiClient`](apps/website/lib/api/base/BaseApiClient.ts:11), and it always includes cookies (`credentials: 'include'`). That means:
- The **browser** must be pointed at a host-accessible API URL via `NEXT_PUBLIC_API_BASE_URL`
- The **server** (Next.js / Node) must be pointed at a container-network API URL via `API_BASE_URL` (when running in Docker)
The single source of truth for “what base URL should I use?” is [`getWebsiteApiBaseUrl()`](apps/website/lib/config/apiBaseUrl.ts:6):
- Browser: reads `NEXT_PUBLIC_API_BASE_URL`
- Server: reads `API_BASE_URL ?? NEXT_PUBLIC_API_BASE_URL`
- In Docker/CI/test: throws if missing (no silent localhost fallback)
#### Dev Docker defaults (docker-compose.dev.yml)
- Website: `http://localhost:3000`
- API: `http://localhost:3001` (maps to container `api:3000`)
- `NEXT_PUBLIC_API_BASE_URL=http://localhost:3001` (browser → host port)
- `API_BASE_URL=http://api:3000` (website container → api container)
#### Test Docker defaults (docker-compose.test.yml)
This stack is intended for deterministic smoke tests and uses different host ports to avoid colliding with `docker:dev`:
- Website: `http://localhost:3100`
- API mock: `http://localhost:3101` (maps to container `api:3000`)
- `NEXT_PUBLIC_API_BASE_URL=http://localhost:3101` (browser → host port)
- `API_BASE_URL=http://api:3000` (website container → api container)
Important: the test stacks API is a mock server defined inline in [`docker-compose.test.yml`](docker-compose.test.yml:24). It exists to validate Website ↔ API wiring, not domain correctness.
#### Troubleshooting
- If `docker:dev` is running, use `npm run docker:dev:down` before `npm run test:docker:website` to avoid port conflicts.
- If Docker volumes get stuck, run `npm run docker:test:down` (it uses `--remove-orphans` + `rm -f`).
### API “Real vs In-Memory” Mode
The API can now be run either:
- **postgres**: loads [`DatabaseModule`](apps/api/src/domain/database/DatabaseModule.ts:1) (requires Postgres)
- **inmemory**: does not load `DatabaseModule` (no Postgres required)
Control it with:
- `GRIDPILOT_API_PERSISTENCE=postgres|inmemory` (defaults to `postgres` if `DATABASE_URL` is set, otherwise `inmemory`)
- Optional: `GRIDPILOT_API_BOOTSTRAP=0` to skip [`BootstrapModule`](apps/api/src/domain/bootstrap/BootstrapModule.ts:1)
### Development (.env.development)
Copy and customize as needed. Default values work out of the box.
### Production (.env.production)
**IMPORTANT**: Update these before deploying:
- Database credentials (POSTGRES_PASSWORD, DATABASE_URL)
- API URLs (NEXT_PUBLIC_API_URL, NEXT_PUBLIC_SITE_URL)
- Vercel KV credentials (required for production)
- Database credentials (`POSTGRES_PASSWORD`, `DATABASE_URL`)
- Website/API URLs (`NEXT_PUBLIC_API_BASE_URL`, `NEXT_PUBLIC_SITE_URL`)
- Vercel KV credentials (`KV_REST_API_URL`, `KV_REST_API_TOKEN`) (required for production email signups/rate limit)
## Architecture