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>
33 KiB
Product Plan v3.1 — Delivery Plan (Phases → Sprints → Todos)
Companion to 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 §7marks 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
Categorytypes, both fed by the same/categoryresponse, 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.enabledcheck 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_PROVIDERandCATEGORY_REPOSITORY, or delete the dead mock branch. Today both silently ignoreuseMockData. 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 inCurrencyRatesService.convert(). L- Currency minor-units + rounding rules table (RUB/USD/EUR/AMD at minimum). M
- Delete browser-owned rates: remove
currencyRates.v1fromlocalStorageand the hardcodedDEFAULT_RATESfallbacks (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.amountand the per-itemprice[]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
PriceHistoryon 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,processedAtper 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]
Orderheader:marketplaceId, source, customer, currency, subtotal, discounts, delivery, total, paymentStatus, orderStatus. LOrderLinewithofferId, sellerId, skuSnapshot, titleSnapshot, qty, unitPriceMinor, lineTotalMinor, priceSnapshotId. MOrderEventtimeline: created, paid, seller notified, accepted, fulfilled, cancelled, refunded (§2.8). Closes our own "Real order audit trail" TODO. M- Real
AdminOrdersApiGatewayreplacing 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 Notificationentity:unread/read,severity,marketplaceId, entity type/id, deep link. MDeliveryAttemptlog 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
AdminOrderWatcherServicefrom 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
ProductontoOffer. L - Formalise
Product/Variant/SKU/Category(withattributesSchema, SEO) as content-only. L - Unify the admin mock product domain with the live storefront
Itemdomain — 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/archivedfor 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/soldcounted 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]
Fulfillmententity: manual / warehouse / pickup / digital;status, assignedTo, issuedAt/shippedAt, evidence where applicable. Onefulfil*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+ConnectorCredentialRefin 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→ internalOrder. 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/CartLineserver-side, keyed onofferId. ReplaceslocalStorage+ 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]
CheckoutSessionentity.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
PaymentIntentvia provider adapter; repeat click must not create a second intent. M- Guest-checkout on/off per tenant policy (§6.2). S
DeliveryOptionentity. M
Phase 7 — Payments hardening + reconciliation (P1-C)
Sprint 7.1 — Refunds [BOTH]
Refundas a first-class operation with reason, actor and order-line linkage.requestRefund(id)is a mock method today. L- Partial refunds;
refunded / partially_refundedstates. M
Sprint 7.2 — Reconciliation [BE] + [FE]
ReconciliationRecord; match onproviderPaymentId/ merchant reference / amount+currency fallback (§7.3). L — zeroreconcil*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. 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
MessagingEventkeyed toorderId. L
Sprint 8.5 — Notification Orchestrator + delivery conversation [BE] — new in v3.1
- Orchestrator routes
order.paidto 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
DeliveryAttempterror 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 against this — it overlaps registry and audit. M
- Consolidate
MarketplaceRefvs.TenantConfigif 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 → publishwith immutable published revisions; rollback creates a new revision (§8.3). L- Real builder persistence — today
apiEndpoints.builderis an empty placeholder and "publish" only promotes alocalStoragesignal. 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_notificationlatency, 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 storefrontItem.visitsor 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 returningof(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.
auditappears 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
/editand/backofficeneed 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 RUBmust not become160 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 separateqrApiUrlhost. 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.typeis 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:localehardcoded toru_RUregardless 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-colorat 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
#cdd6d5instars.component.scss:10with 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.headeris editable in the builder with zero runtime consumer — needs a product decision, not a wiring fix. DEC - Z12
catalog.navigationModerenders a deliberate placeholder; the mega-menu / carousel / left-nav variants it implies do not exist. DEC - Z13
sellerIdtyped as barestringinstead of theUUIDalias 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.