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.
This commit is contained in:
@@ -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-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-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-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
|
### Engineering Rule Documents
|
||||||
|
|
||||||
|
|||||||
@@ -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."
|
||||||
Reference in New Issue
Block a user