diff --git a/docs/architecture/foundation/README.md b/docs/architecture/foundation/README.md index f501ad3..d5afbf7 100644 --- a/docs/architecture/foundation/README.md +++ b/docs/architecture/foundation/README.md @@ -56,6 +56,7 @@ It is a platform runtime that must support unlimited tenants from one Angular ap - [Seller-Management-UX-Review.md](Seller-Management-UX-Review.md) — UX/accessibility review of the Phase 1 UI - [Seller-Management-Backoffice-Readiness-Audit.md](Seller-Management-Backoffice-Readiness-Audit.md) — per-module scoping/permissions readiness audit - [Seller-Management-Storefront-Audit.md](Seller-Management-Storefront-Audit.md) — `market.com`/`seller.market.com` storefront readiness audit +- [Seller-Management-Backend-Migration-Plan.md](Seller-Management-Backend-Migration-Plan.md) — full backend migration plan, module-by-module, phased ### Engineering Rule Documents diff --git a/docs/architecture/foundation/Seller-Management-Backend-Migration-Plan.md b/docs/architecture/foundation/Seller-Management-Backend-Migration-Plan.md new file mode 100644 index 0000000..099a823 --- /dev/null +++ b/docs/architecture/foundation/Seller-Management-Backend-Migration-Plan.md @@ -0,0 +1,567 @@ +# 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: + +- [Seller-Management.md](Seller-Management.md) — capability overview, + Implemented/Planned/Future legend +- [Seller-Management-Backoffice-Readiness-Audit.md](Seller-Management-Backoffice-Readiness-Audit.md) + — per-admin-module scoping facts +- [Seller-Management-Storefront-Audit.md](Seller-Management-Storefront-Audit.md) + — storefront/subdomain facts +- `BACKEND.md` §11 — the backend documentation this plan assumes as its + starting contract + +**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 /bootstrap` — **Minor 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` (`CartPaymentRequest` → `QrCreateResponse`), 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). + +### Search +- **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. **Products** — `seller_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. + +## Recommended implementation phases + +- **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."