diff --git a/src/app/api/auth/[...all]/route.ts b/src/app/api/auth/[...all]/route.ts index b79e685..1c1ac22 100644 --- a/src/app/api/auth/[...all]/route.ts +++ b/src/app/api/auth/[...all]/route.ts @@ -50,12 +50,17 @@ function logSignIn(args: { const email = parsed?.user?.email ?? parsed?.email ?? args.attemptedEmail ?? null; const ok = args.status >= 200 && args.status < 300; + // entityId is text/unbounded but indexed; truncate the attempted- + // email fallback to keep the row predictably sized when the form + // sends a giant value. The audit metadata still carries the full + // original attempted email for forensic context. + const safeAttempted = (args.attemptedEmail ?? '').slice(0, 256); void createAuditLog({ userId, portId: null, action: 'login', entityType: 'session', - entityId: userId ?? args.attemptedEmail ?? 'unknown', + entityId: userId ?? safeAttempted ?? 'unknown', metadata: { ok, status: args.status, diff --git a/src/lib/db/seed-data.ts b/src/lib/db/seed-data.ts index 097625c..217acf4 100644 --- a/src/lib/db/seed-data.ts +++ b/src/lib/db/seed-data.ts @@ -39,6 +39,7 @@ import { berths, berthReservations, interests, + interestBerths, documentTemplates, } from './schema'; import { @@ -966,20 +967,43 @@ export async function seedPortData(portId: string, portSlug: string): Promise ({ - portId, - clientId: clientIds[p.clientIdx]!, - berthId: p.berthIdx !== null ? berthRows[p.berthIdx]!.id : null, - yachtId: p.yachtIdx !== null ? yachtRows[p.yachtIdx]!.id : null, - pipelineStage: p.pipelineStage, - leadCategory: p.leadCategory, - source: p.source, - dateFirstContact: daysAgo(p.daysAgoFirst), - dateLastContact: daysAgo(Math.max(0, p.daysAgoFirst - 2)), - archivedAt: p.archived ? daysAgo(p.daysAgoFirst - 30) : null, - })), - ); + // Insert interests WITHOUT berthId (column was dropped in + // migration 0029); berth links go through the interest_berths + // junction below. Returning the rows so we can wire up the + // junction with the right interestId per row. + const insertedInterests = await tx + .insert(interests) + .values( + interestPlan.map((p) => ({ + portId, + clientId: clientIds[p.clientIdx]!, + yachtId: p.yachtIdx !== null ? yachtRows[p.yachtIdx]!.id : null, + pipelineStage: p.pipelineStage, + leadCategory: p.leadCategory, + source: p.source, + dateFirstContact: daysAgo(p.daysAgoFirst), + dateLastContact: daysAgo(Math.max(0, p.daysAgoFirst - 2)), + archivedAt: p.archived ? daysAgo(p.daysAgoFirst - 30) : null, + })), + ) + .returning({ id: interests.id }); + + const junctionRows: Array = []; + interestPlan.forEach((p, i) => { + if (p.berthIdx === null) return; + const interestId = insertedInterests[i]?.id; + if (!interestId) return; + junctionRows.push({ + interestId, + berthId: berthRows[p.berthIdx]!.id, + isPrimary: true, + isSpecificInterest: true, + isInEoiBundle: false, + }); + }); + if (junctionRows.length > 0) { + await tx.insert(interestBerths).values(junctionRows); + } // ── 8. Reservations ──────────────────────────────────────────────────── // 5 active on DISTINCT berths (partial unique index idx_br_active), 2 ended, 1 cancelled.