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 @@
/**
* External EOI upload for EOIs signed outside Documenso (paper signing,
* External EOI upload - for EOIs signed outside Documenso (paper signing,
* different e-sign vendor, signed in person, etc).
*
* Creates BOTH the document row AND the signed-file record in one shot,
@@ -40,7 +40,7 @@ export interface ExternalEoiInput {
/** When the signing actually happened (the date on the paper / contract). */
signedAt?: Date;
/**
* Structured signatory list preferred over the legacy `signerNames`
* Structured signatory list - preferred over the legacy `signerNames`
* CSV. When present, the service inserts one `document_signers` row
* per non-CC entry pre-stamped `status='signed'` so the
* "X / Y signed" badge renders correctly downstream.
@@ -82,7 +82,7 @@ export async function uploadExternallySignedEoi(input: ExternalEoiInput) {
// Upload to storage FIRST so we have a stable key for the DB rows,
// then commit all four DB writes in one transaction. If the tx fails
// the storage object becomes orphaned (S3 isn't transactional) but
// the DB stays clean orphan reaper handles those.
// the DB stays clean - orphan reaper handles those.
await (
await getStorageBackend()
).put(storagePath, fileData.buffer, {
@@ -91,7 +91,7 @@ export async function uploadExternallySignedEoi(input: ExternalEoiInput) {
});
const title =
input.title ?? `External EOI ${(input.signedAt ?? new Date()).toISOString().slice(0, 10)}`;
input.title ?? `External EOI - ${(input.signedAt ?? new Date()).toISOString().slice(0, 10)}`;
const result = await db.transaction(async (tx) => {
const [fileRecord] = await tx
@@ -140,7 +140,7 @@ export async function uploadExternallySignedEoi(input: ExternalEoiInput) {
// Backfill document_signers rows for the structured signatory list
// so the document-detail "X / Y signed" badge counts correctly. CC
// recipients aren't signatories they're recipients of the email
// recipients aren't signatories - they're recipients of the email
// copy and don't show up in the signed-count denominator.
const signedAtMoment = input.signedAt ?? new Date();
const signerRows = (input.signatories ?? [])
@@ -172,15 +172,15 @@ export async function uploadExternallySignedEoi(input: ExternalEoiInput) {
});
// Two concerns to keep separate:
// 1. Document metadata always write `dateEoiSigned` + `eoiStatus`
// 1. Document metadata - always write `dateEoiSigned` + `eoiStatus`
// from the upload. Even if the rep already advanced the stage
// manually, the paper signing event needs a recorded date so
// downstream surfaces (SkipAheadBanner, milestone strip, EOI
// merge fields) reflect reality. Honour an existing
// dateEoiSigned (don't overwrite if already set covers the
// dateEoiSigned (don't overwrite if already set - covers the
// case where the rep is uploading evidence for an event whose
// date was already backfilled).
// 2. Stage advance only when the deal hasn't reached eoi_signed
// 2. Stage advance - only when the deal hasn't reached eoi_signed
// yet. Bypasses canTransitionStage because the operator just
// brought concrete proof.
const shouldAdvanceStage =
@@ -238,7 +238,7 @@ export async function uploadExternallySignedEoi(input: ExternalEoiInput) {
const { evaluateRule } = await import('@/lib/services/berth-rules-engine');
await evaluateRule('eoi_signed', interestId, portId, meta);
} catch {
// Swallow rules engine failures should never block the upload
// Swallow - rules engine failures should never block the upload
// that the rep has already completed end-to-end. The orphan-reaper
// path doesn't apply; a missed rule evaluation is a soft failure.
}
@@ -280,7 +280,7 @@ export interface ExternalEoiMetadataPatch {
/**
* Update title / notes / signed-date / signatories on a previously-uploaded
* external EOI. Refuses to touch Documenso-managed documents because their
* signer rows are the vendor's source of truth any edit would drift from
* signer rows are the vendor's source of truth - any edit would drift from
* the upstream envelope.
*
* Mirrors the upload service's invariants:
@@ -290,7 +290,7 @@ export interface ExternalEoiMetadataPatch {
* present (insert / update / delete by id-presence). Same shape as the
* upload-time insert: CC entries persisted but not counted as signers.
*
* Stage advance is NOT re-evaluated that fires once at upload and shouldn't
* Stage advance is NOT re-evaluated - that fires once at upload and shouldn't
* be reversed by a metadata edit. If the rep needs to roll a stage back,
* they do it through the stage-change UI directly.
*/