Files
marketplaces/docs/architecture/foundation/Seller-Management-Backend-Migration-Plan.md
sdarbinyan 9e9c11dff2 docs: Backend Migration Plan for Seller Management
Documentation only, no code. Synthesizes the 3 prior audits
(Seller-Management.md, the Backoffice readiness audit, the Storefront
audit) plus BACKEND.md SS11 into one migration plan covering all 17
requested modules: Authentication, Authorization, Bootstrap, Products,
Categories, Orders, Payments, Transactions, Reviews, Analytics, Media,
Search, CMS, Builder, Settings, Notifications, Emails, Audit Logs.

Per module: current behavior, future behavior, migration strategy,
backward compatibility, risk, effort, and an endpoint classification
(No change / Minor change / Major change / New endpoint) grounded in
facts already established in the prior audits - no new exploration,
no invented specifics.

Headline finding: Orders (the Unified-vs-Split-Orders decision) is the
single highest-risk, most consequential item in the whole plan -
payments/refunds/reporting all depend on it, and it can't be resolved
by an additive field the way every other domain's seller-scoping can.
Payments stays untouched (ADR-010, frozen) under the Unified path;
only Split Orders would ever touch the payment flow, and only then
with the same scrutiny the original frozen implementation got.

Cross-cutting sections included per mission: Database changes
(one nullable seller_id column touches existing tables, everything
else is new tables - no NOT NULL migration ever required), Permission
changes, Caching (bootstrap cache key must include resolved seller
identity), Indexes, Security (seller-to-seller isolation treated with
tenant-isolation rigor), Performance, API Versioning (ties to the
already-open BACKEND.md SS2.10 decision), Migration order (14 numbered
dependency steps), and 6 recommended implementation phases (A:
Foundation through F: Operational polish).

Every phase explicitly re-asserts the non-negotiable constraint:
modules.sellerManagement.enabled=false must show zero behavioral
difference before/after each phase ships.

Linked from docs/architecture/foundation/README.md alongside the
other Seller Management docs.
2026-07-26 22:49:07 +04:00

30 KiB

Seller Management — Backend Migration Plan

Documentation only. No code, no implementation. This plan synthesizes the three prior audits — do not re-derive facts already established there, read them for detail:

Non-negotiable constraint repeated from the mission, and load-bearing for every classification below: existing marketplaces without sellers must continue working exactly as today. Seller Management stays optional forever, not just at launch. No endpoint may require seller support unless modules.sellerManagement.enabled is true. Every classification and every migration strategy in this document is written to satisfy that constraint first — where a module can't satisfy it without a structural rework, that's called out explicitly, not glossed over.

Endpoint classification legend

  • No change — endpoint's request/response/behavior is untouched.
  • Minor change — an optional field/parameter added (e.g. sellerId? in a filters object or DTO); absent value behaves identically to today.
  • Major change — data model or endpoint semantics change beyond an optional field (e.g. a new join, a new required decision like split orders, a new aggregation dimension).
  • New endpoint — doesn't exist today, net-new surface.

Module-by-module

Authentication

  • Current: Two live mechanisms (BACKEND.md §4) — Telegram/QR customer session login (live), Ed25519 admin challenge/response (built client-side, not wired live). No seller concept in either.
  • Future: SellerPermissionRole (marketplaceOwner/seller/ sellerStaff/platformAdmin) as a role a session can carry, and a decision on whether Seller/Seller Staff authenticate via a third mechanism or reuse Telegram/Ed25519 with a different claim.
  • Migration strategy: additive only — a new optional claim/role field on the existing JWT structure (§4 §3), never a new auth mechanism forced onto existing flows. Existing customer and admin login must not gain any new required step.
  • Backward compatibility: total, if done as an additive claim. A session with no seller claim today is indistinguishable from a session before this work existed.
  • Risk: Medium — auth is the most consequence-sensitive surface in the app (ADR-010 froze it once already); any change here needs security review, not just a schema add.
  • Effort: Medium (claim/role addition) once the role-vs-AdminRole reconciliation decision (§11.4) is made; that decision itself is the bigger unknown, not the wiring.
  • Endpoint classification: existing login/verify/refresh/logout — Minor change (optional claim), contingent on the role decision above. New seller-specific login/enrollment flow (if Seller/Seller Staff need one) — New endpoint, Future, not designed.

