docs: v3.1 gap analysis + delivery plan; add DI seams to 9 admin gateways
Adds InjectionToken + factory for Orders, Products, Users, Transactions, Monitoring, Moderation (mirrors existing Categories/Dashboard pattern) and repoints their facades plus the derived Analytics/Customers facades and admin-order-watcher off the mock LocalGateway class directly. No behavior change today - still resolves to the mock - but a real backend can now be bound per domain with zero facade edits. Docs: full gap analysis of Product Plan v3.1 against current repo state, and a phased delivery plan (10 phases, 34 sprints, 5 tracks) breaking every identified gap into scoped, sequenced work. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
461
docs/PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md
Normal file
461
docs/PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md
Normal file
@@ -0,0 +1,461 @@
|
||||
# Product Plan v3.1 — Delivery Plan (Phases → Sprints → Todos)
|
||||
|
||||
Companion to [PRODUCT-PLAN-v3.1-GAP-ANALYSIS.md](PRODUCT-PLAN-v3.1-GAP-ANALYSIS.md). Every gap identified there is assigned here exactly once.
|
||||
|
||||
**No calendar dates.** The plan itself (§12) refuses invented dates and fixes *sequence + exit criteria* instead. This document does the same. Sprints are ordered units of work, not two-week promises. Sizes are relative: **S** / **M** / **L** / **XL**.
|
||||
|
||||
**Ownership tags:** `[FE]` this repo · `[BE]` backend/platform service · `[BOTH]` coordinated contract change · `[DEC]` decision, no code.
|
||||
|
||||
**Deviation from the plan's own order, and why:** the plan sequences P0-C (external ingestion) before P0-D (catalog integrity). We swap them. External order ingestion maps `externalSKU → internal offer` (§5.1), and `Offer` does not exist yet — ingestion has nothing to map onto until the Product/Offer split ships. Everything else follows the plan's ordering.
|
||||
|
||||
---
|
||||
|
||||
## Phase map
|
||||
|
||||
| Phase | Name | Plan ref | Gate |
|
||||
|---|---|---|---|
|
||||
| **0** | Unblock & seams | — | Decisions answered; every admin domain swappable |
|
||||
| **1** | Money & payment truth | P0-A, §2.3 §3.3 §3.8 §7 | An order total is explainable from data |
|
||||
| **2** | Orders canonical + notifications | P0-B, §2.8 §2.10 §3.5 | Paid order appears and notifies without refresh |
|
||||
| **3** | Catalog integrity + fulfillment | P0-D, §2.1 §2.4 §3.6 | Any published offer is genuinely buyable and fulfillable |
|
||||
| **4** | External order ingestion | P0-C, §5 §3.7 | External purchase lands in Orders, no duplicates |
|
||||
| **🚦** | **PRODUCTION LAUNCH GATE** | §3 LAUNCH BLOCKERS, §13.2 | All P0 closed and evidenced |
|
||||
| **5** | Seller Portal | P1-A, §2.2 | Seller runs own offers and orders in scoped UI |
|
||||
| **6** | Server cart + checkout session | P1-B, §2.5 §2.6 | Client price never trusted; repeat-safe |
|
||||
| **7** | Payments hardening + reconciliation | P1-C, §2.7 §7.3 | Internal vs provider matched, mismatches visible |
|
||||
| **8** | Identity & messaging | §2.9 §3.4 §14 | VK/MAX/Telegram linked; bot collects delivery |
|
||||
| **9** | Tenant registry, domains, releases | P2-A, §4.3 §8 | New marketplace launched with no hardcode |
|
||||
| **10** | Tenant content modules (Gorbushka) | P2-B, §11 | Content tenant on same runtime/backoffice |
|
||||
|
||||
**Parallel tracks** (start early, run across phases): **A** Analytics pipeline · **S** Security/RBAC/audit · **Q** QA & E2E · **N** API namespace migration · **Z** Pre-existing repo debt.
|
||||
|
||||
---
|
||||
|
||||
## Phase 0 — Unblock & seams
|
||||
|
||||
Nothing downstream can be honestly estimated until this closes. Two sprints: one is other people answering questions, one is work we can do today with no answers.
|
||||
|
||||
### Sprint 0.1 — Decisions `[DEC]`
|
||||
|
||||
Blocking. Escalate as a single list, not one at a time.
|
||||
|
||||
- [ ] **Backend ownership.** Platform API, Workers, Integration Hub, Domain Automation — our team or a service team? Everything `[BE]` below is unassigned until answered.
|
||||
- [ ] **Unfreeze the payment chain.** `BACKEND-API-REFERENCE.md §7` marks it do-not-modify. Phases 1, 6 and 7 are unbuildable otherwise.
|
||||
- [ ] **Name the external marketplaces** for §5 connectors (Ozon / Wildberries / Yandex Market / Avito / other). Each is a separate connector; Phase 4 cannot be sized without the list.
|
||||
- [ ] **FX rate source** — which provider, and does the backend return converted prices or serve rates? Plan §2.3 implies backend-converted.
|
||||
- [ ] **§14 vs. approved email/phone OTP spec** — VK ID first, or finish OTP first?
|
||||
- [ ] **Multi-seller orders: unified or split?** Open in three of our own documents. Blocks Phase 3 and Phase 5 data model.
|
||||
- [ ] **Reproduce or retract the "fixed 5-second payment" claim (§3.2).** Not present in this codebase.
|
||||
- [ ] **API namespace migration (§9.3)** — migrate before new endpoints, or accept two conventions? Cost rises every phase this is deferred.
|
||||
- [ ] **Document version** — file says v3.1, version block says 3.0. Which is canonical?
|
||||
|
||||
**Exit:** all nine answered in writing.
|
||||
|
||||
### Sprint 0.2 — Seams and type reconciliation `[FE]` — runs regardless of answers
|
||||
|
||||
- [ ] Add DI tokens to the 9 admin domains that have none: Orders, Products, Users, Transactions, Monitoring, Moderation (+ derived Customers, Analytics). **M** — hard prerequisite for every `[BE]` swap in Phases 1–7.
|
||||
- [ ] Reconcile `AdminRole` — defined twice with unrelated shapes (auth string-union vs. Users-page display interface). **S**
|
||||
- [ ] Reconcile the two `Category` types, both fed by the same `/category` response, both in use. **S**
|
||||
- [ ] Resolve `SellerConfig` (bootstrap) vs. `Seller`/`SellerBranding` (domain) — pick one or document the mapping. Blocks Phase 5. **S**
|
||||
- [ ] Build the feature-flag / capability-guard service an existing ADR already promises; migrate the hand-rolled `sellerManagement.enabled` check onto it. **S**
|
||||
- [ ] Build the centralized error-handling layer (`core/error-handling/`, `core/interceptors/` are `.gitkeep`-only today): error-envelope interceptor + 429 handling. **M** `[BOTH]` — envelope shape needs backend agreement.
|
||||
- [ ] Fix `toAuthErrorShape()` to read a body-level code, not HTTP status alone — the built "session expired" / "invalid signature" screens are currently dead UI. **S**
|
||||
- [ ] Bind mock implementations to `PRODUCT_DATA_PROVIDER` and `CATEGORY_REPOSITORY`, or delete the dead mock branch. Today both silently ignore `useMockData`. **S**
|
||||
|
||||
**Exit:** any admin domain can be pointed at a real backend by swapping one provider.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Money & payment truth (P0-A)
|
||||
|
||||
Closes §3.3 and §3.8, and half of the §13.1 acceptance table. The single highest-value phase: it is what makes totals explainable to a bank.
|
||||
|
||||
### Sprint 1.1 — Money model `[BOTH]`
|
||||
|
||||
- [ ] `Money = { amountMinor: int, currency }` end to end. Kill float arithmetic in `CurrencyRatesService.convert()`. **L**
|
||||
- [ ] Currency minor-units + rounding rules table (RUB/USD/EUR/AMD at minimum). **M**
|
||||
- [ ] Delete browser-owned rates: remove `currencyRates.v1` from `localStorage` and the hardcoded `DEFAULT_RATES` fallbacks (`USD: 0.011`, `AMD: 4.3`). **S**
|
||||
- [ ] Remove the admin-typed rate editor from Admin Settings once a real source exists. **S**
|
||||
|
||||
### Sprint 1.2 — FX quote + rate source `[BE]` + `[FE]`
|
||||
|
||||
- [ ] `FxQuote { base, quote, rate, source, observedAt, expiresAt, quoteId }` entity + endpoint. **M**
|
||||
- [ ] Rate-source adapter behind an interface; concrete provider pluggable (§7.1). **M**
|
||||
- [ ] Stale/outlier quote rules; checkout **blocks** or uses an explicitly configured fallback. **M**
|
||||
- [ ] `PriceBook`: offer base currency + allowed display/checkout currencies per tenant. **M**
|
||||
|
||||
### Sprint 1.3 — Price snapshot + server-authoritative amount `[BOTH]` — needs the freeze lifted
|
||||
|
||||
- [ ] `PriceSnapshot { offerId, amount, currency, fxQuoteId, capturedAt }`, immutable. **L**
|
||||
- [ ] Server computes and validates the charged amount. Stop trusting `CartPaymentRequest.amount` and the per-item `price[]` array from the browser. **L** — the plan's §2.5 headline requirement.
|
||||
- [ ] Old orders never recalculated when a rate updates. **S**
|
||||
- [ ] Backoffice "total formula" panel: lines × qty − discounts + delivery + fees, plus the FX quote used (§7.2). **M**
|
||||
- [ ] `PriceHistory` on offer price and stock, with author/source (§2.1). **M**
|
||||
|
||||
### Sprint 1.4 — Payment timeline `[BE]` + `[FE]`
|
||||
|
||||
- [ ] Explicit state machines: `PaymentIntent` (created→pending→authorized/paid→failed/cancelled), `Payment` (received→confirmed→captured/settled→refunded), `Order` (pending_payment→paid→processing→fulfilled). **L**
|
||||
- [ ] Persist `provider event id`, `provider timestamp`, `receivedAt`, `processedAt` per transition. **M**
|
||||
- [ ] Webhook entrypoint with signature verification + idempotency (§2.7). **L**
|
||||
- [ ] Idempotency keys on checkout, payment and order creation. Zero `idempot*` exists today. **M**
|
||||
- [ ] Replace client-polled status signals with server truth; keep polling only as a UI fallback. **M**
|
||||
- [ ] Keep the current honest behaviour: no artificial delay. Already compliant — protect it with a test. **S**
|
||||
|
||||
**Exit criteria (plan's own):** currency converts correctly; payment timeline reconstructable from provider events; every total explainable from `SKU/qty/delivery/discount/FX`.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Orders canonical + notifications (P0-B)
|
||||
|
||||
### Sprint 2.1 — Canonical order model `[BOTH]`
|
||||
|
||||
- [ ] `Order` header: `marketplaceId, source, customer, currency, subtotal, discounts, delivery, total, paymentStatus, orderStatus`. **L**
|
||||
- [ ] `OrderLine` with `offerId, sellerId, skuSnapshot, titleSnapshot, qty, unitPriceMinor, lineTotalMinor, priceSnapshotId`. **M**
|
||||
- [ ] `OrderEvent` timeline: created, paid, seller notified, accepted, fulfilled, cancelled, refunded (§2.8). Closes our own "Real order audit trail" TODO. **M**
|
||||
- [ ] Real `AdminOrdersApiGateway` replacing the 24-row static seed with no create path. **L** `[BE]`
|
||||
- [ ] Admin order actions: assign, resend notification, replay sync, cancel/refund by permission, comment, export. **M**
|
||||
- [ ] `OrderContactSnapshot` — name/contacts frozen at order time, immune to later profile edits (§2.9). **S**
|
||||
|
||||
### Sprint 2.2 — Event bus + Notification Center `[BE]` + `[FE]`
|
||||
|
||||
- [ ] Platform event bus emitting `order.created`, `order.paid`, `payment.failed`, `webhook.error`, `stock.low`, `oversell`, `refund.requested/completed`, `external_order.imported`. **L**
|
||||
- [ ] `Notification` entity: `unread/read`, `severity`, `marketplaceId`, entity type/id, **deep link**. **M**
|
||||
- [ ] `DeliveryAttempt` log per external channel — a Telegram/email failure must never lose the internal notification (§2.10). **M**
|
||||
- [ ] Backoffice Notifications section: unread queue, incidents, filter by marketplace and event type. Missing entirely from our nav today. **M**
|
||||
- [ ] Repoint `AdminOrderWatcherService` from polling to the event stream. Feature is already built and inert — this is what switches it on. **S**
|
||||
|
||||
**Exit:** a paid order appears in backoffice without manual refresh, with deep link and seller/source.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Catalog integrity + fulfillment (P0-D)
|
||||
|
||||
Biggest structural change in the whole programme. Everything about multi-seller commerce hangs off it.
|
||||
|
||||
### Sprint 3.1 — Product / Offer split `[BOTH]`
|
||||
|
||||
- [ ] Introduce `Offer/Listing { id, marketplaceId, sellerId, variantId, sellerSku, priceMinor, currency, stockPolicy, status, publishedAt }`. **XL** — does not exist in any form today.
|
||||
- [ ] Move price, stock, currency and status off `Product` onto `Offer`. **L**
|
||||
- [ ] Formalise `Product` / `Variant` / `SKU` / `Category` (with `attributesSchema`, SEO) as content-only. **L**
|
||||
- [ ] Unify the admin mock product domain with the live storefront `Item` domain — two unrelated shapes today. **L**
|
||||
- [ ] Offer lookup in backoffice by internal SKU, seller SKU, product ID or external mapping (§2.1 "готово, когда"). **M**
|
||||
|
||||
### Sprint 3.2 — Lifecycle, import, inventory `[BOTH]`
|
||||
|
||||
- [ ] `draft → moderation → published → paused/archived` for both product and offer; wire the existing mock Moderation module to it. **M**
|
||||
- [ ] Bulk import CSV/API: required-field validation, **error preview before apply**. Nothing exists (current "bulk" is Admin Categories edit actions only). **L**
|
||||
- [ ] `InventoryRecord`: `available` / `reserved` / `sold` counted separately. **L**
|
||||
- [ ] Reservations at checkout or pre-payment per strategy, with TTL. **M**
|
||||
- [ ] Idempotent upsert for seller feed stock updates; repeat webhook must not double-decrement. **M**
|
||||
- [ ] Oversell → dedicated incident queue, never silently hidden (§2.4). **M**
|
||||
|
||||
### Sprint 3.3 — Fulfillment + executability `[BOTH]`
|
||||
|
||||
- [ ] `Fulfillment` entity: manual / warehouse / pickup / digital; `status, assignedTo, issuedAt/shippedAt`, evidence where applicable. One `fulfil*` reference exists in the entire codebase today. **L**
|
||||
- [ ] Publish-time executability validation — an offer that cannot actually be fulfilled cannot be published (§3.6). **M**
|
||||
- [ ] Explicit test proving there is **no** inspector-detection branch anywhere: same production flow for every buyer (§3.6, §10.2, §13.2 last item). **S**
|
||||
- [ ] Multi-seller cart grouping by seller and fulfillment rules — currently undefined behaviour (§2.5). **M** — blocked on the unified-vs-split decision in Sprint 0.1.
|
||||
|
||||
**Exit:** any published, available offer really passes order → fulfillment.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — External order ingestion (P0-C)
|
||||
|
||||
Zero percent built today. Sized per connector; Sprint 4.2 repeats for each marketplace named in Sprint 0.1.
|
||||
|
||||
### Sprint 4.1 — Connector framework `[BE]`
|
||||
|
||||
- [ ] `Connector` + `ConnectorCredentialRef` in secret storage, scoped per marketplace/seller. **M**
|
||||
- [ ] Inbound: webhook where the provider supports it, polling fallback with cursor/since. **L**
|
||||
- [ ] `RawExternalEvent` — persist the raw payload before parsing, for traceability. **S**
|
||||
- [ ] Normalizer: external payload → canonical `ExternalOrderEvent` → internal `Order`. **L**
|
||||
- [ ] `ExternalOrderMapping`: `externalSellerId / externalProductId / externalSKU → internal seller/offer`. **L**
|
||||
- [ ] Idempotency on `source + externalOrderId/eventId`; a repeat must not create a duplicate order. **M**
|
||||
- [ ] Exponential retry, `DeadLetter`, manual replay from backoffice. **M**
|
||||
- [ ] **Unmatched queue** for events with no SKU mapping. **M**
|
||||
- [ ] Status/fulfillment push back to the external marketplace where its API allows (§5.2 step 8). **M**
|
||||
|
||||
### Sprint 4.2 — Per-connector implementation `[BE]` — ×N
|
||||
|
||||
- [ ] One sprint per named marketplace: auth, endpoint mapping, rate limits, sandbox verification. **L each**
|
||||
|
||||
### Sprint 4.3 — Connector observability `[FE]` + `[BE]`
|
||||
|
||||
- [ ] Backoffice **Integrations** section (missing from our nav): connectors, payment providers, FX sources, messaging. **M**
|
||||
- [ ] Per-connector health: last success, lag, errors, rate limit, backlog, unmatched mapping. **M**
|
||||
- [ ] Trace id on every connector error, visible in backoffice (§5.2 SLA). **S**
|
||||
- [ ] SLA instrumentation: webhook 99% under 60s; polling ≤ interval + 60s; **0** duplicate orders. **M**
|
||||
|
||||
**Exit:** an external purchase creates/updates an order automatically, never duplicates, and notifies the responsible manager.
|
||||
|
||||
---
|
||||
|
||||
## 🚦 PRODUCTION LAUNCH GATE
|
||||
|
||||
Per §3 "LAUNCH BLOCKERS" and the §13.2 checklist. Do not schedule a launch before every line is green **and evidenced by a test, not an assertion**.
|
||||
|
||||
- [ ] All P0 closed and confirmed by tests
|
||||
- [ ] Production analytics collecting real events (Track A)
|
||||
- [ ] Catalog contains only genuinely available/publishable offers
|
||||
- [ ] Seller permissions verified (Phase 5 or enforced-empty)
|
||||
- [ ] cart → checkout → payment → order end-to-end smoke passed
|
||||
- [ ] Webhook signatures, idempotency, retry verified
|
||||
- [ ] External connector reconciliation passed
|
||||
- [ ] FX source live, stale-quote policy verified
|
||||
- [ ] Notification delivery + fallback verified
|
||||
- [ ] Refund flow + reconciliation smoke passed
|
||||
- [ ] Domains/SSL/health checks green (Phase 9)
|
||||
- [ ] Backup/rollback exists
|
||||
- [ ] Audit enabled (Track S)
|
||||
- [ ] **No branch anywhere alters commerce flow based on who the buyer appears to be**
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Seller Portal (P1-A)
|
||||
|
||||
A placeholder page with a `false` flag and zero backend bytes today. Note: the enabled code path has **never been exercised even once** — every prior verification ran with the flag at its real value.
|
||||
|
||||
### Sprint 5.1 — Seller foundation `[BOTH]`
|
||||
- [ ] `SellerOrganization`, `SellerUser`, `SellerMarketplaceMembership`, `SellerIntegration`. **L**
|
||||
- [ ] Onboarding: organisation, credentials/profile, contacts, marketplace applications, moderation status. **L**
|
||||
- [ ] Backoffice **Sellers** section (missing from nav): organisations, applications, roles, status, listings, integration health. **L**
|
||||
|
||||
### Sprint 5.2 — Seller working surfaces `[FE]` + `[BE]`
|
||||
- [ ] Catalog: create/edit products & offers, media, attributes, submit for moderation, bulk import. **L**
|
||||
- [ ] Prices & Stock: mass edit, API/feed sync, change history, sync errors. **L**
|
||||
- [ ] Orders: new, confirm, pick/issue/ship, cancel, return, SLA, comments. **L**
|
||||
- [ ] Finance: accruals, commissions, refunds, settlement/payout register, report export. **L**
|
||||
- [ ] Team: `SELLER_OWNER`, `SELLER_CATALOG_MANAGER`, `SELLER_ORDER_MANAGER`, `SELLER_FINANCE_VIEWER`, `SELLER_VIEWER`. **M**
|
||||
- [ ] Integrations: API credentials, webhook/feed status, external SKU mapping, sync logs. **M**
|
||||
|
||||
### Sprint 5.3 — Seller isolation `[BE]` + `[Q]`
|
||||
- [ ] A seller cannot see another seller's products, orders, customers, finance or API keys — enforced backend-side, tested. **M**
|
||||
- [ ] Bank/payment detail changes: step-up auth + audit event + approval when maker/checker is on. **M**
|
||||
- [ ] Seller staff permissions verified backend-side regardless of UI visibility. **M**
|
||||
- [ ] First-ever fixture test of the seller-management enabled state. **S**
|
||||
|
||||
---
|
||||
|
||||
## Phase 6 — Server cart + checkout session (P1-B)
|
||||
|
||||
Partly pulled forward into Sprint 1.3 (server-authoritative amount). This phase completes the move.
|
||||
|
||||
### Sprint 6.1 — Server cart `[BOTH]`
|
||||
- [ ] `Cart` / `CartLine` server-side, keyed on `offerId`. Replaces `localStorage` + Telegram CloudStorage. **L**
|
||||
- [ ] Idempotent add/update/remove; quantity validated against stock and seller rules. **M**
|
||||
- [ ] Price-refresh: cart surfaces price changes before checkout and requires explicit confirmation when the total moved. **M**
|
||||
- [ ] Guest cart via session token; authenticated cart bound to customer account. **M**
|
||||
- [ ] Expiration: inactive carts cleared, reservations released on TTL. **S**
|
||||
|
||||
### Sprint 6.2 — Checkout session `[BOTH]`
|
||||
- [ ] `CheckoutSession` entity. `features/website/checkout/` is an empty directory today; checkout lives in a 751-line cart popup. **XL**
|
||||
- [ ] Server re-validates offers and stock at checkout start. **M**
|
||||
- [ ] Contact requirements enforced by tenant policy: email and/or phone verifiable (§2.6 step 4). **M**
|
||||
- [ ] Clear total breakdown shown to the customer. **M**
|
||||
- [ ] `PaymentIntent` via provider adapter; repeat click must not create a second intent. **M**
|
||||
- [ ] Guest-checkout on/off per tenant policy (§6.2). **S**
|
||||
- [ ] `DeliveryOption` entity. **M**
|
||||
|
||||
---
|
||||
|
||||
## Phase 7 — Payments hardening + reconciliation (P1-C)
|
||||
|
||||
### Sprint 7.1 — Refunds `[BOTH]`
|
||||
- [ ] `Refund` as a first-class operation with reason, actor and order-line linkage. `requestRefund(id)` is a mock method today. **L**
|
||||
- [ ] Partial refunds; `refunded / partially_refunded` states. **M**
|
||||
|
||||
### Sprint 7.2 — Reconciliation `[BE]` + `[FE]`
|
||||
- [ ] `ReconciliationRecord`; match on `providerPaymentId` / merchant reference / amount+currency fallback (§7.3). **L** — zero `reconcil*` in the codebase today.
|
||||
- [ ] Classify: unmatched, duplicate, amount mismatch, status mismatch. **M**
|
||||
- [ ] Backoffice **Payments & Finance** section (missing from nav): payments, refunds, reconciliation queue, unmatched events, settlements. **L**
|
||||
- [ ] Controlled resolution with full audit trail. **M**
|
||||
- [ ] Settlements / payout register. **L** — zero `settlement*` today.
|
||||
|
||||
### Sprint 7.3 — Provider breadth `[DEC]` + `[BOTH]`
|
||||
- [ ] Decide additional providers beyond the current QR/card flow (wallets, BNPL) — open business question. **DEC**
|
||||
- [ ] Provider adapter interface so a new provider is a plug-in, not a rewrite. **M**
|
||||
|
||||
---
|
||||
|
||||
## Phase 8 — Identity & messaging (§2.9, §3.4, §14)
|
||||
|
||||
Order inside this phase depends on the Sprint 0.1 decision (VK ID first vs. OTP first).
|
||||
|
||||
### Sprint 8.1 — Customer identity core `[BOTH]`
|
||||
- [ ] `Customer`, `ExternalIdentity`, `ContactMethod`, `Verification`, `Consent`. **L**
|
||||
- [ ] Telegram demoted from sole identity to one provider among several. **M**
|
||||
- [ ] `emailVerifiedAt` / `phoneVerifiedAt` / `telegramLinkedAt`. **S**
|
||||
- [ ] Backoffice **Customers** on real data: profiles, verified contacts, orders, consent. **M**
|
||||
- [ ] Sensitive profile changes logged. **S**
|
||||
|
||||
### Sprint 8.2 — Email/phone OTP `[BOTH]`
|
||||
- [ ] Implement the approved [email/phone login spec](superpowers/specs/2026-08-15-email-phone-login-design.md). **L**
|
||||
- [ ] Position it as recovery/fallback per v3.1 §14, not as the primary path. **S**
|
||||
|
||||
### Sprint 8.3 — VK ID `[BOTH]` — new in v3.1
|
||||
- [ ] OAuth 2.1/PKCE completed **backend-side**; link external identity to `Customer`. **L**
|
||||
- [ ] VK ID as the primary storefront social login. **M**
|
||||
- [ ] Repeat login must never create a duplicate customer. **M**
|
||||
- [ ] Identity-conflict handling → controlled resolution, never overwrite an existing binding (§14.3). **M**
|
||||
|
||||
### Sprint 8.4 — MAX + Telegram bot channels `[BOTH]` — new in v3.1
|
||||
- [ ] `ContactChannel`, `BotConversationBinding`, `MessagingConsent`. **L**
|
||||
- [ ] MAX bot-assisted linking: one-time code, TTL, single-use, bound to marketplace + browser session. **L**
|
||||
- [ ] Provider secrets never reach the frontend; all bot updates handled idempotently. **M**
|
||||
- [ ] Bot adapters (VK / MAX / Telegram) normalised into one `MessagingEvent` keyed to `orderId`. **L**
|
||||
|
||||
### Sprint 8.5 — Notification Orchestrator + delivery conversation `[BE]` — new in v3.1
|
||||
- [ ] Orchestrator routes `order.paid` to the customer's chosen channel; the backoffice notification always fires regardless. **L**
|
||||
- [ ] Channel choice in checkout ("where should we send confirmation?"), recorded in `OrderContactSnapshot`; linking flow must not lose the cart or checkout session. **M**
|
||||
- [ ] Delivery Conversation State Machine: `not_started → awaiting_customer → details_received → manager_assigned/auto_confirmed → shipment_planned → completed`. **L**
|
||||
- [ ] Bot collects city/address/recipient/phone/time window/comment; backend validates and snapshots into the order. **L**
|
||||
- [ ] **The bot must never change financial statuses** — delivery fields only, via Delivery Service. **M**
|
||||
- [ ] Follow-up rules per tenant; after N attempts hand off to a manager, no infinite spam. **M**
|
||||
- [ ] Manager handoff view: message history, current conversation state, accept handoff. **M**
|
||||
- [ ] Messenger unavailability creates a `DeliveryAttempt` error and triggers fallback — never blocks the order. **M**
|
||||
|
||||
---
|
||||
|
||||
## Phase 9 — Tenant registry, domains, releases (P2-A)
|
||||
|
||||
### Sprint 9.1 — Marketplace Registry `[BOTH]`
|
||||
- [ ] `Marketplace`, `MarketplaceDomain`, `MarketplaceFeatureSet`, `MarketplaceRevision`. **L**
|
||||
- [ ] Backoffice **Marketplaces** section (missing from nav): registry, type, status, domains, currencies, feature set, responsible manager. **L**
|
||||
- [ ] Onboarding wizard, all 8 steps of §4.3 (card → feature set → domains → design → roles → integrations → staging + smoke → production launch). **XL**
|
||||
- [ ] Lifecycle state machine `draft → configured → content_ready → domains_planned → staging_live → qa_passed → production_ready → live → paused/archived`, **showing which blocker prevents the next transition**. **L**
|
||||
- [ ] Marketplace dashboard (§4.2): GMV, paid orders, conversion, payment failure rate, orders needing action, seller moderation queue, low stock, unmatched events, integration health, domain/SSL/release status. **L**
|
||||
- [ ] Re-scope the [super-admin Phase 1 design](superpowers/specs/superuser.md) against this — it overlaps registry and audit. **M**
|
||||
- [ ] Consolidate `MarketplaceRef` vs. `TenantConfig` if a third marketplace-shaped type appears. **S**
|
||||
|
||||
### Sprint 9.2 — Domain automation `[BE]`
|
||||
- [ ] Hostinger DNS integration, all 7 endpoints from §8.2. Zero references exist today. **L**
|
||||
- [ ] Read current zone → snapshot/rollback payload → build and validate plan → apply only after production approval. **L**
|
||||
- [ ] **Never touch MX/SPF/DKIM/DMARC/CAA** without a separate task. **S**
|
||||
- [ ] Propagation, SSL and health verification; mark domain active only after checks pass. **M**
|
||||
- [ ] Backoffice **Domains & Releases** section (missing from nav). **M**
|
||||
|
||||
### Sprint 9.3 — Publish model `[BOTH]`
|
||||
- [ ] `draft → validation → preview → publish` with immutable published revisions; rollback creates a new revision (§8.3). **L**
|
||||
- [ ] Real builder persistence — today `apiEndpoints.builder` is an empty placeholder and "publish" only promotes a `localStorage` signal. **L**
|
||||
- [ ] CMS/static pages get a real backend write path (currently in-memory bootstrap only). **L**
|
||||
- [ ] Enforce that orders/payments/inventory ledger are **not** part of a content revision and never roll back with the storefront. **S**
|
||||
- [ ] Tenant resolution hardening: verified Host server-side, unknown Host → 404 with **no fallback tenant** (§6.1). **M**
|
||||
|
||||
---
|
||||
|
||||
## Phase 10 — Tenant content modules (P2-B, Gorbushka)
|
||||
|
||||
Only after Commerce Core is real. The plan is explicit that Gorbushka does not define the architecture.
|
||||
|
||||
### Sprint 10.1 — Directory content entities `[BOTH]`
|
||||
- [ ] `Shop`, `ShopCategory`, `Service`, `Floor`, `SchemePin`, `RentListing`, `News/Promo`, `StaticPage`, `Lead`, `MallSettings`. Only static pages exist today. **XL**
|
||||
- [ ] Every entity carries `marketplaceId`, audit, and publish/preview flow. **M**
|
||||
- [ ] Mall scheme / floors / pins UI. **L**
|
||||
- [ ] Rent listings + lead capture. **M**
|
||||
|
||||
### Sprint 10.2 — Gorbushka tenant config `[FE]`
|
||||
- [ ] Feature set per §11.1: CMS, shops, services, scheme, rent, news, SEO/media/domains **on**; catalog / seller portal / commerce **platform-ready but off**. **M**
|
||||
- [ ] Prove commerce can be switched on later without touching backend or storefront code. **M**
|
||||
|
||||
---
|
||||
|
||||
## Parallel tracks
|
||||
|
||||
### Track A — Analytics pipeline (P1-D, §3.1 §6.3)
|
||||
|
||||
**Start at Phase 1, not last.** Longest lead time in the programme, and it is a P0 in the plan's own §3. There is no tracking infrastructure at all today — this is not a missing endpoint.
|
||||
|
||||
- [ ] **A1** Server-side event logging spine. **XL** `[BE]`
|
||||
- [ ] **A2** Traffic events: `session_started`, `page_view`, source/utm/referrer, unique users/sessions. **M**
|
||||
- [ ] **A3** Catalog events: `search`, `category_view`, `product_view`, `seller_view`. **M**
|
||||
- [ ] **A4** Commerce events: `add_to_cart`, `cart_view`, `checkout_started`, `payment_started`, `payment_success/failed`, `order_created`. **M**
|
||||
- [ ] **A5** Operations metrics: `order_paid_to_notification` latency, fulfillment time, connector lag, payment webhook lag. **M**
|
||||
- [ ] **A6** Quality metrics: frontend/backend errors, checkout validation failures, FX stale-rate blocks. **M**
|
||||
- [ ] **A7** Real funnel dashboard in backoffice, replacing the mock-composed Analytics facade. **L**
|
||||
- [ ] **A8** **Synthetic traffic technically separated** from production analytics — staging/test only, never presented as real visits (§3.1, §6.3). **M**
|
||||
- [ ] **A9** Real product view counts — the shipped "Views" column always renders `0`. Either bridge to the live storefront `Item.visits` or serve it from the real Products backend. **S**
|
||||
- [ ] **A10** Post-launch monitoring set (§13.3): checkout conversion, payment success/failure, webhook lag, order-notification lag, connector lag, FX quote age, unmatched reconciliation, stuck fulfillment. **L**
|
||||
- [ ] **A11** Trending search terms endpoint — `loadTrending()` is a stub returning `of(null)`. **S**
|
||||
|
||||
### Track S — Security, RBAC, audit (§4.4, §10)
|
||||
|
||||
**Gate on Phase 5 and on the launch gate.** Today the role model is decorative: types exist, nothing gates any button, page or action. Anyone who authenticates has full access.
|
||||
|
||||
- [ ] **S1** Enforce RBAC backend-side with tenant scope on every request. **L**
|
||||
- [ ] **S2** Implement the 17 roles across 3 scopes (5 platform / 7 marketplace / 5 seller). **L**
|
||||
- [ ] **S3** Frontend permission guards on routes and actions — currently zero. **M**
|
||||
- [ ] **S4** Audit log covering permissions, seller changes, catalog moderation, price, payment/refund, manual order actions, integrations, production launch. `audit` appears only as mock display fields today. **L**
|
||||
- [ ] **S5** Backoffice **Audit & Security** section (missing from nav): role changes, sensitive actions, login/security events, exports. **M**
|
||||
- [ ] **S6** Step-up authentication for sensitive financial actions. **M**
|
||||
- [ ] **S7** Rate limits and abuse controls on storefront/auth/provider endpoints; client-side 429 handling (zero today). **M**
|
||||
- [ ] **S8** Secret storage for provider/connector credentials, scoped per marketplace/seller. **M**
|
||||
- [ ] **S9** PII minimisation: store only necessary customer data, restrict access and export. **M**
|
||||
- [ ] **S10** Ed25519 admin auth backend — wired client-side, 404s today. Decide: build it, or drop it for the plan's conventional RBAC. **DEC** + **L**
|
||||
- [ ] **S11** HttpOnly session cookie (existing frontend-blocked TODO). **M**
|
||||
|
||||
### Track Q — QA & E2E (§13)
|
||||
|
||||
The plan's entire Definition of Done is end-to-end. We have **zero** E2E tests and ~32% statement / ~19% branch coverage across 11 spec files.
|
||||
|
||||
- [ ] **Q1** Stand up an E2E harness (Playwright or equivalent) — none exists. **L**
|
||||
- [ ] **Q2** Solve automated admin login; several past "verified live" claims were code-inspection only because `/edit` and `/backoffice` need Telegram login. **M**
|
||||
- [ ] **Q3** E2E: full §13.1 acceptance path — seller → catalog → storefront → cart → checkout → payment → order → notification → fulfillment. **XL**
|
||||
- [ ] **Q4** E2E: currency switch recalculates by FX quote — explicitly, `160 RUB` must not become `160 USD/AMD`. **M**
|
||||
- [ ] **Q5** E2E: repeat webhook and double-click create exactly one order. **M**
|
||||
- [ ] **Q6** E2E: external marketplace purchase imports and notifies. **M**
|
||||
- [ ] **Q7** Facade tests for cart/checkout, moderation, Orders, Products, Users, Transactions, Monitoring — the domains about to get real backends carry the most regression risk with the least coverage. **L**
|
||||
- [ ] **Q8** Regression pattern for reactive flag/config reads that must track `bootstrapRevision()` — this bug class already bit us once and was invisible until specifically hunted. **S**
|
||||
- [ ] **Q9** Set a justified coverage floor and a CI gate. Deliberately unset today. **M**
|
||||
- [ ] **Q10** One real screen-reader pass (NVDA/VoiceOver). Never performed on this codebase — every accessibility claim to date is automated tree inspection only. **M**
|
||||
|
||||
### Track N — API namespace migration (§9.3)
|
||||
|
||||
Cheapest now, more expensive every phase. Decision in Sprint 0.1.
|
||||
|
||||
- [ ] **N1** Adopt `/api/v2/storefront/*`, `/api/admin/v2/*`, `/api/seller/v1/*`, `/api/identity/v1/*`, `/api/providers/v1/*`, `/api/integrations/v1/*`. **L** `[BOTH]`
|
||||
- [ ] **N2** Migrate today's flat unversioned endpoints (`/cart`, `/orders`, `/items`, `/category`, `/searchitems`) plus the separate `qrApiUrl` host. **L**
|
||||
- [ ] **N3** Agree the structured error envelope; today no interceptor reads error bodies at all. **M** (implementation lands in Sprint 0.2)
|
||||
|
||||
### Track Z — Pre-existing repo debt
|
||||
|
||||
Not in the plan, but real. Fold into whichever phase touches the same surface.
|
||||
|
||||
- [ ] **Z1** Dark-mode selector does nothing — nothing reads `data-theme-mode`. **S**
|
||||
- [ ] **Z2** "Site Layout" selector has no effect — `layout.type` is edited but never read. **S**
|
||||
- [ ] **Z3** Footer "Contacts" link has no content behind it. **S**
|
||||
- [ ] **Z4** `SeoService.setItemMeta()` exists but is **never called** — product pages ship only site-wide meta. **S**
|
||||
- [ ] **Z5** `og:locale` hardcoded to `ru_RU` regardless of active locale. **S**
|
||||
- [ ] **Z6** No JSON-LD structured data, no sitemap generation. **M**
|
||||
- [ ] **Z7** Hardcoded Russian payment-description fallback (`'Покупка на Маркетплейсе'`) in a multi-tenant product. **S**
|
||||
- [ ] **Z8** Brand colours fail WCAG AA — `--border-color` at 1.24–1.42:1 against a 3:1 requirement; status colours fail 4.5:1 as text. **Needs theme-owner sign-off, not just a code fix.** **M**
|
||||
- [ ] **Z9** Literal hex `#cdd6d5` in `stars.component.scss:10` with no token behind it. **S**
|
||||
- [ ] **Z10** Two large lazy chunks unaddressed: `project-editor` (~1.0 MB), `catalog-container` (~330–375 kB). Profile under real backend latency, not instant mock responses. **M**
|
||||
- [ ] **Z11** `navigation.header` is editable in the builder with zero runtime consumer — needs a product decision, not a wiring fix. **DEC**
|
||||
- [ ] **Z12** `catalog.navigationMode` renders a deliberate placeholder; the mega-menu / carousel / left-nav variants it implies do not exist. **DEC**
|
||||
- [ ] **Z13** `sellerId` typed as bare `string` instead of the `UUID` alias used elsewhere. **S**
|
||||
- [ ] **Z14** No shared breadcrumb component; the only breadcrumb logic is a local signal in the catalog container. **S**
|
||||
- [ ] **Z15** Duplicate search models under two module paths. **S**
|
||||
- [ ] **Z16** Consolidate the eight cross-linked Seller Management documents — at least three independently restate the same undecided unified-vs-split orders question. Do this **before** Phase 5 starts. **M**
|
||||
- [ ] **Z17** Angular 22 upgrade — researched, not started; needs a dependency fix and a Node bump. **Its own dedicated session, never bundled with feature work.** **M**
|
||||
|
||||
---
|
||||
|
||||
## Critical path
|
||||
|
||||
```
|
||||
Sprint 0.1 (decisions)
|
||||
└─> Sprint 0.2 (seams)
|
||||
└─> Phase 1 (money truth) ──────────────┐
|
||||
└─> Phase 2 (orders + notif) │
|
||||
└─> Phase 3 (offer split) │
|
||||
└─> Phase 4 (external ingestion)
|
||||
└─> 🚦 LAUNCH GATE
|
||||
Track A (analytics) ── starts at Phase 1, gates the launch ──┘
|
||||
Track S (RBAC/audit) ── starts at Phase 2, gates the launch ──┘
|
||||
Track Q (E2E) ── starts at Phase 1, evidences the gate ┘
|
||||
```
|
||||
|
||||
Phases 5–10 all sit behind the launch gate and can be resequenced by business priority. Phases 1–4 cannot.
|
||||
|
||||
**Single hardest dependency:** Phase 1 Sprint 1.3 needs the payment chain unfrozen. If that answer is "no", the programme stops at Sprint 0.2 and the plan's P0s cannot be delivered — that outcome should go back to them in writing, not be worked around.
|
||||
Reference in New Issue
Block a user