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

@@ -1,5 +1,5 @@
/**
* Per-port sales-email configuration (Phase 7 see plan §4.9).
* Per-port sales-email configuration (Phase 7 - see plan §4.9).
*
* Distinct from {@link getPortEmailConfig} (`port-config.ts`) which resolves
* the **noreply** account used by automated/system emails. The sales account
@@ -13,7 +13,7 @@
*
* SECURITY (§14.10): SMTP/IMAP passwords are encrypted at rest using the
* existing `EMAIL_CREDENTIAL_KEY` symmetric key. Reps cannot read the
* decrypted value via the API only `manage_settings` admins can write,
* decrypted value via the API - only `manage_settings` admins can write,
* and even they only ever see a placeholder mask on read (see the admin
* route handler).
*/
@@ -85,7 +85,7 @@ const DEFAULT_BERTH_PDF_BODY = [
'',
'Please find attached the spec sheet for berth {{berth.mooringNumber}} at {{port.name}}.',
'',
'Happy to set up a call to walk through the details let me know what works.',
'Happy to set up a call to walk through the details - let me know what works.',
'',
'Best,',
].join('\n');
@@ -148,7 +148,7 @@ export async function getSalesEmailConfig(portId: string): Promise<SalesEmailCon
authMethod: authMethod ?? 'app_password',
// "Usable" means we have host + (user, pass) pair OR host + no auth
// (some test/local SMTP doesn't auth). For prod-realistic, we require
// creds empty creds means we'll just bounce against the relay.
// creds - empty creds means we'll just bounce against the relay.
isUsable: Boolean(
(smtpHost ?? env.SMTP_HOST) && ((smtpUser && smtpPass) ?? (env.SMTP_USER && env.SMTP_PASS)),
),
@@ -344,7 +344,7 @@ export async function createSalesTransporter(portId: string): Promise<{
}
/**
* Public-facing sanitizer strips encrypted fields and replaces password
* Public-facing sanitizer - strips encrypted fields and replaces password
* fields with a boolean `isSet` marker. Used by the admin GET endpoint so
* reps with `manage_settings` can see whether creds are configured without
* the API ever returning the ciphertext (much less plaintext).
@@ -358,7 +358,7 @@ export function redactSalesConfigForResponse(
imap: Omit<SalesImapConfig, 'imapPass'> & { imapPassIsSet: boolean };
content: SalesContentConfig;
} {
// Spread without the password fields never reflect the decrypted value
// Spread without the password fields - never reflect the decrypted value
// (or its ciphertext) back to the API surface.
const email = {
fromAddress: cfg.fromAddress,