Add yacht list + create routes, export RouteHandler type and inner
handlers so tests can invoke them directly with a mock AuthContext.
New tests/helpers/route-tester.ts provides makeMockCtx/makeMockRequest
reusable by subsequent Task 3.x routes.
Adds the berth_reservations service covering the full lifecycle
(pending -> active -> ended/cancelled) with tenant scoping, DB-enforced
exclusivity on the idx_br_active partial unique index, and
client-or-company-member cross-checks for yacht ownership.
- validators: createPending / activate / end / cancel / list schemas
- service: createPending, activate, endReservation, cancel, getById,
listReservations — with narrow 23505/idx_br_active catch that
re-queries the conflicting active reservation
- socket events: berth_reservation:{created,activated,ended,cancelled}
- tests: unit (lifecycle, tenant, membership cross-check),
integration (concurrent-activate ConflictError + re-activate after end)
Adds company-membership service with six operations (add, update, end,
setPrimary, listByCompany, listByClient), the corresponding Zod
validators, three socket events, and a unit-test suite covering the
portId-scoping rules, the unique_cm_exact conflict path, and the atomic
setPrimary transaction.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds `listYachts`, `listYachtsForOwner`, and `autocomplete` to the
yacht service so UIs can page/filter yachts per port, look up all
yachts tied to a given client/company, and power search-as-you-type.
`listYachts` delegates to the shared port-scoped `buildListQuery`,
supporting search over name/hullNumber/registration plus ownerType,
ownerId and status filters; `autocomplete` caps at 10 results and is
tenant-scoped; `listYachtsForOwner` returns all yachts whose current
owner matches, newest first. Extends `makeYacht` factory to accept
flat `name`, `status`, `hullNumber`, `registration` overrides.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds integration test covering:
- idx_yoh_active: only one active ownership row per yacht
- idx_br_active: only one active reservation per berth (non-active rows
are ignored by the partial index)
- Case-insensitive company name uniqueness within a port, with same-name
companies allowed across different ports
Extends tests/helpers/factories.ts with async DB-inserting factories for
ports, clients, berths, yachts (+ ownership history row) and companies.
The new factories use the app's `db` handle so FK and partial unique
indexes are enforced by Postgres. The in-memory data helpers used by
unit tests (makeAuditMeta, makeCreateClientInput, permission helpers)
are preserved.
Introduces yachts and companies as first-class entities with memberships,
ownership history, berth reservations, and dual-path EOI templates.
Explicit non-goals (importer, merge endpoint) carved out as Specs 2 and 3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Failures were mostly stale selectors, not product regressions:
- .or() traps matching the topbar "+ New" button → use specific names
(Add Webhook, New Field, New Template)
- broad /create|add|new/ patterns → same fix
- [role="dialog"] overlay matched before content → getByRole('dialog').last()
- locator('input') picked hidden Radix Select inputs → getByPlaceholder /
getByRole('combobox', { name })
- 11-global-search rewritten for the inline topbar search (the cmdk
CommandDialog the old tests targeted was replaced)
- missing .first() causing strict-mode failures on notifications heading,
version history text, nav links
- dashboard landing test: no h1 exists, target KPI text instead
- activity-feed: items aren't anchors; match action badge text
- monitoring data-leak check scoped to <main> (sidebar has Email/Documents)
- admin API without port context returns 400 (not 403) for non-admins —
accept 400 as a valid "blocked" status in the sales-agent test
Also dropped dead imports and unused locals surfaced by lint-staged.
Full suite: 124 passed (11.2m).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The portal has its own JWT-based auth (withPortalAuth). The CRM
middleware was redirecting /portal/login and /api/portal/auth/request
to /login, breaking the magic-link flow for unauthenticated clients.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a 'Since 2026-03-26' section summarizing the admin/reminders
expansion, multi-address clients, full inquiry notifications feature,
and Next.js 15 build fixes. Updates the Layer 3 reminders entry to
reflect full CRUD + background processors. Marks Priority 1 push-to-
Gitea as done and splits out CI verification as its own checkbox.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The override file is a local-only port remap for when the default
dev postgres port is already bound by another project. .remember/ is
skill-maintained session-state storage.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Next.js 15 static prerender bails out when useSearchParams is used
outside a Suspense boundary. Extract the hook-using component into
an inner child and wrap it in Suspense at the page root.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Prevents cross-platform CRLF/LF churn between Windows and macOS checkouts.
Windows-only scripts (bat/cmd/ps1) pinned to CRLF; shell scripts pinned to LF.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers migrating ActivePieces inquiry flow into the CRM:
client confirmation emails, sales team notifications,
client addresses table, and admin configuration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Port CRUD: list, create, update with branding, currency, timezone
- System settings: upsert key-value pairs per port with known settings UI
(AI feature flags, invoice discount, pipeline weights, berth rules)
- Settings manager with toggle switches, number inputs, and JSON editors
- Replace both stub pages with real implementations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add user CRUD: list, create (via Better Auth), update role/status, remove from port
- Add role CRUD: create, update permissions, delete with system role protection
- Full permissions matrix UI with accordion groups and per-action checkboxes
- Validators, services, API routes, and UI components following existing patterns
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add SKIP_ENV_VALIDATION to bypass Zod env check during next build
- Bundle custom server.ts with esbuild so production uses Socket.io
- Create worker entry point (src/worker.ts) with all BullMQ workers
- Add esbuild build scripts for server and worker bundles
- Fix Dockerfile.worker to include its own build stage
- Fix pre-commit hook to work without global pnpm
- Add CLAUDE.md with project conventions and quick reference
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>