feat(post-audit): Phase 4 polish + Phase 2 wiring + Phase 6 cron + CLAUDE.md
Three of the master plan's "suggested execution order" items shipped this session; Phase 3b (EOI dialog overrides) deferred — estimate exceeded the remaining session time. - Phase 4 polish: yachtId field on <ReminderForm> via the existing YachtPicker, Ship-icon subtitle on <ReminderCard>, listReminders filter by yachtId, getReminder joins the yacht relation. - Phase 2 risk-signal data wiring: getInterestById derives the 3 dates (dateDocumentDeclined / dateReservationCancelled / dateBerthSoldToOther) from document_events / berth_reservations / cross-interest interest_berths in parallel — chosen over new schema columns to keep the master plan's "no new tables" promise. Threaded through to DealPulseChip. - Phase 6 cron + UI: src/jobs/processors/imap-bounce-poller.ts polls the configured IMAP mailbox (IMAP_* env), matches NDRs to recent document_sends rows via recipient + 7-day window, idempotent via bounceDetectedAt, fires email_bounced notifications on hard/soft (skips OOO). State persisted to system_settings.bounce_poller_state. Wired into maintenance queue at */15 * * * *. Admin /admin/sends page surfaces the bounce badge + reason inline. - CLAUDE.md: trimmed 27KB → ~19.5KB (~28% smaller bytes). Prose-heavy Documenso webhook / v1-v2 routing / Document folders sections rewritten as scannable bullets. Added a new "Working in this repo — skills, MCPs, agents" section promoting brainstorming/TDD/debugging/frontend-design skills, Context7/Playwright/Serena MCPs, and the Explore/feature-dev agents. Documented Phase 2 derivation choice in the data-model section. Quality gates: 1374/1374 vitest pass, tsc --noEmit clean, lint 0 errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ export async function listReminders(portId: string, query: ReminderListQuery) {
|
||||
if (query.clientId) conditions.push(eq(reminders.clientId, query.clientId));
|
||||
if (query.interestId) conditions.push(eq(reminders.interestId, query.interestId));
|
||||
if (query.berthId) conditions.push(eq(reminders.berthId, query.berthId));
|
||||
if (query.yachtId) conditions.push(eq(reminders.yachtId, query.yachtId));
|
||||
if (query.dueBefore) conditions.push(lte(reminders.dueAt, new Date(query.dueBefore)));
|
||||
if (query.dueAfter) conditions.push(gte(reminders.dueAt, new Date(query.dueAfter)));
|
||||
|
||||
@@ -173,7 +174,7 @@ async function assertReminderFksInPort(
|
||||
export async function getReminder(id: string, portId: string) {
|
||||
const reminder = await db.query.reminders.findFirst({
|
||||
where: and(eq(reminders.id, id), eq(reminders.portId, portId)),
|
||||
with: { client: true, interest: true, berth: true },
|
||||
with: { client: true, interest: true, berth: true, yacht: true },
|
||||
});
|
||||
if (!reminder) throw new NotFoundError('Reminder');
|
||||
return reminder;
|
||||
|
||||
Reference in New Issue
Block a user