Commit Graph

5 Commits

Author SHA1 Message Date
e469b2b6a6 fix(P1): GDPR export + Redis eviction policy
F3: BullMQ 5.x rejects custom job IDs containing `:` (collides with internal
Redis-key namespacing). GDPR export crashed with "Custom Id cannot contain :".
Switched to dash separator. GDPR Article 15 right-to-access now functional.

F4: Redis was configured with `allkeys-lru` eviction in both docker-compose.yml
and docker-compose.prod.yml. BullMQ explicitly requires `noeviction` —
otherwise queue keys can be evicted under memory pressure and jobs vanish
silently. Switched to noeviction with comment pointing at the audit finding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 22:39:16 +02:00
0ea8d94d26 fix(audit-wave-10): build-auditor fixes — CSP, server externals, healthcheck
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>
2026-05-13 12:30:22 +02:00
ad74e4a174 audit: Tier 1/3/6/7 batch — PII redaction, mobile safe-area, perf, build hardening
Tier 1.4: error_events.request_body_excerpt sanitizer now redacts
GDPR-relevant fields (email, phone, dob, address, fullName, firstName,
lastName, postcode, nationalId, etc.) on top of the existing
credential list. A 5xx in /api/v1/clients no longer lands full client
PII in the super-admin inspector.

Tier 3.10: ScanShell <main> now adds pb-[max(1.5rem, env(safe-area-
inset-bottom))]. Mobile-pwa audit caught the Save expense button sitting
flush against the iPhone 14/15 home indicator in standalone PWA mode.

Tier 6.2: dashboard widget-registry now dynamic-imports every
recharts-backed chart widget (berth status, lead source, occupancy
timeline, pipeline funnel, revenue breakdown, source conversion).
~80-150KB initial-bundle savings when reps have charts disabled.
ssr:false because recharts needs window.

Tier 6.3: DataTable wraps the assembled columns in useMemo keyed on
(columns, hasBulkActions). TanStack docs explicitly warn that
rebuilding columns every render resets the table's internal state.

Tier 7.1: Added .dockerignore (was missing — 7.6 GB context with
.env reachable via COPY . .). Excludes git, env files, node_modules,
build artefacts, IDE config, test artefacts, audit docs.

Tier 7.4: Dockerfile.dev now runs as the node user (uid 1000) — was
root. Working dir moves to /home/node/app.

Tier 7.5: docker-compose.prod.yml adds memory limits (2g postgres,
512m redis, 1g crm-app, 1g crm-worker) and json-file log rotation
(max-size, max-file) to every service.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 17:18:35 +02:00
Matt Ciaccio
6a609ecf94 fix(audit-tier-1): timeouts, lifecycle, per-port Documenso, FK constraints
Closes the second wave of HIGH-priority audit findings:

* fetchWithTimeout helper (new src/lib/fetch-with-timeout.ts) wraps
  Documenso, OCR, currency, Umami, IMAP, etc. — a hung upstream can
  no longer pin a worker concurrency slot indefinitely.  OpenAI client
  passes timeout: 30_000.  ImapFlow gets socket / greeting / connection
  timeouts.
* SIGTERM / SIGINT handler in src/server.ts drains in-flight HTTP,
  closes Socket.io, and disconnects Redis before exit; compose
  stop_grace_period bumped to 30s.  Adds closeSocketServer() helper.
* env.ts gains zod-validated PORT and MULTI_NODE_DEPLOYMENT, and
  filesystem.ts now reads from env (a typo can no longer silently
  disable the multi-node guard).
* Per-port Documenso template + recipient IDs land in system_settings
  with env fallback (PortDocumensoConfig now exposes eoiTemplateId,
  clientRecipientId, developerRecipientId, approvalRecipientId).
  document-templates.ts uses the per-port config and threads portId
  into documensoGenerateFromTemplate().
* Migration 0042 wires the eleven HIGH-tier missing FK constraints
  (documents/files/interests/reminders/berth_waiting_list/
  form_submissions) plus polymorphic CHECK round 2
  (yacht_ownership_history.owner_type, document_sends.document_kind),
  invoices.billing_entity_id NOT EMPTY, and clients.merged_into self-FK.
  Drizzle schema columns updated to .references(...) where possible
  so the misleading "FK wired in relations.ts" comments are gone.

Test status: 1168/1168 vitest, tsc clean.

Refs: docs/audit-comprehensive-2026-05-05.md HIGH §§5,6,7,8,9,10 +
MED §§14,15,16,18.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 19:52:58 +02:00
67d7e6e3d5 Initial commit: Port Nimara CRM (Layers 0-4)
Some checks failed
Build & Push Docker Images / build-and-push (push) Has been cancelled
Build & Push Docker Images / deploy (push) Has been cancelled
Build & Push Docker Images / lint (push) Has been cancelled
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00