Files
pn-new-crm/src/lib/db/migrations/meta/_journal.json

77 lines
1.5 KiB
JSON
Raw Normal View History

{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1776185027494,
"tag": "0000_narrow_longshot",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1776185487775,
"tag": "0001_soft_ender_wiggin",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1776958500747,
"tag": "0002_groovy_excalibur",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1776959610819,
"tag": "0003_opposite_lucky_pierre",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1776959707066,
"tag": "0004_nasty_warstar",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1776959832091,
"tag": "0005_stale_kronos",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1776959911400,
"tag": "0006_great_pixie",
"breakpoints": true
},
{
"idx": 7,
"version": "7",
"when": 1776959993173,
"tag": "0007_brainy_felicia_hardy",
"breakpoints": true
refactor(clients): drop deprecated yacht/company/proxy columns PR 13: now that all reads are migrated to the dedicated yacht / company / membership entities, drop the columns that mirrored them on `clients`: companyName, isProxy, proxyType, actualOwnerName, relationshipNotes, yachtName, yachtLength{Ft,M}, yachtWidth{Ft,M}, yachtDraft{Ft,M}, berthSizeDesired. Migration `0008_loud_ikaris.sql` issues the destructive ALTER TABLE DROP COLUMN statements. Run `pnpm db:push` (or the migration runner) to apply. Caller cleanup (zero behavioral change to remaining flows): - Drops the legacy `generateEoi` flow entirely (route, service function, pdfme template, validator schema). The dual-path generate-and-sign service from PR 11 has fully replaced it; the route was no longer wired to the UI. - `clients.service`: company-name search column / WHERE / audit value removed; search now ranks by full name only. - `interests.service`: `resolveLeadCategory` reads dimensions from `yachts` via `interest.yachtId` instead of the dropped `client.yachtLength{Ft,M}`. - `record-export`: client-summary now lists yachts via owner-side lookup (direct + active company memberships); interest-summary fetches yacht via `interest.yachtId`. Both PDF templates updated to read yacht details from the new entity. - `client-detail-header`, `client-picker`, `command-search`, `search-result-item`, `use-search` hook, `types/domain.ts`, `search.service` — drop the companyName badge / sub-label / typed field everywhere it was rendered or fetched. - `ai.ts` worker: drop the company / yacht context lines from the prompt (will be re-added later sourced from the new entities). - `validators/interests.ts`: remove the deprecated public-form flat yacht/company fields. The route already ignores them. - `factories.ts`: drop the `isProxy: false` default. Tests: 652/652 green; type-check clean. The `security-sensitive-data` tests use `companyName` / `isProxy` as arbitrary record keys for a generic util — left unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 13:57:54 +02:00
},
{
"idx": 8,
"version": "7",
"when": 1777204563579,
"tag": "0008_loud_ikaris",
"breakpoints": true
feat(portal): replace magic-link with email/password + admin-initiated activation The client portal no longer uses passwordless / magic-link sign-in. Each client now has a `portal_users` row with a scrypt-hashed password, created by an admin from the client detail page; the admin's invite mails an activation link that the client uses to set their own password. Forgot-password is wired through the same token mechanism. Schema (migration `0009_outgoing_rumiko_fujikawa.sql`): - `portal_users` — one per client account, separate from the CRM `users` table (better-auth) so the auth realms stay isolated. Email is globally unique, password is null until activation. - `portal_auth_tokens` — single-use activation / reset tokens. Stores only the SHA-256 hash so a DB compromise never leaks live tokens. Services: - `src/lib/portal/passwords.ts` — scrypt hash/verify (no new deps; uses node:crypto), token mint+hash helpers. - `src/lib/services/portal-auth.service.ts` — createPortalUser, resendActivation, activateAccount, signIn (timing-safe), requestPasswordReset, resetPassword. Auth failures throw the new UnauthorizedError (401); enumeration-safe behaviour everywhere. Routes: - POST /api/portal/auth/sign-in — sets the existing portal JWT cookie. - POST /api/portal/auth/forgot-password — always 200. - POST /api/portal/auth/reset-password — token + new password. - POST /api/portal/auth/activate — token + initial password. - POST /api/v1/clients/:id/portal-user — admin invite (and `?action=resend`). - Removed: /api/portal/auth/request, /api/portal/auth/verify (magic link). UI: - /portal/login — replaced email-only magic-link form with email + password + "forgot password" link. - /portal/forgot-password, /portal/reset-password, /portal/activate — new. - New shared `PasswordSetForm` component used by activate + reset. - New `PortalInviteButton` rendered on the client detail header. Email send: - `createTransporter` now wires SMTP auth when SMTP_USER+SMTP_PASS are set (gmail app-password or marina-server creds, configured via env). - `SMTP_FROM` env var lets the sender address be overridden without pinning it to `noreply@${SMTP_HOST}`. Tests: - Smoke spec 17 (client-portal) updated to the new flow: 7/7 green. - Smoke specs 02-crud-spine, 05-invoices, 20-critical-path updated to match the post-refactor client + invoice forms (drop companyName, use OwnerPicker + billingEmail). - Vitest 652/652 still green; type-check clean. Drops the dead `requestMagicLink` from portal.service.ts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 15:34:02 +02:00
},
{
"idx": 9,
"version": "7",
"when": 1777210206070,
"tag": "0009_outgoing_rumiko_fujikawa",
"breakpoints": true
}
]
}