Initial commit: Port Nimara CRM (Layers 0-4)
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
|
|
|
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
|
|
|
|
|
restart: unless-stopped
|
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
|
|
|
# build-auditor HIGH: bound memory + log rotation so a stuck query or
|
|
|
|
|
# noisy log doesn't fill the host disk. Postgres respects shared
|
|
|
|
|
# buffers env via init.sql; the hard limit here is the container
|
|
|
|
|
# ceiling.
|
|
|
|
|
deploy:
|
|
|
|
|
resources:
|
|
|
|
|
limits:
|
|
|
|
|
memory: 2g
|
|
|
|
|
logging:
|
|
|
|
|
driver: json-file
|
|
|
|
|
options:
|
|
|
|
|
max-size: "20m"
|
|
|
|
|
max-file: "5"
|
Initial commit: Port Nimara CRM (Layers 0-4)
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
|
|
|
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
|
|
|
|
|
restart: unless-stopped
|
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
|
|
|
deploy:
|
|
|
|
|
resources:
|
|
|
|
|
limits:
|
|
|
|
|
memory: 512m
|
|
|
|
|
logging:
|
|
|
|
|
driver: json-file
|
|
|
|
|
options:
|
|
|
|
|
max-size: "10m"
|
|
|
|
|
max-file: "3"
|
Initial commit: Port Nimara CRM (Layers 0-4)
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
|
|
|
networks:
|
|
|
|
|
- internal
|
|
|
|
|
|
|
|
|
|
crm-app:
|
|
|
|
|
image: code.letsbe.solutions/letsbe/pn-new-crm/crm-app:latest
|
|
|
|
|
env_file: .env
|
|
|
|
|
ports:
|
|
|
|
|
- "7100:3000"
|
|
|
|
|
depends_on:
|
|
|
|
|
postgres:
|
|
|
|
|
condition: service_healthy
|
|
|
|
|
redis:
|
|
|
|
|
condition: service_healthy
|
|
|
|
|
healthcheck:
|
|
|
|
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
|
|
|
|
|
interval: 15s
|
|
|
|
|
timeout: 5s
|
|
|
|
|
retries: 3
|
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
|
|
|
# Give the SIGTERM handler in src/server.ts time to drain in-flight
|
|
|
|
|
# HTTP requests, close Socket.io, and disconnect Redis before Docker
|
|
|
|
|
# SIGKILLs the process. The internal hard timeout is 25s.
|
|
|
|
|
stop_grace_period: 30s
|
Initial commit: Port Nimara CRM (Layers 0-4)
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
|
|
|
restart: unless-stopped
|
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
|
|
|
deploy:
|
|
|
|
|
resources:
|
|
|
|
|
limits:
|
|
|
|
|
memory: 1g
|
|
|
|
|
logging:
|
|
|
|
|
driver: json-file
|
|
|
|
|
options:
|
|
|
|
|
max-size: "20m"
|
|
|
|
|
max-file: "5"
|
Initial commit: Port Nimara CRM (Layers 0-4)
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
|
|
|
networks:
|
|
|
|
|
- internal
|
|
|
|
|
|
|
|
|
|
crm-worker:
|
|
|
|
|
image: code.letsbe.solutions/letsbe/pn-new-crm/crm-worker:latest
|
|
|
|
|
env_file: .env
|
|
|
|
|
depends_on:
|
|
|
|
|
postgres:
|
|
|
|
|
condition: service_healthy
|
|
|
|
|
redis:
|
|
|
|
|
condition: service_healthy
|
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
|
|
|
# Match the app: BullMQ jobs need time to finish or be released back
|
|
|
|
|
# to the queue when worker.ts handles SIGTERM.
|
|
|
|
|
stop_grace_period: 30s
|
Initial commit: Port Nimara CRM (Layers 0-4)
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
|
|
|
restart: unless-stopped
|
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
|
|
|
deploy:
|
|
|
|
|
resources:
|
|
|
|
|
limits:
|
|
|
|
|
memory: 1g
|
|
|
|
|
logging:
|
|
|
|
|
driver: json-file
|
|
|
|
|
options:
|
|
|
|
|
max-size: "20m"
|
|
|
|
|
max-file: "5"
|
Initial commit: Port Nimara CRM (Layers 0-4)
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
|
|
|
networks:
|
|
|
|
|
- internal
|
|
|
|
|
|
|
|
|
|
volumes:
|
|
|
|
|
pgdata:
|
|
|
|
|
redisdata:
|
|
|
|
|
|
|
|
|
|
networks:
|
|
|
|
|
internal:
|
|
|
|
|
driver: bridge
|