feat(post-audit): Phase 1.3 + 1.4 + Phase 2 signals + pulse admin
Phase 1.3 — signing-invitation role copy - Order-agnostic phrasing (was assuming client→developer→approver order; ports configure any sequence so the "client has already signed" assumption was brittle). - Explicit developer-role branch + safe default for unknown roles. Phase 1.4 — supplemental form per-port URL - New supplemental_form_url registry entry (email.from section). - Threaded through getPortEmailConfig → PortEmailConfig.supplementalFormUrl. - /api/v1/interests/[id]/supplemental-info-request resolves the link via per-port URL when set, falls back to /public/supplemental-info/<token> CRM route when blank. Phase 2 — deal-pulse signal expansion + admin config - Compute function gains: - +5 eoi_sent_recent (≤14d) — was previously invisible - +15 deposit_received — strongest near-commit signal - +10 contract_signed — closed-loop reinforcement until outcome flips - -25 document_declined — strongest cooling signal - -20 reservation_cancelled — booked-then-cancelled warning - -30 berth_sold_to_other — primary berth lost to another deal - Each signal honours optional per-port `signal_<id>_enabled` toggle. - Registry adds master toggle (pulse_enabled), per-signal toggles, and per-port label overrides (Hot/Warm/Cold rename). - New /admin/pulse page mounted via RegistryDrivenForm. - AdminSectionsBrowser entry under Configuration. Data-wiring for the 3 risk signals (declined/cancelled/sold-to-other) needs follow-up: requires either schema timestamps on interests or derivation from event tables. Master plan §B captures the gap. Tests: 1374/1374 passing. tsc clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,12 +42,19 @@ interface InvitationData {
|
||||
|
||||
function InvitationBody({ data, accent }: { data: InvitationData; accent: string }) {
|
||||
const greeting = `Dear ${data.recipientName},`;
|
||||
const isClient = (data.signerRole ?? 'client') === 'client';
|
||||
const leadCopy = isClient
|
||||
? `Your ${data.documentLabel} for ${data.portName} is ready for signing. Click the button below to review and sign — it should only take a couple of minutes.`
|
||||
: data.signerRole === 'approver'
|
||||
? `An ${data.documentLabel} is awaiting your approval. The earlier signers have completed their parts; please review and sign to finalise the document.`
|
||||
: `An ${data.documentLabel} is awaiting your signature. The client has already signed; you're the next signer in the chain.`;
|
||||
const role = data.signerRole ?? 'client';
|
||||
// §1.3 audit: role-specific copy stays order-agnostic. The original
|
||||
// copy assumed client→developer→approver order; ports can configure
|
||||
// any sequence, so generic phrasing is safer than naming the prior
|
||||
// signer.
|
||||
const leadCopy =
|
||||
role === 'client'
|
||||
? `Your ${data.documentLabel} for ${data.portName} is ready for signing. Click the button below to review and sign — it should only take a couple of minutes.`
|
||||
: role === 'approver'
|
||||
? `An ${data.documentLabel} is awaiting your approval. Please review and sign to finalise the document.`
|
||||
: role === 'developer'
|
||||
? `An ${data.documentLabel} is awaiting your signature as developer. Please review and sign when ready.`
|
||||
: `An ${data.documentLabel} is awaiting your signature. Please review and sign when ready.`;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user