Authorization

  • Current: Coarse AdminRole (Owner/Manager/Support/ReadOnly) mapped to backoffice.read/backoffice.write/builder.read/builder.write/ settings.manage (§4 §9.1). No route currently enforces even this — the admin role model exists but nothing gates on it yet (confirmed by the Backoffice audit: "no admin module anywhere does role-based hiding of buttons or data today").
  • Future: SellerPermissionRole layered in, deciding whether it extends or sits alongside AdminRole.
  • Migration strategy: since authorization enforcement doesn't exist yet even for the current roles, there is no existing enforcement to break — this is genuinely additive design space, not a migration of live behavior.
  • Backward compatibility: trivial today (nothing to preserve because nothing enforces roles yet) but becomes a real compatibility question the moment AdminRole enforcement is eventually added — sequence matters: whichever role model ships first should be designed with the other in mind, or the second one becomes a breaking migration of the first.
  • Risk: Low today, Medium if sequenced wrong — the risk is entirely about doing AdminRole enforcement and SellerPermissionRole design in the wrong order, not about either individually.
  • Effort: Low to design (no live behavior to preserve); Medium to implement once both role systems' relationship is decided.
  • Endpoint classification: all admin endpoints — No change today (no enforcement exists to change); Major change whenever role-enforcement is added generally, seller-aware or not.

Bootstrap

  • Current: GET /bootstrap, backend resolves tenant by Host (ADR-001, §1). BootstrapConfig already has optional modules?/seller? fields (§11.6), always absent/false — no backend populates them.
  • Future: backend resolving {seller}.{marketplace-domain} (§11.5) and populating modules.sellerManagement.enabled + seller for a real seller-scoped request.
  • Migration strategy: the fields already exist and are optional — the only backend work is populating them correctly for a resolved seller scope, not adding new frontend-facing shape. Existing marketplaces' bootstrap responses need zero changes; they simply never populate the new fields.
  • Backward compatibility: already verified — these are optional fields added to a live contract with zero consumer changes required (confirmed tsc --noEmit clean at the time they were added).
  • Risk: Low — this is the best-prepared module in the whole migration, precisely because the frontend contract was already extended in advance without needing backend cooperation.
  • Effort: Medium — the resolution logic (subdomain → seller lookup) is new backend work, but the response shape is already spoken for.
  • Endpoint classification: GET /bootstrapMinor change (two new optional response fields to populate, conditionally).

Products

  • Current: No real backend yet (§8) — mock gateway. AdminProductListFilters already has search/categoryId/visibility/stock/includeArchived/sort/page/pageSize. Item/AdminProduct already carry optional sellerId? (§11.8), read/written by nobody today.
  • Future: sellerId filter on list endpoints; ownership enforcement on create/update/delete once a real seller session exists.
  • Migration strategy: add sellerId as one more optional field to the existing filters object and DTOs — the field already exists in the frontend type, so there's no frontend change required at all, only backend query logic (WHERE seller_id = ? OR seller_id IS NULL pattern or equivalent) gated behind the feature flag.
  • Backward compatibility: guaranteed at the frontend type level already; backend guarantee depends on making the new column/filter nullable and defaulting existing rows to NULL (marketplace-owned) — see Database changes below.
  • Risk: Low for the filter addition; Medium for ownership enforcement (a bug here could hide a marketplace owner's own products from themselves, or leak a seller's products to another seller).
  • Effort: Small (list/filter) once the DI-token seam this domain currently lacks (per Backoffice audit) is added — that seam is independent prerequisite work, not seller-specific.
  • Endpoint classification: list/get — Minor change. Create/update (ownership assignment) — Minor change if sellerId is just an optional write field; Major change if ownership transfer or seller-side write restrictions are added.

