feat(supplemental-info): pre-EOI public form flow

Lets a sales rep send a client a one-shot link to fill out the
information we need before drafting the EOI (intent, dimensions,
signatory, timeline). Token-keyed: single-use, soft-expiring, scoped
to one interest + client. Public POST endpoint accepts the form
submission; CRM endpoint mints tokens for rep-initiated requests;
portal page renders the form for the recipient.

Schema: supplemental_form_tokens table (migration 0061) with port_id
+ interest_id + client_id refs, unique token, consumed_at marker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-14 03:36:56 +02:00
parent e11529ffcc
commit 0fe3e984d1
7 changed files with 858 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
-- 0061_supplemental_form_tokens.sql
-- ----------------------------------------------------------------------------
-- Pre-EOI supplemental info form tokens. One row per public form link the
-- CRM emails to a client. Token-keyed lookups + soft expiry + one-shot
-- consumption.
CREATE TABLE IF NOT EXISTS supplemental_form_tokens (
id text PRIMARY KEY DEFAULT gen_random_uuid()::text,
port_id text NOT NULL REFERENCES ports(id),
interest_id text NOT NULL REFERENCES interests(id) ON DELETE CASCADE,
client_id text NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
token text NOT NULL UNIQUE,
created_at timestamptz NOT NULL DEFAULT now(),
expires_at timestamptz NOT NULL,
consumed_at timestamptz,
issued_by text
);
CREATE INDEX IF NOT EXISTS idx_supplemental_tokens_interest
ON supplemental_form_tokens (interest_id);
CREATE INDEX IF NOT EXISTS idx_supplemental_tokens_client
ON supplemental_form_tokens (client_id);
CREATE INDEX IF NOT EXISTS idx_supplemental_tokens_port
ON supplemental_form_tokens (port_id);