Address the highest-leverage CRITICAL/HIGH/MEDIUM items from the
build-auditor that weren't already covered by Wave 1 (EMAIL_REDIRECT_TO
production guard) or the existing `.dockerignore`.
**C3 — socket.io in standalone trace**
- Add socket.io + @socket.io/redis-adapter to serverExternalPackages
in next.config so the build system sees the dependency (the custom
server is the only importer, no Next route touches it).
- Belt-and-braces: COPY both from the deps stage into the runner stage
of Dockerfile, mirroring the audit's suggested fix.
**H1 — CSP `'unsafe-inline'` in prod**
- Audit recommends nonce-based scripts. Implementing nonces requires
middleware that emits a per-request nonce + threading it through
Next's RSC bootstrap + Server Actions. Out of scope for this wave;
documented the rationale at the CSP definition so the next pass
knows where to start, and noted that the in-the-wild XSS surfaces
are already closed via escapeHtml/escapeUrl in the email + webhook
pipelines.
**H2 — NEXT_PUBLIC_APP_URL validation**
- Add `NEXT_PUBLIC_APP_URL: z.string().url()` to the env schema so a
missing build-time value fails validation instead of silently
inlining the empty string into the client bundle and breaking
multi-origin deploys.
**M3 — serverExternalPackages completeness**
- Add imapflow, mailparser, pdf-lib, sharp, tesseract.js,
@react-pdf/renderer, unpdf — all heavy native/CJS-leaning
server-only deps that should not be route-traced.
**H5 — healthcheck PORT templatization**
- docker-compose.{,prod.}yml: replace hardcoded
`http://localhost:3000/api/health` with `${PORT:-3000}` so
overriding PORT via .env doesn't put the container into a
restart loop.
**M9 — NODE_ENV=production in builder**
- Dockerfile builder stage now sets NODE_ENV=production above
`RUN pnpm build` so the prod-only branches in next.config
(CSP, etc.) compile deterministically.
**M7 — HEALTHCHECK directive in image**
- Add image-level HEALTHCHECK to the app Dockerfile (mirrors the
one in Dockerfile.worker for Redis) so the image is
self-describing for non-compose orchestrators.
Items already addressed prior to this wave:
- C1 (.dockerignore exists, comprehensive)
- C2 (EMAIL_REDIRECT_TO production refusal — Wave 1)
- H4 (compose resource + log limits — already in prod compose)
Tests 1315/1315 throughout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
86 lines
1.9 KiB
YAML
86 lines
1.9 KiB
YAML
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
environment:
|
|
POSTGRES_DB: port_nimara_crm
|
|
POSTGRES_USER: ${DB_USER:-crm}
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
- ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/01-init.sql
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-crm} -d port_nimara_crm"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
networks:
|
|
- internal
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 256mb --maxmemory-policy allkeys-lru
|
|
volumes:
|
|
- redisdata:/data
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
networks:
|
|
- internal
|
|
|
|
crm-app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
env_file: .env
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
# Templatize port so `PORT=…` env overrides don't desync the
|
|
# healthcheck from the actual listener.
|
|
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:${PORT:-3000}/api/health"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 3
|
|
networks:
|
|
- internal
|
|
|
|
crm-worker:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile.worker
|
|
env_file: .env
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
networks:
|
|
- internal
|
|
|
|
nginx:
|
|
image: nginx:alpine
|
|
ports:
|
|
- "443:443"
|
|
- "80:80"
|
|
volumes:
|
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
- ./nginx/certs:/etc/nginx/certs:ro
|
|
depends_on:
|
|
crm-app:
|
|
condition: service_healthy
|
|
networks:
|
|
- internal
|
|
|
|
volumes:
|
|
pgdata:
|
|
redisdata:
|
|
|
|
networks:
|
|
internal:
|
|
driver: bridge
|