Categories

  • Current: The most backend-mature domain — real HTTP already (AdminCategoriesApiGateway, DI-token-bound, §3.2). Facade currently hardcodes a full unfiltered fetch and does all real filtering client-side to preserve tree parent/child chains (Backoffice audit finding).
  • Future: categories are conceptually marketplace-wide (shared taxonomy) — the real future question is scoping products within a category by seller, not scoping categories themselves.
  • Migration strategy: likely no backend change at all for Categories proper; ownership scoping happens one level down, at Products.
  • Backward compatibility: trivial — no change anticipated.
  • Risk: Low.
  • Effort: Low (frontend-only fix: the facade's hardcoded full-fetch pattern, unrelated to backend).
  • Endpoint classification: No change anticipated.

Orders

  • Current: AdminOrderListFilters has search/status/page/pageSize; AdminOrder has optional sellerId? (§11.8) at the order level. AdminOrderItem (per-line-item) has no seller attribution field at all — the concrete gap behind Checkout Modes (§11.7).
  • Future: per-item seller attribution, plus the Unified-vs-Split-Orders decision (§11.7) — the single most consequential undecided item in this entire plan.
  • Migration strategy: cannot be resolved by an additive field alone. Unified Order path: add optional sellerId to each order-item row (minor, additive). Split Orders path: checkout must decide, at creation time, whether to write N order records instead of one for a multi-seller cart — that changes POST /orders' semantics for any cart containing mixed-seller items, which is a major change regardless of how carefully it's gated, because "how many order records does this checkout produce" is not optional-field-shaped.
  • Backward compatibility: guaranteed for any cart containing only marketplace-owned items (the only kind that exists today) under either path. The compatibility risk is entirely about new multi-seller carts, which cannot exist until Products have real seller ownership — so there is a natural sequencing safety net here, not just a promise.
  • Risk: High — this is the highest-risk item in the whole plan. Payments, refunds, and financial reporting all depend on the Unified-vs-Split decision; getting it wrong after sellers exist means a breaking change to live financial data, not a code refactor.
  • Effort: Large — this decision should be made and locked before any seller onboarding is possible, not discovered mid-rollout.
  • Endpoint classification: GET /orders (list/filter) — Minor change. POST /orders (create) — Major change (semantics change based on the Unified/Split decision). PATCH status transitions — likely Minor change if orders stay 1:1 with a single seller scope (Split path) or Major change if partial per-seller status exists within one unified order.

Payments

  • Current: Frozen (ADR-010) — Telegram QR/card payment flow, POST /cart (CartPaymentRequestQrCreateResponse), status polling. Explicitly preserved unchanged through every prior platform-refactoring pass in this codebase's history.
  • Future: if Split Orders is chosen (§ Orders above), a single checkout may need to create multiple payment records or split a captured payment across sellers — a genuinely new payment-flow shape, not a parameter addition.
  • Migration strategy: do not touch the frozen flow for the Unified Order path — a unified order with mixed-seller items can still use today's exact single-payment flow, only the order record differs internally. Only the Split Orders path forces any payment-flow change, and even then, the existing flow should remain the path for seller-disabled marketplaces with zero exceptions.
  • Backward compatibility: absolute requirement, restated from ADR-010 — this is the one area of the whole codebase with an explicit prior "freeze, do not redesign" decision, and Seller Management does not override it.
  • Risk: High if Split Orders is chosen — payment/financial flows are the least forgiving place for a design misstep in this entire system.
  • Effort: Large, only if Split Orders is chosen; zero for Unified Order.
  • Endpoint classification: No change under Unified Order. Major change or New endpoint under Split Orders (undecided, Future).

Transactions

  • Current: Derived entirely from the same unscoped Orders list (AdminTransactionsLocalGateway mirrors AdminOrdersLocalGateway's pattern, Backoffice audit finding). AdminTransactionListFilters has search/status/type/page/pageSize.
  • Future: per-seller transaction filtering/reporting.
  • Migration strategy: inherits whatever Orders decides — Transactions cannot be scoped correctly until Orders resolves per-item seller attribution (§ Orders above). Adding a sellerId filter here today would be cosmetic without that prerequisite.
  • Backward compatibility: same guarantee as Orders — blocked on the same prerequisite, not an independent risk.
  • Risk: Medium — inherits Orders' risk one level removed (financial reporting, not the payment flow itself).
  • Effort: Small once Orders is resolved; not independently schedulable before that.
  • Endpoint classification: Minor change (filter field), contingent on Orders' Major change landing first.

Reviews

  • Current: Storefront submission is live; admin moderation (AdminModerationGateway) is mock-only. AdminReviewListFilters has search/status/rating/page/pageSize. Reviews carry productId — no direct seller field.
  • Future: a seller sees reviews on their own products, via a join through Products' sellerId, not a new field on the review itself.
  • Migration strategy: add sellerId as a filter that internally joins through the product's ownership — additive at the API surface, but implemented as a join, not a stored column on reviews.
  • Backward compatibility: total — the filter is purely additive and optional.
  • Risk: Low.
  • Effort: Small, contingent on Products having real sellerId data to join against.
  • Endpoint classification: review list/detail — Minor change. Reports (loadReports(), currently bare no-arg, no filters object at all) — Minor change too, but requires adding a filters parameter that doesn't exist on the endpoint today, so slightly more surface than the reviews list.

Analytics

  • Current: No aggregation endpoint exists at all (§3.20) — every number (revenue, top products, health, recommendations) is computed client-side by summing the entire orders/products/categories/reviews corpus. This gap exists independent of Seller Management.
  • Future: per-seller analytics, requiring the underlying domains (Orders, Products, Reviews) to be seller-scoped first, then a real aggregation endpoint partitioned by seller.
  • Migration strategy: do not attempt to seller-scope analytics before a real aggregation endpoint exists for the marketplace as a whole — that is a prerequisite gap, not a Seller Management task. Once it exists, seller-partitioning is an additional dimension on the same aggregation query, not a new endpoint family.
  • Backward compatibility: unaffected — a marketplace with no sellers gets marketplace-wide aggregates exactly as it always has, whenever the real aggregation endpoint is eventually built.
  • Risk: Medium — mostly the risk of building the wrong aggregation shape before seller-partitioning is even a consideration, and having to redo it.
  • Effort: Large — this is explicitly the last domain recommended for real backend work in BACKEND.md §9, and Seller Management adds a further dimension on top of an already-large lift.
  • Endpoint classification: New endpoint (the aggregation endpoint itself doesn't exist yet, seller-aware or not).

Media

  • Current: MediaRepository abstract class, DI-token-bound already (mock live, ApiMediaRepository not yet written). MediaListParams already accepts page/pageSize/search/folder/kind/sort. MediaAsset has no owner/uploader field at all.
  • Future: sellerId filter, requiring an owner field added to MediaAsset first.
  • Migration strategy: two small additive changes — a new optional sellerId/ownerId field on the asset model, and a matching optional filter field on MediaListParams. This module and Categories are the two best-positioned in the entire audit for a low-risk addition.
  • Backward compatibility: total — both changes are optional-field additions to an already-flexible params object.
  • Risk: Low.
  • Effort: Small.
  • Endpoint classification: list — Minor change. Upload/update (§7) — Minor change (one new optional field in the request body).
  • Current: Standard search contract exists (§2.5) as a framework convention (keyword, no dedicated backend endpoint beyond catalog list filtering — /search reuses the same catalog container/endpoint as /catalog per the Storefront audit). No autocomplete/trending endpoint exists; explicitly flagged as its own open "Requires backend decision" in §2.12.
  • Future: filtering search results by seller scope, same mechanism as Products (search is not architecturally distinct from catalog browsing today).
  • Migration strategy: inherits Products' migration entirely — no separate search-specific backend work anticipated beyond what Products already needs.
  • Backward compatibility: total, same guarantee as Products.
  • Risk: Low.
  • Effort: None beyond Products — not independently schedulable.
  • Endpoint classification: Minor change, identical to Products' classification (same underlying endpoint).

CMS (Static Pages)

  • Current: No backend call at all — reads/writes BootstrapConfig.staticPages in-memory (§1, §3.8). Marketplace-wide content (legal, about) by nature.
  • Future: conceptually does not apply — no per-seller static page concept exists in this document or in product intent. If sellers ever need their own content pages, that is new product surface, not an extension of this module.
  • Migration strategy: none anticipated. Flag if product strategy later decides otherwise — treat as a new capability, not a CMS migration.
  • Backward compatibility: unaffected — no change proposed.
  • Risk: None.
  • Effort: None.
  • Endpoint classification: No change.

Builder

  • Current: No backend write path at all (§1.10, §8) — draft/publish is localStorage-only, editing one global BootstrapConfig document per marketplace. The single strongest one-owner assumption in the codebase (Backoffice audit finding).
  • Future: a seller-scoped builder (per-seller storefront layout/ branding) would be an entirely new product surface built on a different premise than "one config document per marketplace" — not an extension of the existing builder.
  • Migration strategy: none proposed for the existing Builder. If a seller-facing builder is ever wanted, it should be scoped as its own ADR and its own backend surface, not bolted onto the marketplace Builder's existing draft/publish contract.
  • Backward compatibility: unaffected — no change proposed to the existing module.
  • Risk: None for the existing module; High if a future team attempts to retrofit seller-awareness into the existing single-document model rather than building fresh — flagged explicitly as an anti-pattern to avoid.
  • Effort: None now; a seller-facing builder, if ever built, is a large, independent effort, not a migration of this one.
  • Endpoint classification: No change to the existing (still nonexistent) builder write path. Any future seller-builder surface is New endpoint, Future, not designed.

Settings

  • Current: No route exists — comingSoon: true in the admin nav, no component backs it (confirmed, Backoffice audit).
  • Future: if Settings is ever built, it's the natural home for marketplace-level Seller Management configuration (e.g. enabling the module, default seller policies) — speculative, not designed.
  • Migration strategy: none — there's nothing to migrate.
  • Backward compatibility: not applicable.
  • Risk: None.
  • Effort: None attributable to Seller Management specifically.
  • Endpoint classification: No change — no endpoint exists.

Notifications

  • Current: A marketplace-facing feature flag exists (FeatureFlagsConfig.notifications: boolean) but this gates a storefront UI feature, not a backend notification/email service — no such service exists in this codebase for anyone today.
  • Future: seller onboarding (invitation accepted, application approved/rejected) would need real notification delivery — entirely net-new, not an extension of the existing flag.
  • Migration strategy: none — nothing exists to migrate.
  • Backward compatibility: not applicable.
  • Risk: Low (net-new work carries normal build risk, not migration risk).
  • Effort: Medium, whenever built — but zero today and not a prerequisite for anything else in this plan.
  • Endpoint classification: New endpoint, Future, not designed.

Emails

  • Current: No email-sending capability exists anywhere in this codebase.
  • Future: the mocked "Request Access" form on the Phase 1 UI (admin-seller-management-page.component.ts) implies a real email would eventually be sent on submission — today it's a setTimeout-mocked success dialog with zero delivery.
  • Migration strategy: none — nothing exists to migrate.
  • Backward compatibility: not applicable.
  • Risk: Low (net-new, not migration).
  • Effort: Small to Medium, whenever built (transactional email for one form submission is a contained scope).
  • Endpoint classification: New endpoint, Future, not designed.

Audit Logs

  • Current: Documented in BACKEND.md §5.14 as a proposed convention (structured audit-log entries with actor/action/target/timestamp) — no backend implementation confirmed to exist; this is itself already Planned/Future in the base backend doc, independent of Seller Management.
  • Future: any seller-specific action (seller created, activated, suspended, branding changed) should flow through the same audit-log convention once it exists, with an added seller-scope dimension on the log entry — not a parallel logging system.
  • Migration strategy: none specific to Seller Management beyond ensuring, whenever audit logging is built, that its schema includes an optional seller-scope field from day one rather than retrofitting it later.
  • Backward compatibility: not applicable — nothing exists yet to preserve.
  • Risk: Low.
  • Effort: None additional if sequenced correctly (add the field when audit logging is first built); Medium if audit logging ships first without it and needs a schema migration later.
  • Endpoint classification: New endpoint (audit log query surface, if one is ever exposed to admins) — Future, not designed.

Database changes

No schema exists yet for any of this (§8 — no backend implemented at all). Recommendations, not decisions:

  • A sellers table (id, marketplace_id, name, slug, status, branding JSON/columns, timestamps) — new table, no impact on existing schema.
  • A nullable seller_id foreign key on products/items and orders (or order-items, pending the Unified/Split decision) — nullable by design, defaulting existing rows to NULL (marketplace-owned). This is the one schema change that touches existing tables; every other addition is a new table.
  • A nullable seller_id/owner_id on the media-assets table, if Media ownership scoping is pursued.
  • No column should ever be added as NOT NULL without a default — that would force a backfill migration on existing data, which this plan's constraint explicitly rules out.

Permission changes

  • New sellers and seller_users (or equivalent) authorization checks — entirely new policy, not a modification of existing AdminRole checks (which, per the Backoffice audit, don't enforce anything yet regardless).
  • Existing admin/customer authorization paths: no change required for marketplaces with modules.sellerManagement.enabled = false.
  • Recommendation: implement seller-scoped authorization as an additional policy layer evaluated only when a request resolves to a seller scope (§11.5) — never as a modification of the existing marketplace-level policy evaluation path.

Caching

  • Bootstrap responses are already cached client-side per tenant (§1.7); a seller-scoped bootstrap response should be cached under a cache key that includes the resolved seller identity (e.g. keyed by full resolved Host, which it already effectively is), not the marketplace alone — otherwise a seller subdomain risks serving a cached marketplace-level response or vice versa.
  • No existing cache invalidation logic needs to change for marketplaces without sellers.

Indexes

  • sellers(marketplace_id) — every seller lookup is scoped by marketplace.
  • products(seller_id) / orders(seller_id) (or order-items equivalent) — nullable-column indexes; most databases index NULL efficiently, but this should be verified against the chosen database engine before assuming query performance is unaffected for the common (NULL) case.
  • No index changes required on any table for marketplaces that never populate seller_id.

Security

  • Seller-scoped data access is a new cross-tenant-adjacent boundary (a seller must never see another seller's data within the same marketplace) — recommend treating this with the same rigor as tenant isolation (§5.10/§4 §10), not as a lesser internal boundary.
  • The existing frozen payment flow (ADR-010) must not be reopened for the Unified Order path — only the Split Orders path (if chosen) touches payment security surface at all, and that touch should get the same security review rigor as the original payment implementation.

Performance

  • Analytics is already the heaviest computation path in the app (full client-side aggregation over the entire corpus, §3.20) — building the real aggregation endpoint this plan's Analytics section calls for should happen with seller-partitioning in mind from the start, to avoid a second heavy migration shortly after the first.
  • No performance regression is anticipated for marketplaces without sellers — every proposed change is either a new table/endpoint (zero cost when unused) or a nullable-field filter (negligible cost when the filter is never applied).

API Versioning

Already documented as an open, undecided item in BACKEND.md §2.10 (no path/header versioning scheme exists today). Recommendation specific to this migration: whichever versioning decision is made generally should land before any Seller Management endpoint ships, so new endpoints (Seller CRUD, Activation, Invitations, Branding, Analytics, Dashboard) are versioned consistently with the rest of the API from their first day, rather than being retrofitted later as the one inconsistent set.

Migration order

Strict dependency order, not a preference:

  1. Bootstrap (already prepared, lowest risk) — backend starts populating modules/seller fields for a resolved seller scope.
  2. Productsseller_id column + filter, the foundation every downstream domain depends on.
  3. Categories — confirm no change needed (likely true, low effort to verify).
  4. Media — independent, can happen in parallel with Products.
  5. Reviews — depends on Products (join through product ownership).
  6. Orders — the Unified-vs-Split-Orders decision must be made here, informed by Products already existing. This is the hard gate — nothing past this point should start before it's resolved.
  7. Payments — only touched if Split Orders is chosen; otherwise untouched, in parallel with everything above.
  8. Transactions — depends on Orders.
  9. Analytics — depends on Orders, Products, Reviews all being scoped; also depends on the pre-existing (non-seller-specific) real aggregation endpoint being built first.
  10. Authentication/Authorization — the SellerPermissionRole design and its relationship to AdminRole should be settled in parallel with steps 2-6, not deferred to the end, since Seller Activation and any real seller-facing endpoint depend on it.
  11. Seller CRUD/Activation/Invitations/Branding — depends on Authentication/Authorization being settled.
  12. Seller Dashboard/Analytics endpoints — last, depends on Analytics' real aggregation endpoint existing.
  13. Notifications/Emails/Audit Logs — can start any time after step 11 (Seller Invitations existing gives them something to notify about); not blocking anything else.
  14. CMS, Builder, Settings — no migration anticipated; revisit only if product strategy changes.
  • Phase A — Foundation (steps 1-4, 10 above): bootstrap population, Products/Categories/Media scoping, and the permission-role design done in parallel. Nothing customer-visible yet. Lowest risk, unblocks everything else.
  • Phase B — The hard decision (step 6, Orders): Unified-vs-Split-Orders locked before any real seller can transact. This phase is a design decision plus its implementation, not a feature — treat it as a gate, not a sprint item.
  • Phase C — Dependent domains (steps 5, 7, 8): Reviews, Payments (if Split chosen), Transactions — mechanical once Phase B lands.
  • Phase D — Seller-facing surface (step 11): Seller CRUD, Activation, Invitations, Branding — the first point where a seller account can actually exist and do something.
  • Phase E — Analytics & reporting (steps 9, 12): the largest single remaining lift, deliberately last since it depends on everything above.
  • Phase F — Operational polish (step 13): Notifications, Emails, Audit Logs — improves the experience of Phase D/E but blocks nothing.

At every phase boundary: re-verify the non-negotiable constraint. A marketplace with modules.sellerManagement.enabled = false must show zero behavioral difference before and after each phase ships. If a phase can't satisfy that, it isn't ready to ship — regardless of how much of it is "done."