Files
marketplaces/docs/backend/FRONTEND-API-SURFACE-COMPLETE.md

394 lines
28 KiB
Markdown
Raw Normal View History

# Complete Frontend API Surface — Master Endpoint List
docs: add §0 - auth + payment authorization was missing entirely Direct question caught a real gap: "everything is there? payment auth?" The census only grepped src/app/ - auth moved into the external @marketplaces/auth package this session, and its HTTP calls were never captured. Seven real endpoints were silently absent from a doc that called itself "complete": - 3 Telegram QR/session endpoints (POST/GET/DELETE .../users/sessions) - live today, customer and admin login share them, which is exactly why every admin endpoint must independently verify authorization server-side - 4 ed25519 admin challenge/response endpoints - specified in BACKEND-HANDOFF.md §3 and the package's own auth-api.model.ts, but not built server-side. Client shows backend-unavailable until they exist. Added §0.3 stating plainly what actually connects auth to payment: there is no separate payment login. Checkout, order pricing (§20), and partner credentials (§16) each ride on whichever of the two sessions above is active, or on the partner API's own separate signed-request auth (§6 of that contract - unrelated to Telegram/ed25519, already built, not a gap). The real payment gap is §1 (QR/card creation and polling, undocumented anywhere), not auth. Counts corrected: 51->54 specified, 90->97 total. Added item 0 to the action list, ahead of everything else: the ed25519 endpoints are the single most serious open issue named anywhere in docs/backend/, and every other item on the list assumes a working admin session to authorize against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:12:22 +04:00
Generated 2026-08-18, updated same day after the frontend backlog (F1F65) closed, updated again same day to add §0 after a direct question ("everything is there? payment auth?") caught that the first pass only grepped `src/app/` — auth moved into the external `@marketplaces/auth` package this session, and its own HTTP calls (§0) were missing from what this doc called "complete." Fixed by grepping `node_modules/@marketplaces/auth/dist/` directly. Directly from source (every `this.http.get/post/patch/put/delete` call across `src/app/core/`, `src/app/features/admin/`, `src/app/services/api.service.ts`, and now the auth package). This is not a design document — it is a **census**: every endpoint this codebase currently calls or will call once its gateway swap goes live, in one place, cross-referenced against the contracts that already exist.
docs: final backend handoff - revision endpoints, response-shape additions, close-out Updates FRONTEND-API-SURFACE-COMPLETE.md to cover everything built after it was first generated - this is the final version for this pass, not a snapshot mid-way through. Added, none of which existed in the doc before: - §18: the 4 marketplace revision endpoints (create draft/validate/ publish/rollback) - built this session, missing from the census entirely. Flags the same draft/validated/preview/published ambiguity already documented in the model itself, so backend sees it without having to read source. - §19: RoutingContext as an optional field addition on GET /api/admin/v2/orders/{id} - not a new endpoint, a response-shape ask. - §20: order pricing-breakdown fields (unitPriceMinor, lineTotalMinor, priceSnapshotId, discountMinor, fxQuoteId, deliveryMinor) feeding the new total-formula panel. States plainly that the panel shows nothing rather than a wrong number while these are absent. - §21: 8 optional dashboard-metrics fields (GMV, conversion, moderation queue, etc.) - explicitly labelled a genuine ask, not a confirmed contract, since no spec exists for this endpoint at all (§15). - §22: states directly that the frontend's new double-click guard does not replace backend idempotency enforcement and was never meant to - closes one UI race, does nothing for a retried request or a duplicate webhook. Counts updated (47->51 specified, 86->90 total; +3 response-shape asks that aren't new endpoints). Closing section states the one item genuinely blocked pending a live backend (F60, the full acceptance-path E2E) so nobody mistakes "frontend backlog complete" for "nothing left to build." Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:08:41 +04:00
**This is the final handoff doc for this pass.** Frontend work is done except one item that genuinely cannot be finished without a live backend (§19). Everything else — every gateway, every model, every invariant — is written, tested, and pushed. What follows is everything backend needs to make it real.
**Why this exists.** The individual Phase/Track contracts in this directory each cover one domain well. Nothing until now listed the *entire* surface in one pass, so a backend dev building against these docs had no way to see what's fully specified, what's inferred-and-needs-confirmation, and what has no contract at all. This closes that gap.
**Status legend**
| Status | Meaning |
|---|---|
| ✅ Specified | Exact shape exists in a Phase/Track contract doc. Build as written. |
| ⚠️ Inferred | Endpoint follows this codebase's own REST conventions (path pattern, verb) but no contract doc states it explicitly. Flagged in source with a comment at the call site. **Confirm or correct before building — do not treat as final.** |
| ❌ Undocumented | Legacy endpoint, no contract anywhere, still called by `api.service.ts`. Will be replaced when the corresponding `/api/v2` migration lands (Track N) — do not invest in these long-term, but they are live today. |
---
docs: add §0 - auth + payment authorization was missing entirely Direct question caught a real gap: "everything is there? payment auth?" The census only grepped src/app/ - auth moved into the external @marketplaces/auth package this session, and its HTTP calls were never captured. Seven real endpoints were silently absent from a doc that called itself "complete": - 3 Telegram QR/session endpoints (POST/GET/DELETE .../users/sessions) - live today, customer and admin login share them, which is exactly why every admin endpoint must independently verify authorization server-side - 4 ed25519 admin challenge/response endpoints - specified in BACKEND-HANDOFF.md §3 and the package's own auth-api.model.ts, but not built server-side. Client shows backend-unavailable until they exist. Added §0.3 stating plainly what actually connects auth to payment: there is no separate payment login. Checkout, order pricing (§20), and partner credentials (§16) each ride on whichever of the two sessions above is active, or on the partner API's own separate signed-request auth (§6 of that contract - unrelated to Telegram/ed25519, already built, not a gap). The real payment gap is §1 (QR/card creation and polling, undocumented anywhere), not auth. Counts corrected: 51->54 specified, 90->97 total. Added item 0 to the action list, ahead of everything else: the ed25519 endpoints are the single most serious open issue named anywhere in docs/backend/, and every other item on the list assumes a working admin session to authorize against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:12:22 +04:00
## 0. Auth — lives in `@marketplaces/auth`, not this repo, and payment authorization runs through it
Two separate, real mechanisms. Both are called from the external package (`node_modules/@marketplaces/auth/dist/`), which is why §0 didn't exist in the first pass of this doc — that pass only grepped `src/app/`.
### 0.1 Telegram QR/session — ✅ Specified, **live**
Per `BACKEND-HANDOFF.md` §3 and `PACKAGES-USAGE.md`. **Customer and admin login call the same endpoints** — only client-side storage differs, which is exactly why every admin endpoint must independently verify authorization server-side (stated plainly in `BACKEND-HANDOFF.md` §3 as "the single most serious open issue in the system").
| Method | Path | Purpose |
|---|---|---|
| POST | `{authApiUrl}/users/sessions` | create a session from a Telegram login |
| GET | `{authApiUrl}/users/sessions/{id}` | poll / check session status |
| DELETE | `{authApiUrl}/users/sessions/{id}` | log out |
Expected response: `{ webSessionID, user: { userId, username, firstName, lastName }, status, expiresAt }` — parsed permissively client-side (many key-name variants accepted), but a clean backend implementation should return exactly this shape.
### 0.2 Ed25519 admin challenge/response — specified, **not built**
Per `BACKEND-HANDOFF.md` §3 and the package's own `ed25519/models/auth-api.model.ts`. This is what backend-authorizes an admin session distinctly from a customer one, and it does not exist server-side yet — every request today shows a `backend-unavailable` screen once the client reaches for it, nothing is mocked.
| Method | Path |
|---|---|
| GET | `/api/admin/auth/challenge` |
| POST | `/api/admin/auth/verify` |
| POST | `/api/admin/auth/refresh` |
| POST | `/api/admin/auth/logout` |
### 0.3 What this has to do with payment
There is no separate "payment login." Authorization for anything payment-adjacent — creating a checkout session, viewing `GET /api/admin/v2/orders/{id}`'s pricing breakdown (§20), touching a partner credential (§16) — rides on whichever of the two sessions above is active. The partner-provisioning API (§16) has its **own**, separate signed-request auth (§6 of that contract, public-key based, no session token at all) — that one is unrelated to Telegram/ed25519 and is not a gap, it's a different, already-built mechanism for a different caller (partners, not our own admins or customers).
**The actual payment gap is §1 below, not auth**: QR/card payment creation and status polling are real, live, and completely undocumented anywhere in `docs/backend/`.
---
## 1. Legacy surface (still called today, no `/api/v2` contract)
These come from `BACKEND-API-REFERENCE.md`, not `docs/backend/`. Base URL is `environment.localhostApiUrl` / tenant-resolved; `qrBaseUrl` is a separate provider base for QR-specific calls.
| Method | Path | Called from | Status |
|---|---|---|---|
| GET | `/ping` | `api.service.ts` | ❌ Undocumented — health check |
| GET | `/category` | `api.service.ts`, `api-category.repository.ts` | ❌ Undocumented — full category tree |
| GET | `/category/{categoryID}` | `api.service.ts` | ❌ Undocumented — one category + its items |
| GET | `/items/{itemID}` | `api.service.ts` | ❌ Undocumented — single item detail |
| GET | `/searchitems` | `api.service.ts` | ❌ Undocumented — search |
| GET | `/items/randomitems` | `api.service.ts` | ❌ Undocumented — related/random items |
| POST | `/websession/{sessionId}` | `api.service.ts` | ❌ Undocumented — sync cart to a Telegram web session |
| POST | `/items/{itemID}/callback` | `api.service.ts` | ❌ Undocumented — "call me back" request |
| POST | `/items/{itemID}/questiion` | `api.service.ts` | ❌ Undocumented — product Q&A (note: `questiion` typo is load-bearing, do not silently "fix" without checking the live backend uses the same typo) |
| POST | `/items/{itemID}/notify-me` | `api.service.ts` | ❌ Undocumented — back-in-stock subscription |
| POST | `/purchase-email` | `api.service.ts` | ❌ Undocumented — post-purchase email collection |
| POST | `/orders` | `api.service.ts` | ❌ Undocumented — records a paid cart as a backoffice order, fire-and-forget |
refactor: delete dead legacy payment code from ApiService Verified zero remaining callers for each before deleting (grepped src/app for every method name individually), not assumed from the earlier commit's dead-code note. Deleted from api.service.ts: - createPayment() - legacy direct QR creation (POST {qrBaseUrl}/qr) - createCartPayment() - legacy /cart payment creation, client-sent amount - createPaymentIntent() - superseded by @marketplaces/payment's gateway - checkCartPaymentStatus(), checkCartCardPaymentStatus(), checkPaymentStatus() - legacy QR/card status polls, superseded by the same gateway - resolvePaymentQrId/resolvePaymentQrUrl/resolvePaymentLink/ resolveBankPaymentUrl - QrCreateResponse field-normalization helpers, no longer had a caller once the methods above were gone - Types: QrCreateRequest, QrCreateResponse, CartPaymentRequest, PaymentIntentRequest, QrDynamicStatusResponse - Fields: qrBaseUrl, cartPaymentPartnerId - no longer read by anything - Imports: HttpHeaders, environment - no longer used in this file Did NOT touch createOrder() or createCheckoutSession() - both still have live callers in cart.component.ts, confirmed before deciding what to keep. cart.component.ts: corrected the createPaymentIntent() comment, which referenced the deleted method/helper names, to name what actually got deleted instead of what was merely "dead as of that commit." docs/backend/FRONTEND-API-SURFACE-COMPLETE.md: moved the 4 now-deleted QR/card endpoints out of the "still live" legacy table into a dated removal note - the doc's own premise is "every endpoint this codebase currently calls," so it was wrong to leave them listed as called once they weren't. Legacy-undocumented count corrected 15->11, total 97->93. Verified: production build succeeds (no dangling references), 247/247 unit tests, arch:check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 10:27:59 +04:00
**Recommendation:** these 11 need their own contract doc if they are staying, or a deprecation timeline if `/api/v2/storefront/*` replaces them. Right now they are simply undocumented and live — the single biggest gap in `docs/backend/`.
**Removed 2026-08-21, no longer called by this codebase:** `POST {qrBaseUrl}/qr` (direct QR creation), `POST /cart` (legacy payment creation with client-sent `amount`), `GET {qrBaseUrl}/qr/dynamic/{partnerId}/{qrId}` and `GET {qrBaseUrl}/card/{partnerId}/{orderId}` (status polls). §2's checkout flow made these dead in code (`createPaymentIntent`) as of the earlier `@marketplaces/payment` integration commit; confirmed zero remaining callers and deleted the dead `ApiService` methods, request/response types, and unused fields (`qrBaseUrl`, `cartPaymentPartnerId`) in the same pass. If a real backend still serves these endpoints, they are now backend-only surface with no frontend caller — decide their fate independently of this doc.
---
## 2. Storefront checkout & cart — ✅ Specified
Contract: [PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md](PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md) §5.2, [PHASE-6-CART-CHECKOUT-CONTRACT.md](PHASE-6-CART-CHECKOUT-CONTRACT.md) §3, §5.
| Method | Path | Called from |
|---|---|---|
| GET | `/api/v2/storefront/cart` | `server-cart-api.gateway.ts` |
| POST | `/api/v2/storefront/cart/lines` | `server-cart-api.gateway.ts` |
| PATCH | `/api/v2/storefront/cart/lines/{lineId}` | `server-cart-api.gateway.ts` |
| DELETE | `/api/v2/storefront/cart/lines/{lineId}` | `server-cart-api.gateway.ts` |
| POST | `/api/v2/storefront/checkout` | `server-cart-api.gateway.ts`, `api.service.ts` (two different callers, same contract) |
| POST | `/api/v2/storefront/payments/intents` | `api.service.ts` |
## 3. Pricing — ✅ Specified
Contract: [PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md](PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md) §3.1.
| Method | Path | Called from |
|---|---|---|
| GET | `/api/v2/pricing/fx-quote?base=&quote=` | `fx-quote-api.gateway.ts` |
## 4. Identity & permissions — ✅ Specified
Contracts: [PHASE-8-IDENTITY-MESSAGING-CONTRACT.md](PHASE-8-IDENTITY-MESSAGING-CONTRACT.md) §2, [TRACK-S-SECURITY-RBAC-CONTRACT.md](TRACK-S-SECURITY-RBAC-CONTRACT.md) §2.
| Method | Path | Called from |
|---|---|---|
| GET | `/api/identity/v1/vk/authorize` | `vk-id-api.gateway.ts` |
| POST | `/api/identity/v1/vk/callback` | `vk-id-api.gateway.ts` |
| GET | `/api/identity/v1/session/permissions` | `permission-api.gateway.ts` |
## 5. Team / RBAC — mixed
Contract: [TRACK-S-SECURITY-RBAC-CONTRACT.md](TRACK-S-SECURITY-RBAC-CONTRACT.md) §8.
| Method | Path | Called from | Status |
|---|---|---|---|
| GET | `/api/admin/v2/audit` | `permission-api.gateway.ts`, `admin-users-api.gateway.ts?actor=` | ✅ Specified |
| POST | `/api/admin/v2/team/invite` | `admin-users-api.gateway.ts` | ✅ Specified |
| GET | `/api/admin/v2/team?marketplaceId=` | `admin-users-api.gateway.ts` | ✅ Specified |
| PATCH | `/api/admin/v2/team/{userId}` | `admin-users-api.gateway.ts` | ✅ Specified |
| DELETE | `/api/admin/v2/team/{userId}` | (interface exists, not yet called) | ✅ Specified |
| GET | `/api/admin/v2/team/roles` | `admin-users-api.gateway.ts` | ⚠️ Inferred |
| GET | `/api/admin/v2/team/invitations` | `admin-users-api.gateway.ts` | ⚠️ Inferred |
| GET | `/api/admin/v2/team/{userId}/sessions` | `admin-users-api.gateway.ts` | ⚠️ Inferred |
| PATCH | `/api/admin/v2/team/{userId}/status` | `admin-users-api.gateway.ts` | ⚠️ Inferred |
| DELETE | `/api/admin/v2/team/invitations/{id}` | `admin-users-api.gateway.ts` | ⚠️ Inferred |
| DELETE | `/api/admin/v2/team/sessions/{sessionId}` | `admin-users-api.gateway.ts` | ⚠️ Inferred |
## 6. Orders & notifications — ✅ Specified
Contract: [PHASE-2-ORDERS-NOTIFICATIONS-CONTRACT.md](PHASE-2-ORDERS-NOTIFICATIONS-CONTRACT.md).
| Method | Path | Called from |
|---|---|---|
| GET | `/api/admin/v2/orders?marketplaceId=&status=&source=&page=&pageSize=` | `admin-orders-api.gateway.ts` |
| GET | `/api/admin/v2/orders/{id}` | `admin-orders-api.gateway.ts` |
| PATCH | `/api/admin/v2/orders/{id}/status` | `admin-orders-api.gateway.ts` |
| POST | `/api/admin/v2/orders/{id}/refund-request` | `admin-orders-api.gateway.ts` (note: gateway calls this `refund-request`; interface method is named `requestRefund` — same endpoint) |
| POST | `/api/admin/v2/orders/{id}/notes` | `admin-orders-api.gateway.ts` |
| POST | `/api/admin/v2/orders/{id}/archive` | `admin-orders-api.gateway.ts` |
| POST | `/api/admin/v2/orders/{id}/restore` | `admin-orders-api.gateway.ts` |
| DELETE | `/api/admin/v2/orders/{id}` | `admin-orders-api.gateway.ts` |
| GET | `/api/admin/v2/notifications?marketplaceId=&unreadOnly=&eventType=` | `admin-notifications-api.gateway.ts` |
| PATCH | `/api/admin/v2/notifications/{id}/read` | `admin-notifications-api.gateway.ts` |
| PATCH | `/api/admin/v2/notifications/read-all` | `admin-notifications-api.gateway.ts` | ⚠️ Inferred (bulk mark-read not in contract) |
## 7. Catalog / offers — ✅ Specified + ⚠️ Inferred
Contract: [PHASE-3-CATALOG-OFFER-FULFILLMENT-CONTRACT.md](PHASE-3-CATALOG-OFFER-FULFILLMENT-CONTRACT.md) §7.
| Method | Path | Called from | Status |
|---|---|---|---|
| GET | `/api/admin/v2/products?marketplaceId=&status=&search=&page=&pageSize=` | `admin-products-api.gateway.ts` | ✅ Specified |
| GET | `/api/admin/v2/products/{id}` | `admin-products-api.gateway.ts` | ✅ Specified |
| POST | `/api/admin/v2/products` | `admin-products-api.gateway.ts` | ✅ Specified |
| PATCH | `/api/admin/v2/products/{id}` | `admin-products-api.gateway.ts` | ✅ Specified |
| GET | `/api/admin/v2/offers?productId=&sellerId=&status=` | `offer-api.gateway.ts` | ✅ Specified |
| POST | `/api/admin/v2/offers/{id}/publish` | `offer-api.gateway.ts` | ✅ Specified — 422 + `details[]` on executability failure |
| GET | `/api/admin/v2/offers/lookup?sku=&sellerSku=&externalId=` | `offer-api.gateway.ts` | ✅ Specified |
| GET | `/api/admin/v2/products/categories` | `admin-products-api.gateway.ts` | ⚠️ Inferred |
| DELETE | `/api/admin/v2/products/{id}` | `admin-products-api.gateway.ts` | ⚠️ Inferred |
| POST | `/api/admin/v2/products/{id}/duplicate` | `admin-products-api.gateway.ts` | ⚠️ Inferred |
| POST | `/api/admin/v2/products/{id}/archive` | `admin-products-api.gateway.ts` | ⚠️ Inferred |
| POST | `/api/admin/v2/products/{id}/restore` | `admin-products-api.gateway.ts` | ⚠️ Inferred |
| GET | `/api/admin/v2/offers/{offerId}/inventory` | `offer-api.gateway.ts` | ⚠️ Inferred |
## 8. Categories — ✅ Specified (pre-existing, F29 done before this session)
| Method | Path | Called from |
|---|---|---|
| GET | `{baseUrl}` (categories collection) | `admin-categories-api.gateway.ts` |
| GET | `{baseUrl}/{id}` | `admin-categories-api.gateway.ts` |
| POST | `{baseUrl}` | `admin-categories-api.gateway.ts` |
| PUT | `{baseUrl}/{id}` | `admin-categories-api.gateway.ts` |
| DELETE | `{baseUrl}/{id}` | `admin-categories-api.gateway.ts` |
| POST | `{baseUrl}/{id}/restore` | `admin-categories-api.gateway.ts` |
| GET | `{baseUrl}/slug-taken` | `admin-categories-api.gateway.ts` |
## 9. Seller portal — mixed
Contract: [PHASE-5-SELLER-PORTAL-CONTRACT.md](PHASE-5-SELLER-PORTAL-CONTRACT.md) §3.
| Method | Path | Called from | Status |
|---|---|---|---|
| GET | `/api/seller/v1/finance/settlements` | (contract-only, no current caller) | ✅ Specified |
| GET | `/api/admin/v2/sellers` | `seller-api.gateway.ts` | ⚠️ Inferred — contract only specifies the caller's own `GET /api/seller/v1/profile`, not an admin list-all |
| GET | `/api/admin/v2/sellers/{sellerId}/team` | `seller-api.gateway.ts` | ⚠️ Inferred — contract's `GET /api/seller/v1/team` is session-scoped, not parameterized |
## 10. Payments, refunds, reconciliation, settlements — ✅ Specified
Contract: [PHASE-7-PAYMENTS-RECONCILIATION-CONTRACT.md](PHASE-7-PAYMENTS-RECONCILIATION-CONTRACT.md).
| Method | Path | Called from |
|---|---|---|
| GET | `/api/admin/v2/orders/{orderId}/refunds` | `finance-api.gateway.ts` |
| GET | `/api/admin/v2/reconciliation/queue` | `finance-api.gateway.ts` |
| POST | `/api/admin/v2/reconciliation/{id}/resolve` | `finance-api.gateway.ts` |
| GET | `/api/admin/v2/finance/settlements?sellerId=` | `finance-api.gateway.ts` |
## 11. Tenant registry — mixed
Contract: [PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md).
| Method | Path | Called from | Status |
|---|---|---|---|
| GET | `/api/admin/v2/marketplaces/{id}/lifecycle` | `marketplace-api.gateway.ts` | ✅ Specified |
| GET | `/api/admin/v2/marketplaces` (list) | `marketplace-api.gateway.ts` | ⚠️ Inferred — contract specifies `POST` for creation, not the list `GET` |
| GET | `/api/admin/v2/marketplaces/{id}/domains` | `marketplace-api.gateway.ts` | ⚠️ Inferred |
## 12. Connector framework — mixed
Contract: [PHASE-4-CONNECTOR-FRAMEWORK-CONTRACT.md](PHASE-4-CONNECTOR-FRAMEWORK-CONTRACT.md) §7-8.
| Method | Path | Called from | Status |
|---|---|---|---|
| GET | `/api/admin/v2/integrations` | `connector-api.gateway.ts` | ✅ Specified |
| PATCH | `/api/admin/v2/integrations/{id}` | `connector-api.gateway.ts` (pause/resume via `status` field) | ✅ Specified |
| GET | `/api/admin/v2/integrations/{connectorId}/dead-letter` | `connector-api.gateway.ts` | ⚠️ Inferred — contract specifies replay, not the list |
| POST | `/api/admin/v2/integrations/{connectorId}/dead-letter/{id}/replay` | `connector-api.gateway.ts` | ✅ Specified — path corrected 2026-08-18; the gateway initially omitted `connectorId`, caught while writing this doc, fixed in the same pass |
## 13. Content modules (Gorbushka-class) — ⚠️ Mostly inferred
Contract: [PHASE-10-CONTENT-MODULES-CONTRACT.md](PHASE-10-CONTENT-MODULES-CONTRACT.md) §2.
| Method | Path | Called from | Status |
|---|---|---|---|
| POST | `/api/admin/v2/content/rent-listings/{id}/leads` | `mall-content-api.gateway.ts` | ✅ Specified |
| GET | `/api/admin/v2/content/shops` | `mall-content-api.gateway.ts` | ⚠️ Inferred |
| GET | `/api/admin/v2/content/shop-categories` | `mall-content-api.gateway.ts` | ⚠️ Inferred |
| GET | `/api/admin/v2/content/floors` | `mall-content-api.gateway.ts` | ⚠️ Inferred |
| GET | `/api/admin/v2/content/floors/{floorId}/pins` | `mall-content-api.gateway.ts` | ⚠️ Inferred |
| GET | `/api/admin/v2/content/rent-listings` | `mall-content-api.gateway.ts` | ⚠️ Inferred |
## 14. Analytics — ✅ Specified
Contract: [TRACK-A-ANALYTICS-CONTRACT.md](TRACK-A-ANALYTICS-CONTRACT.md) §1.
| Method | Path | Called from |
|---|---|---|
| POST | `/api/v2/storefront/analytics/events` | `analytics-api.gateway.ts` |
## 15. Transactions, monitoring, moderation — ❌ No contract doc exists
These three domains have gateways calling `/api/admin/v2/{resource}` by convention only. No Phase/Track doc covers any of them.
| Method | Path | Called from |
|---|---|---|
| GET | `/api/admin/v2/transactions` | `admin-transactions-api.gateway.ts` |
| POST | `/api/admin/v2/transactions/{id}/retry` | `admin-transactions-api.gateway.ts` |
| PATCH | `/api/admin/v2/transactions/{id}` | `admin-transactions-api.gateway.ts` |
| GET | `/api/admin/v2/monitoring/events` | `admin-monitoring-api.gateway.ts` |
| GET | `/api/admin/v2/monitoring/queues` | `admin-monitoring-api.gateway.ts` |
| GET | `/api/admin/v2/monitoring/webhooks` | `admin-monitoring-api.gateway.ts` |
| GET | `/api/admin/v2/moderation/reviews` | `admin-moderation-api.gateway.ts` |
| GET | `/api/admin/v2/moderation/reviews/{id}` | `admin-moderation-api.gateway.ts` |
| PATCH | `/api/admin/v2/moderation/reviews/{id}` | `admin-moderation-api.gateway.ts` (status/visible/pinned/featured — 4 different PATCH bodies, same endpoint) |
| POST | `/api/admin/v2/moderation/reviews/{id}/notes` | `admin-moderation-api.gateway.ts` |
| DELETE | `/api/admin/v2/moderation/reviews/{id}` | `admin-moderation-api.gateway.ts` |
| GET | `/api/admin/v2/moderation/reports` | `admin-moderation-api.gateway.ts` |
| PATCH | `/api/admin/v2/moderation/reports/{id}` | `admin-moderation-api.gateway.ts` |
| GET | `/api/admin/v2/dashboard/metrics` | `admin-dashboard-metrics-api.gateway.ts` |
**Recommendation: these are the highest-priority gap.** Three full admin domains with real UI and real gateways, zero backend contract. Whoever picks up Phase 5/7 next should write these as proper contract docs — the endpoint shapes above are a starting point, not a spec.
## 16. Partner provisioning API — ✅ Specified
Contract: [PARTNER-PROVISIONING-API-CONTRACT.md](PARTNER-PROVISIONING-API-CONTRACT.md) §4, §6. This is the one domain where the frontend gateway was built *from* the contract, not the other way around — no drift to reconcile.
| Method | Path | Called from |
|---|---|---|
| GET | `/api/partner/v1/companies/{companyId}/hierarchy?environment=` | `partner-hierarchy-api.gateway.ts` |
| GET | `/api/partner/v1/nodes/{nodeId}` | `partner-hierarchy-api.gateway.ts` |
| GET | `/api/partner/v1/nodes/lookup?externalReference=&environment=` | `partner-hierarchy-api.gateway.ts` |
| POST | `/api/partner/v1/companies/{companyId}/projects` | `partner-hierarchy-api.gateway.ts` |
| POST | `/api/partner/v1/projects/{projectId}/stores` | `partner-hierarchy-api.gateway.ts` |
| POST | `/api/partner/v1/stores/{storeId}/payment-points` | `partner-hierarchy-api.gateway.ts` |
| PATCH | `/api/partner/v1/nodes/{nodeId}/status` | `partner-hierarchy-api.gateway.ts` |
| POST | `/api/partner/v1/nodes/{nodeId}/disable` | `partner-hierarchy-api.gateway.ts` |
| GET | `/api/partner/v1/credentials?companyId=` | `partner-hierarchy-api.gateway.ts` |
| POST | `/api/partner/v1/credentials` | `partner-hierarchy-api.gateway.ts` |
| POST | `/api/partner/v1/credentials/{keyId}/rotate` | `partner-hierarchy-api.gateway.ts` |
| DELETE | `/api/partner/v1/credentials/{keyId}` | `partner-hierarchy-api.gateway.ts` |
## 17. Backoffice data & bootstrap — ✅ Specified elsewhere (not a Phase/Track doc, but stable)
| Method | Path | Called from |
|---|---|---|
| GET | `/api/backoffice/products` | `api-backoffice-data.provider.ts` |
| GET | `/api/backoffice/categories` | `api-backoffice-data.provider.ts` |
| GET | (tenant bootstrap URL) | `api-bootstrap.provider.ts` — see `BACKEND-HANDOFF.md` §1a |
docs: final backend handoff - revision endpoints, response-shape additions, close-out Updates FRONTEND-API-SURFACE-COMPLETE.md to cover everything built after it was first generated - this is the final version for this pass, not a snapshot mid-way through. Added, none of which existed in the doc before: - §18: the 4 marketplace revision endpoints (create draft/validate/ publish/rollback) - built this session, missing from the census entirely. Flags the same draft/validated/preview/published ambiguity already documented in the model itself, so backend sees it without having to read source. - §19: RoutingContext as an optional field addition on GET /api/admin/v2/orders/{id} - not a new endpoint, a response-shape ask. - §20: order pricing-breakdown fields (unitPriceMinor, lineTotalMinor, priceSnapshotId, discountMinor, fxQuoteId, deliveryMinor) feeding the new total-formula panel. States plainly that the panel shows nothing rather than a wrong number while these are absent. - §21: 8 optional dashboard-metrics fields (GMV, conversion, moderation queue, etc.) - explicitly labelled a genuine ask, not a confirmed contract, since no spec exists for this endpoint at all (§15). - §22: states directly that the frontend's new double-click guard does not replace backend idempotency enforcement and was never meant to - closes one UI race, does nothing for a retried request or a duplicate webhook. Counts updated (47->51 specified, 86->90 total; +3 response-shape asks that aren't new endpoints). Closing section states the one item genuinely blocked pending a live backend (F60, the full acceptance-path E2E) so nobody mistakes "frontend backlog complete" for "nothing left to build." Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:08:41 +04:00
## 18. Marketplace publish/revision model — ✅ Specified
Contract: [PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md) §5. Frontend core built (`marketplace-revision-*.gateway.ts`), not yet wired into the project editor's UI — see §20.
| Method | Path | Called from |
|---|---|---|
| POST | `/api/admin/v2/marketplaces/{id}/revisions` | `marketplace-revision-api.gateway.ts` — create draft |
| POST | `/api/admin/v2/marketplaces/{id}/revisions/{revId}/validate` | `marketplace-revision-api.gateway.ts` |
| POST | `/api/admin/v2/marketplaces/{id}/revisions/{revId}/publish` | `marketplace-revision-api.gateway.ts` |
| POST | `/api/admin/v2/marketplaces/{id}/revisions/{revId}/rollback` | `marketplace-revision-api.gateway.ts` — creates a NEW revision, never mutates the old one |
**One real ambiguity in §5 itself, flagged for confirmation, not guessed silently:** the pipeline is described as 4 stages (`draft → validated → preview → publish`) but only 3 write endpoints exist (validate/publish/rollback) — there is no dedicated "move to preview" call. The frontend model assumes `POST .../validate` moves a revision straight to `preview` (the state `publish` requires), treating `validated` as a value the caller may never observe. **Confirm this is correct before implementing** — if the real response returns `status: 'validated'` and requires a separate step to reach `preview`, the frontend model and this doc both need updating.
## 19. RoutingContext on payments — carried through, not yet backend-verified
Contract: [PARTNER-PROVISIONING-API-CONTRACT.md](PARTNER-PROVISIONING-API-CONTRACT.md) §7, [PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md](PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md) §6.5. Not a separate endpoint — a field addition backend needs to populate on existing responses:
```ts
routing?: {
companyId: string;
routingPath: string[];
leafNodeId: string;
environment: 'TEST' | 'LIVE';
merchantReference: string;
providerPaymentId: string;
}
```
Frontend added this as an **optional** field on `AdminOrder` (`admin-order.model.ts`) and renders it on the order detail page when present. Nothing breaks if it's absent — but nothing shows the payment-point attribution either until backend populates it on `GET /api/admin/v2/orders/{id}`.
## 20. Order pricing breakdown — same pattern, different fields
Contract: [PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md](PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md) §5.3. Optional fields added to `AdminOrderItem` and `AdminOrder`:
```ts
// per line
unitPriceMinor?: number;
lineTotalMinor?: number;
priceSnapshotId?: string;
discountMinor?: number;
// per order
fxQuoteId?: string;
deliveryMinor?: number;
```
Frontend renders a "total formula" panel on the order detail page (`order-total-formula.component.ts`) reconstructing `total = sum(unitPrice*qty) - discounts + delivery`, with the FX quote used. **It refuses to show a partial breakdown** — every line must carry `unitPriceMinor` or the panel says "not available" instead of a number that's silently wrong. Populate these fields on `GET /api/admin/v2/orders/{id}` to make it real; until then it correctly shows nothing.
## 21. Dashboard metrics — 8 new optional fields, no shape confirmed
Contract intent: [PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md) §7's target metric list — no contract doc defines `GET /api/admin/v2/dashboard/metrics`'s response shape (§15 already flagged this endpoint has no spec at all). Frontend added these as optional fields on `AdminDashboardMetrics`, each rendering `'unknown'` (not a fabricated `'healthy'`) while absent:
```ts
gmvMinor?: number;
currency?: string;
paidOrdersCount?: number;
conversionRate?: number; // 0-1, not a percentage
paymentFailureRate?: number; // 0-1
moderationQueueCount?: number;
lowStockCount?: number;
unmatchedEventsCount?: number;
integrationHealthyCount?: number;
integrationTotalCount?: number;
```
This is a genuine ask, not a confirmed contract — §15's recommendation to write a real spec for this endpoint still stands. These field names are what the frontend already expects; change them here first if backend needs different ones.
## 22. Idempotency — frontend now guards, backend enforcement is still required
The frontend added a client-side guard against double-submitting checkout (a real bug: double-clicking used to fire two `POST /api/v2/storefront/checkout` calls — fixed in `cart.component.ts`, `checkoutInFlight` signal). **This does not replace backend idempotency and was never meant to.** It closes one specific UI race; it does nothing for a retried request from a flaky network, a backgrounded tab resuming, or an actual duplicate webhook delivery. Contract requirements are unchanged and still required:
- `PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md` §6.3 — webhook idempotency key = `provider + providerEventId`
- `PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md` §6.4 — order creation idempotency key = `checkoutSessionId`
- `PARTNER-PROVISIONING-API-CONTRACT.md` §5 — `Idempotency-Key` header semantics for all partner-API creates
---
## Summary counts
| Status | Count |
|---|---|
docs: add §0 - auth + payment authorization was missing entirely Direct question caught a real gap: "everything is there? payment auth?" The census only grepped src/app/ - auth moved into the external @marketplaces/auth package this session, and its HTTP calls were never captured. Seven real endpoints were silently absent from a doc that called itself "complete": - 3 Telegram QR/session endpoints (POST/GET/DELETE .../users/sessions) - live today, customer and admin login share them, which is exactly why every admin endpoint must independently verify authorization server-side - 4 ed25519 admin challenge/response endpoints - specified in BACKEND-HANDOFF.md §3 and the package's own auth-api.model.ts, but not built server-side. Client shows backend-unavailable until they exist. Added §0.3 stating plainly what actually connects auth to payment: there is no separate payment login. Checkout, order pricing (§20), and partner credentials (§16) each ride on whichever of the two sessions above is active, or on the partner API's own separate signed-request auth (§6 of that contract - unrelated to Telegram/ed25519, already built, not a gap). The real payment gap is §1 (QR/card creation and polling, undocumented anywhere), not auth. Counts corrected: 51->54 specified, 90->97 total. Added item 0 to the action list, ahead of everything else: the ed25519 endpoints are the single most serious open issue named anywhere in docs/backend/, and every other item on the list assumes a working admin session to authorize against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:12:22 +04:00
| ✅ Specified | 54 |
| ⚠️ Inferred (needs confirmation) | 24 |
refactor: delete dead legacy payment code from ApiService Verified zero remaining callers for each before deleting (grepped src/app for every method name individually), not assumed from the earlier commit's dead-code note. Deleted from api.service.ts: - createPayment() - legacy direct QR creation (POST {qrBaseUrl}/qr) - createCartPayment() - legacy /cart payment creation, client-sent amount - createPaymentIntent() - superseded by @marketplaces/payment's gateway - checkCartPaymentStatus(), checkCartCardPaymentStatus(), checkPaymentStatus() - legacy QR/card status polls, superseded by the same gateway - resolvePaymentQrId/resolvePaymentQrUrl/resolvePaymentLink/ resolveBankPaymentUrl - QrCreateResponse field-normalization helpers, no longer had a caller once the methods above were gone - Types: QrCreateRequest, QrCreateResponse, CartPaymentRequest, PaymentIntentRequest, QrDynamicStatusResponse - Fields: qrBaseUrl, cartPaymentPartnerId - no longer read by anything - Imports: HttpHeaders, environment - no longer used in this file Did NOT touch createOrder() or createCheckoutSession() - both still have live callers in cart.component.ts, confirmed before deciding what to keep. cart.component.ts: corrected the createPaymentIntent() comment, which referenced the deleted method/helper names, to name what actually got deleted instead of what was merely "dead as of that commit." docs/backend/FRONTEND-API-SURFACE-COMPLETE.md: moved the 4 now-deleted QR/card endpoints out of the "still live" legacy table into a dated removal note - the doc's own premise is "every endpoint this codebase currently calls," so it was wrong to leave them listed as called once they weren't. Legacy-undocumented count corrected 15->11, total 97->93. Verified: production build succeeds (no dangling references), 247/247 unit tests, arch:check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 10:27:59 +04:00
| ❌ Undocumented (legacy) | 11 |
| **Total distinct endpoints called** | **93** |
docs: add §0 - auth + payment authorization was missing entirely Direct question caught a real gap: "everything is there? payment auth?" The census only grepped src/app/ - auth moved into the external @marketplaces/auth package this session, and its HTTP calls were never captured. Seven real endpoints were silently absent from a doc that called itself "complete": - 3 Telegram QR/session endpoints (POST/GET/DELETE .../users/sessions) - live today, customer and admin login share them, which is exactly why every admin endpoint must independently verify authorization server-side - 4 ed25519 admin challenge/response endpoints - specified in BACKEND-HANDOFF.md §3 and the package's own auth-api.model.ts, but not built server-side. Client shows backend-unavailable until they exist. Added §0.3 stating plainly what actually connects auth to payment: there is no separate payment login. Checkout, order pricing (§20), and partner credentials (§16) each ride on whichever of the two sessions above is active, or on the partner API's own separate signed-request auth (§6 of that contract - unrelated to Telegram/ed25519, already built, not a gap). The real payment gap is §1 (QR/card creation and polling, undocumented anywhere), not auth. Counts corrected: 51->54 specified, 90->97 total. Added item 0 to the action list, ahead of everything else: the ed25519 endpoints are the single most serious open issue named anywhere in docs/backend/, and every other item on the list assumes a working admin session to authorize against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:12:22 +04:00
(§0's 3 Telegram endpoints count as Specified+live; its 4 ed25519 endpoints count as Specified+not-built — both are real, named endpoints with a known shape, distinct from §1's "no contract exists anywhere" undocumented status.)
docs: final backend handoff - revision endpoints, response-shape additions, close-out Updates FRONTEND-API-SURFACE-COMPLETE.md to cover everything built after it was first generated - this is the final version for this pass, not a snapshot mid-way through. Added, none of which existed in the doc before: - §18: the 4 marketplace revision endpoints (create draft/validate/ publish/rollback) - built this session, missing from the census entirely. Flags the same draft/validated/preview/published ambiguity already documented in the model itself, so backend sees it without having to read source. - §19: RoutingContext as an optional field addition on GET /api/admin/v2/orders/{id} - not a new endpoint, a response-shape ask. - §20: order pricing-breakdown fields (unitPriceMinor, lineTotalMinor, priceSnapshotId, discountMinor, fxQuoteId, deliveryMinor) feeding the new total-formula panel. States plainly that the panel shows nothing rather than a wrong number while these are absent. - §21: 8 optional dashboard-metrics fields (GMV, conversion, moderation queue, etc.) - explicitly labelled a genuine ask, not a confirmed contract, since no spec exists for this endpoint at all (§15). - §22: states directly that the frontend's new double-click guard does not replace backend idempotency enforcement and was never meant to - closes one UI race, does nothing for a retried request or a duplicate webhook. Counts updated (47->51 specified, 86->90 total; +3 response-shape asks that aren't new endpoints). Closing section states the one item genuinely blocked pending a live backend (F60, the full acceptance-path E2E) so nobody mistakes "frontend backlog complete" for "nothing left to build." Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:08:41 +04:00
Plus 3 response-shape additions (§1921) on existing endpoints — not new endpoints, new optional fields on responses those endpoints already return.
## What backend needs to do with this
docs: add §0 - auth + payment authorization was missing entirely Direct question caught a real gap: "everything is there? payment auth?" The census only grepped src/app/ - auth moved into the external @marketplaces/auth package this session, and its HTTP calls were never captured. Seven real endpoints were silently absent from a doc that called itself "complete": - 3 Telegram QR/session endpoints (POST/GET/DELETE .../users/sessions) - live today, customer and admin login share them, which is exactly why every admin endpoint must independently verify authorization server-side - 4 ed25519 admin challenge/response endpoints - specified in BACKEND-HANDOFF.md §3 and the package's own auth-api.model.ts, but not built server-side. Client shows backend-unavailable until they exist. Added §0.3 stating plainly what actually connects auth to payment: there is no separate payment login. Checkout, order pricing (§20), and partner credentials (§16) each ride on whichever of the two sessions above is active, or on the partner API's own separate signed-request auth (§6 of that contract - unrelated to Telegram/ed25519, already built, not a gap). The real payment gap is §1 (QR/card creation and polling, undocumented anywhere), not auth. Counts corrected: 51->54 specified, 90->97 total. Added item 0 to the action list, ahead of everything else: the ed25519 endpoints are the single most serious open issue named anywhere in docs/backend/, and every other item on the list assumes a working admin session to authorize against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:12:22 +04:00
0. **§0.2 first, ahead of everything else on this list.** The 4 ed25519 admin auth endpoints are the single most serious open issue named anywhere in `docs/backend/` (`BACKEND-HANDOFF.md` §3's own words). Every other item below assumes an admin session exists to authorize the request — that session mechanism does not exist server-side yet.
docs: final backend handoff - revision endpoints, response-shape additions, close-out Updates FRONTEND-API-SURFACE-COMPLETE.md to cover everything built after it was first generated - this is the final version for this pass, not a snapshot mid-way through. Added, none of which existed in the doc before: - §18: the 4 marketplace revision endpoints (create draft/validate/ publish/rollback) - built this session, missing from the census entirely. Flags the same draft/validated/preview/published ambiguity already documented in the model itself, so backend sees it without having to read source. - §19: RoutingContext as an optional field addition on GET /api/admin/v2/orders/{id} - not a new endpoint, a response-shape ask. - §20: order pricing-breakdown fields (unitPriceMinor, lineTotalMinor, priceSnapshotId, discountMinor, fxQuoteId, deliveryMinor) feeding the new total-formula panel. States plainly that the panel shows nothing rather than a wrong number while these are absent. - §21: 8 optional dashboard-metrics fields (GMV, conversion, moderation queue, etc.) - explicitly labelled a genuine ask, not a confirmed contract, since no spec exists for this endpoint at all (§15). - §22: states directly that the frontend's new double-click guard does not replace backend idempotency enforcement and was never meant to - closes one UI race, does nothing for a retried request or a duplicate webhook. Counts updated (47->51 specified, 86->90 total; +3 response-shape asks that aren't new endpoints). Closing section states the one item genuinely blocked pending a live backend (F60, the full acceptance-path E2E) so nobody mistakes "frontend backlog complete" for "nothing left to build." Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:08:41 +04:00
1. **Build the ✅ rows as written** — they match an existing contract doc exactly. This includes §18's 4 revision endpoints, pending confirmation on the `validated`/`preview` ambiguity called out there.
2. **Confirm or correct every ⚠️ row** — each one has a comment at its call site in source explaining the inference. Search the codebase for `Inferred` to find all 24 in place, with the reasoning right next to the code.
docs: final backend handoff - revision endpoints, response-shape additions, close-out Updates FRONTEND-API-SURFACE-COMPLETE.md to cover everything built after it was first generated - this is the final version for this pass, not a snapshot mid-way through. Added, none of which existed in the doc before: - §18: the 4 marketplace revision endpoints (create draft/validate/ publish/rollback) - built this session, missing from the census entirely. Flags the same draft/validated/preview/published ambiguity already documented in the model itself, so backend sees it without having to read source. - §19: RoutingContext as an optional field addition on GET /api/admin/v2/orders/{id} - not a new endpoint, a response-shape ask. - §20: order pricing-breakdown fields (unitPriceMinor, lineTotalMinor, priceSnapshotId, discountMinor, fxQuoteId, deliveryMinor) feeding the new total-formula panel. States plainly that the panel shows nothing rather than a wrong number while these are absent. - §21: 8 optional dashboard-metrics fields (GMV, conversion, moderation queue, etc.) - explicitly labelled a genuine ask, not a confirmed contract, since no spec exists for this endpoint at all (§15). - §22: states directly that the frontend's new double-click guard does not replace backend idempotency enforcement and was never meant to - closes one UI race, does nothing for a retried request or a duplicate webhook. Counts updated (47->51 specified, 86->90 total; +3 response-shape asks that aren't new endpoints). Closing section states the one item genuinely blocked pending a live backend (F60, the full acceptance-path E2E) so nobody mistakes "frontend backlog complete" for "nothing left to build." Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:08:41 +04:00
3. **Populate the 3 optional field sets (§1921)** on the endpoints that already exist — `routing` and pricing-breakdown fields on `GET /api/admin/v2/orders/{id}`, the 8 metric fields on `GET /api/admin/v2/dashboard/metrics`. Nothing on the frontend breaks while these are absent; nothing shows the real data either.
4. **Write a contract for §15** (transactions, monitoring, moderation) — real UI, real gateways, zero spec. Highest-priority gap in this whole list.
5. **Decide the fate of §1** — 15 legacy endpoints with no contract at all, still live. Either document them as a stable, permanent surface, or set a Track N migration date.
6. **Enforce idempotency server-side regardless of §22** — the frontend's double-click guard is a UI nicety, not a substitute for `Idempotency-Key`/`providerEventId` dedup.
## One item that stays blocked until a real backend exists
The frontend backlog (F1F65, tracked this session) is complete except **F60: the full acceptance-path E2E** — seller → catalog → storefront → cart → checkout → payment → order → notification → fulfillment, in one test, against real infrastructure. Every other item is written, unit-tested, E2E-covered where an E2E test could prove something real, and pushed. This one cannot be honestly finished by mocking harder — it needs an actual backend to run against. Once even a minimal version of Phases 14 is live, this is the next thing to build (`docs/PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md` Track Q, Q3).