Yachts list page rendered each row's Current Owner via OwnerLink, which
fired its own /api/v1/clients/{id} or /companies/{id} fetch — N+1 round-
trips per page load (12+ for the harbor-royale fixture). Worse, until
those fetches resolved each cell showed "Client c68da7..." style raw IDs.
Fix: listYachts now resolves the polymorphic currentOwnerName in two
batched in-array queries after the page query (mirrors the listClients
yachtCount/companyCount pattern), and OwnerLink accepts an optional
preloadedName prop that suppresses the per-row fetch when supplied.
Topbar: show real user name + avatar initial from session/profile, and
expand the My-Account dropdown header to include the user's email.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the Task 5.3 stub with a real YachtTransferDialog backed by
OwnerPicker, a date input, reason select, and notes textarea. Submits to
POST /api/v1/yachts/{id}/transfer, invalidates yacht + ownership-history
queries on success, and surfaces API errors (same-owner 400, cross-tenant
404, no-permission 403) as form-level messages. Transfer button is now
gated by PermissionGate resource="yachts" action="transfer".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements Task 5.3: server page passes yachtId to a client YachtDetail,
which fetches via TanStack Query and renders the shared DetailLayout with
Overview / Ownership History / Interests / Reservations / Notes / Tags
tabs. Header shows name, dimensions, polymorphic owner link, status badge,
and Edit / Transfer / Archive actions. Transfer is a stub dialog pending
Task 5.5; Notes tab is a placeholder because NotesList does not yet support
entityType='yachts'.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>