Commit Graph

4 Commits

Author SHA1 Message Date
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
Matt Ciaccio
1151768159 feat(email): system/user senderType + attachments
Composer validator now takes senderType (system|user) and an
attachments[] array, and the service dispatches across two paths:
the system path uses lib/email/index.ts with port-config noreply
identity and logs signed_doc_emailed when an attachment matches a
document's signed PDF; the user path stays on the existing personal-
account flow but is gated by the new email.allowPersonalAccountSends
toggle and the attachment fileIds are persisted on email_messages.
sendEmail in lib/email accepts attachments and resolves them from
MinIO with cross-port enforcement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 02:48:11 +02:00
Matt Ciaccio
da44e8ecbe feat(documenso): version-aware field placement + void abstractions
Adds DOCUMENSO_API_VERSION env (default v1) plus per-port override.
Introduces placeFields, placeDefaultSignatureFields, and voidDocument
that hide v1 (per-field POST, pixel coords) vs v2 (bulk POST, percent +
fieldMeta) differences. cancelDocument now voids in Documenso first and
treats transient void failures as recoverable so the CRM stays the
system of record. 16 unit specs cover dispatch, layout math, idempotent
404, and v1 pixel conversion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 02:22:04 +02:00
Matt Ciaccio
4877b97f27 feat(admin): per-port email/Documenso/branding/reminder settings + invitations
All checks were successful
Build & Push Docker Images / lint (pull_request) Successful in 1m1s
Build & Push Docker Images / build-and-push (pull_request) Has been skipped
Centralizes everything operators need to configure into the admin panel,
each setting per-port with env fallback.

New admin pages
- /admin              landing page linking to every admin section as a card
- /admin/email        FROM name+address, reply-to, signature/footer HTML,
                      optional SMTP host/port/user/pass override
- /admin/documenso    API URL+key override, EOI Documenso template ID,
                      default EOI pathway (documenso-template vs inapp),
                      "Test connection" button
- /admin/branding     logo URL, primary color, app name, email
                      header/footer HTML
- /admin/reminders    port-level defaults for new interests +
                      port-wide daily-digest delivery window
- /admin/invitations  send / list / resend / revoke CRM invitations

Per-user reminder digest
- /notifications/preferences gains a Reminder digest card:
  immediate / daily / weekly / off, with HH:MM, day-of-week,
  IANA timezone fields. Stored in user_profiles.preferences.reminders.

Plumbing
- port-config.ts typed accessors (getPortEmailConfig, getPortDocumensoConfig,
  getPortBrandingConfig, getPortReminderConfig) — settings → env fallback.
- sendEmail accepts optional portId; resolves From/SMTP from settings
  when supplied.
- documensoFetch + downloadSignedPdf accept optional portId; each public
  function takes it through. checkDocumensoHealth() backs the test button.
- crm-invite.service gains listCrmInvites / revokeCrmInvite / resendCrmInvite
  with audit-log entries (revoke_invite, resend_invite added to AuditAction).
- AdminLandingPage card grid + shared SettingsFormCard component to remove
  per-page form boilerplate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:21:54 +02:00