chore(autonomous-session): consolidate uncommitted work from prior session

Bundles the prior autonomous-session output that was sitting unstaged:

- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
  never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
  after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
  redirects (ocr to ai, reports to dashboard, invitations to users),
  docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
  flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
  let-reassign), set-state-in-effect disables in CountryFlag and
  UploadForSigning preview-bytes effect, unused 'confirm' destructures in
  interest contract + reservation tabs, unescaped apostrophe in test-template
  card copy
This commit is contained in:
2026-05-23 00:52:59 +02:00
parent 43719b49e9
commit 221ae5784e
749 changed files with 7440 additions and 3118 deletions

View File

@@ -22,7 +22,7 @@ export const SETTING_KEYS = {
// to (typically the marketing site's hosted form). When blank, the
// built-in CRM route `/public/supplemental-info/<token>` is used.
supplementalFormUrl: 'supplemental_form_url',
// email_signature_html / email_footer_html removed; the email shell
// email_signature_html / email_footer_html - removed; the email shell
// reads branding_email_header_html / branding_email_footer_html from
// /admin/branding, which is the source of truth.
emailAllowPersonalAccountSends: 'email_allow_personal_account_sends',
@@ -42,7 +42,7 @@ export const SETTING_KEYS = {
documensoClientRecipientId: 'documenso_client_recipient_id',
documensoDeveloperRecipientId: 'documenso_developer_recipient_id',
documensoApprovalRecipientId: 'documenso_approval_recipient_id',
// Per-port Documenso webhook secret two ports pointed at different
// Per-port Documenso webhook secret - two ports pointed at different
// Documenso instances cannot share the global env secret. The receiver
// resolves the matching port by trying each enabled secret with a
// timing-safe comparison.
@@ -116,14 +116,14 @@ export const SETTING_KEYS = {
// Berths
berthsDefaultCurrency: 'berths_default_currency',
// Pipeline auto-advance per-trigger mode (auto | suggest | off).
// Pipeline auto-advance - per-trigger mode (auto | suggest | off).
// Stored as a single JSON blob keyed by trigger name so the admin UI
// edits/saves the full map atomically. Defaults applied in
// `getStageAdvanceMode` aggressive defaults match the conventional
// `getStageAdvanceMode` - aggressive defaults match the conventional
// CRM behaviour (EOI signed → reservation auto-advances).
stageAdvanceRules: 'stage_advance_rules',
// Residential partner-forwarding recipients comma-separated emails
// Residential partner-forwarding recipients - comma-separated emails
// that receive a courtesy notification on every new residential
// inquiry. Blank disables. See createResidentialInterest +
// forwardResidentialInquiryToPartner for usage.
@@ -137,7 +137,7 @@ export type StageAdvanceMode = 'auto' | 'suggest' | 'off';
/**
* Stage transitions that callers can gate through the admin's
* `stage_advance_rules` setting. Keys are the trigger names already
* used by the rules engine (`berth-rules-engine.ts`) keeping them in
* used by the rules engine (`berth-rules-engine.ts`) - keeping them in
* sync lets a single admin toggle drive both side-effects (berth status)
* and stage moves.
*/
@@ -150,7 +150,7 @@ export type StageAdvanceTrigger =
const STAGE_ADVANCE_DEFAULTS: Record<StageAdvanceTrigger, StageAdvanceMode> = {
// Sending the EOI is the moment the deal formally enters the document-
// signing pursuit phase auto-advance so the kanban tracks reality
// signing pursuit phase - auto-advance so the kanban tracks reality
// without a rep having to click.
eoi_sent: 'auto',
// EOI signed = formal commitment to proceed → advance to reservation.
@@ -303,7 +303,7 @@ export interface PortDocumensoConfig {
apiUrl: string;
apiKey: string;
apiVersion: DocumensoApiVersion;
/** Resolution provenance `port` / `global` / `env` / `default` /
/** Resolution provenance - `port` / `global` / `env` / `default` /
* `none`. Surfaces in DOCUMENSO_AUTH_FAILURE messages so a 401 in
* prod tells the operator "this came from env fallback" vs "this
* came from a per-port admin entry" without checking logs. */
@@ -338,7 +338,7 @@ export interface PortDocumensoConfig {
* upload-and-place-fields per deal instead of templates. */
contractTemplateId: number | null;
reservationTemplateId: number | null;
/** Per-port display labels for the developer + approver slots drive
/** Per-port display labels for the developer + approver slots - drive
* email subjects and signer-progress UI copy. */
developerLabel: string;
approverLabel: string;
@@ -351,7 +351,7 @@ export interface PortDocumensoConfig {
/**
* v2-only: PARALLEL (default) or SEQUENTIAL signing-order enforcement.
* `null` keeps the upstream default (PARALLEL); a non-null value gets
* passed verbatim. v1 instances ignore this see admin Documenso page.
* passed verbatim. v1 instances ignore this - see admin Documenso page.
*/
signingOrder: 'PARALLEL' | 'SEQUENTIAL' | null;
/**
@@ -468,7 +468,7 @@ export async function getPortDocumensoConfig(portId: string): Promise<PortDocume
* finds a match, then dispatches with the resolved portId.
*
* `null` portId in the returned array means "matches but no port was
* resolved" the caller falls back to the legacy global path.
* resolved" - the caller falls back to the legacy global path.
*/
export interface DocumensoSecretEntry {
portId: string | null;
@@ -503,7 +503,7 @@ export async function listDocumensoWebhookSecrets(): Promise<DocumensoSecretEntr
try {
secret = decrypt(JSON.stringify(row.value));
} catch {
// Decryption failure (corrupt envelope, key mismatch) skip the
// Decryption failure (corrupt envelope, key mismatch) - skip the
// entry so a stale row doesn't crash the entire receiver loop.
secret = null;
}