Matt 7d33e73eef feat(berths): manual status catch-up wizard + reconciliation queue (#67)
Wires the long-dormant berths.status_override_mode column into a closed
loop so reps can reconcile berths flipped to under_offer/sold without a
backing interest.

Phase 1 — Status source tracking:
  - updateBerthStatus() stamps 'manual' on every user-facing write
  - berth-rules-engine.ts stamps 'automated' on auto-rule writes
  - new clearBerthOverride() helper nulls the field and stamps the
    reason "Reconciled via interest <id>" — only the wizard calls it

Phase 2 — Visual indicator:
  - Amber "Manual" chip on berth-list rows where statusOverrideMode='manual'
    AND no active linked interest (the candidates for catch-up)

Phase 3 — Reconciliation queue:
  - new service listManualReconcileBerths() with cross-port-safe
    NOT-EXISTS against activeInterestsWhere
  - GET /api/v1/berths/reconcile-queue
  - new page /[portSlug]/admin/berths/reconcile listing the queue,
    each row linking to the catch-up wizard

Phase 4 — Catch-up wizard:
  - POST /api/v1/berths/[id]/reconcile orchestrates create-client
    (optional quick-create), create-interest with primary berth link,
    and clearBerthOverride — composed via existing service helpers
  - <CatchUpWizard> dialog: existing-client or quick-create, optional
    yacht link, stage picker scoped to the current berth status, with
    contract auto-setting outcome=won

Phase 5 — Entry points:
  - sidebar Admin > "Reconcile berths" link
  - berth-list row action menu shows "Catch up…" on flagged rows

Doc upload + payment recording (spec phases 4.4 / 4.5) are deferred —
once the interest exists, the rep uses the standard interest detail
page surfaces for those follow-ups. The wizard's MVP responsibility is
to take a manual berth to "interest exists, override cleared" in one
round-trip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 23:55:22 +02:00
Description
No description provided
25 MiB
Languages
TypeScript 98.7%
HTML 1%
CSS 0.1%
Shell 0.1%