# Vessel Ownership Transfer — mock implementation notes (for API integration)

Portal (owner-facing) + Backoffice (officer-facing) built as **mock UI only**, matching each app's existing mock-driven review-workflow convention. No backend calls anywhere. This doc exists to make wiring the real API fast — it says exactly what to replace and where.

## What exists

### Portal (`apps/portal/src/app/features/vessel-transfer/`)
- `mock.ts` — types + `MOCK_VESSELS`, `MOCK_REQUESTS`, `addTransferRequest()`
- `pages/VesselTransferPage.tsx` — list/status view (`/vessel-transfers`)
- `pages/VesselTransferApplicationPage.tsx` — 4-step submit wizard (`/vessel-transfers/apply`)

### Backoffice (`apps/backoffice/src/app/features/vessel-transfer/`)
- `pages/VesselTransferQueuePage.tsx` — types + `MOCK_REQUESTS`, queue table, stats, quick-view drawer (`/vessel-transfers`)
- `pages/VesselTransferReviewPage.tsx` — full review, approve/reject, doc view/download (`/vessel-transfers/:id`)

Each app defines its **own separate mock array** (codebase convention: no shared domain types in `libs/`). They are not the same objects and don't sync — submitting in portal does not appear in the backoffice queue, and vice versa. That's the main thing a real API fixes.

## Data shape mismatch to resolve

Portal's `TransferRequest.currentOwner` / `newOwnerName` are plain strings. Backoffice's `TransferRequest.currentOwner` / `newOwner` are full objects (`{ name, idOrTin, phone, email, address }`). The real API should standardize on the **backoffice shape** — it's the superset the officer review page needs.

**Known gap:** `VesselTransferApplicationPage.tsx`'s wizard collects `newOwnerIdOrTin`, `newOwnerPhone`, `newOwnerEmail`, `newOwnerAddress` and shows them in the review step, but `addTransferRequest()` only persists `newOwnerName` — the rest are captured in UI state and silently dropped on submit. When wiring the real POST, send all of them (the fields already exist in component state, just not in the payload today).

## Suggested API surface

- `GET /vessels?ownerId=:id&status=approved` — portal wizard's vessel `<Select>` (replaces `MOCK_VESSELS.filter(v => v.approved)` in `VesselTransferApplicationPage.tsx`).
- `POST /vessel-transfers` — submit. Body: `vesselId, newOwner: {name, idOrTin, phone, email, address}, reason, document (file upload)`. Replaces `addTransferRequest()` in portal's `mock.ts`.
- `GET /vessel-transfers?ownerId=:id` — portal's "My Transfer Requests" list (`VesselTransferPage.tsx`).
- `GET /vessel-transfers` (officer, all + filters) — backoffice queue (`VesselTransferQueuePage.tsx`); search/status-filter can move server-side or stay client-side over the fetched page.
- `GET /vessel-transfers/:id` — backoffice review page and portal status detail both key off this.
- `PATCH /vessel-transfers/:id` — officer action. Body: `{ status: 'Under Review' | 'Approved' | 'Rejected', remarks? }`. Replaces the in-place `record.status = ...` mutation in `VesselTransferReviewPage.tsx`. Backend should enforce remarks-required-on-Rejected (UI already gates this, but don't trust client-only validation).
- Document storage: real upload + signed URL for View, and a real download endpoint — today `getDocUrl()` in both `CoCReviewPage`-style `DocViewer`s and this feature's `VesselTransferReviewPage.tsx` fake it with a hardcoded base64 PDF / placehold.co image.
- SMS/email: triggered server-side on submit and on every status change — UI currently just shows a toast claiming this happened (`notify.success('... SMS and email ...')`); no actual send anywhere.

## Where to swap mock for real calls

- Portal: `apps/portal/src/app/features/vessel-transfer/mock.ts` (whole file), plus the `useState`/local reads of `MOCK_VESSELS`/`MOCK_REQUESTS` in both page files.
- Backoffice: the exported `MOCK_REQUESTS`/types block at the top of `VesselTransferQueuePage.tsx`, plus the direct `record.status = ...` mutation in `VesselTransferReviewPage.tsx` (swap for a mutation call + refetch/cache-invalidate).
- Both apps already have an RTK Query base (`@ema-platform/api` → `baseApi.injectEndpoints`, see `apps/portal/.../payment/api/payment-api.ts` or `apps/backoffice/.../certification/api/certification-api.ts`) — follow that pattern rather than the ad-hoc `useApiQuery`/`useApiMutation` escape hatch.
