Generated directly from source (every this.http.get/post/patch/put/delete
call across core/, features/admin/, api.service.ts) rather than written
from memory - a census, not a design doc.
47 already match an existing Phase/Track contract exactly. 24 are inferred
from this codebase's own REST conventions with no contract doc stating them
- each flagged in source at its call site, not just in this doc, so backend
sees the reasoning next to the code. 15 are legacy endpoints
(/category, /cart, /qr, /websession, ...) with no contract anywhere,
still live today.
Biggest concrete gap surfaced: three full admin domains (transactions,
monitoring, moderation) have real UI and real gateways calling
/api/admin/v2/{resource} by convention, with zero backend contract written
for any of them.
One real bug found and fixed while building this, not just flagged:
connector-api.gateway.ts's replay() called
POST /api/admin/v2/integrations/dead-letter/{id}/replay, omitting the
{connectorId} segment the contract's own path requires
(PHASE-4-CONNECTOR-FRAMEWORK-CONTRACT.md §7). Fixed the interface, both
gateway implementations, and the doc entry in the same pass - no callers
existed yet, so this shipped without ever being exercised by a UI.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adding a domain was a manual per-domain script run. With domains arriving
continuously that does not hold, so certificate issuance is now automatic.
HTTP already needed no work: the nginx catch-all serves any Host and the SPA
resolves its tenant from that header. Only TLS needed a name-by-name step.
Two mechanisms:
- setup-wildcard-tls.sh issues one DNS-01 wildcard for *.<apex>, after which a
new tenant subdomain is live over HTTPS with zero certificate work.
- sync-domains.sh reconciles tenant-owned domains against a desired list on a
10-minute timer: issues what is missing, skips certificates with >30 days
left, skips names already covered by the wildcard, waits out unpropagated
DNS, and caps issuance per run so a bad source cannot burn the weekly ACME
budget.
Safety properties worth stating: a failed fetch of the desired list aborts the
run rather than reading as "remove every domain"; removing a domain disables
its server block but keeps the certificate, so re-adding is instant; malformed
hostnames are rejected before reaching certbot or an nginx server_name.
The source is pluggable - a file today, the Phase 9 domain registry once it
exists, whose MarketplaceDomain statuses already match what this needs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was no CD: pushing to main deployed nothing, and deploys were a manual
copy onto the server. This adds the missing half.
- .github/workflows/deploy.yml - build, upload to a per-commit release
directory, swap the symlink atomically, reload nginx, verify over HTTP.
The swap only happens after the upload is verified to contain index.html,
so a failed deploy leaves the previous release serving.
- scripts/deploy/server-setup.sh - idempotent one-time provisioning: nginx,
certbot, ufw, and a key-only deploy user whose sole sudo right is
"systemctl reload nginx".
- scripts/deploy/add-domain.sh - per-domain server block plus TLS issuance,
run once a domain's A record resolves to the server.
- docs/DEPLOYMENT.md - setup order, required CI secrets, rollback, limits.
Also adds .gitattributes: the shell scripts were being checked out with CRLF
endings, which makes bash fail on the shebang line on Linux.
Host keys are pinned via DEPLOY_KNOWN_HOSTS rather than trusted on first use.
No credentials are committed; all four deploy secrets are supplied by CI.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A partner integration request landed for programmatic merchant-hierarchy
management (Company/Project/Store/PaymentPoint). Built the answer generically:
partner-specific behaviour is a PartnerProfile config row, and no partner name
appears in any entity, field, endpoint or status value.
New:
- docs/backend/PARTNER-PROVISIONING-API-CONTRACT.md - hierarchy, idempotency,
node-scoped public-key credentials, TEST/LIVE partition, routing context
- docs/context/adrs/ADR-0003-generic-partner-provisioning-api.md
Amended, because the schema impact must land before Phase 1 is implemented:
- Phase 1 gains RoutingContext on CheckoutSession/PaymentIntent/Payment,
frozen at checkout-session creation and immutable after
- Phase 7 gains routing on Refund/ReconciliationRecord, plus the rule that
seller settlement splits happen after routing, never as a hierarchy level
- Phase 9 gains Company/Project above Marketplace and PaymentPoint below it,
with a backfill sequence for existing marketplaces
- Track S gains partner credentials: public key only, node-scoped authority,
rotation with overlap, immediate revoke, audit coverage
Also: Track P (P1-P10) in the delivery plan, and backend ownership closed as
answered across the contract set.
Card payment was checked, not added - qr and card both already ship in
cart.component.ts with separate create paths and status pollers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Verdaccio registry introduced earlier is unreachable from CI (listens on
127.0.0.1:4873 behind a firewall allowing only 80/443/SSH), which broke the
architecture-governance workflow - its npm ci step could no longer resolve
@marketplaces/auth.
Packages are now published to git release branches (release/auth,
release/payment in vitanovaPackages) whose root is the package itself, and
installed with git+<repo>#release/auth. No registry, token, tunnel, or CI
secret - anonymous git read is enough.
- package.json: git dependency; .npmrc removed (no scope mapping needed)
- vitanovaPackages release.yml rebuilt to force-push release branches
- ADR-0001 amended with the distribution change and why the registry lost
- BACKEND-HANDOFF: added the multi-tenancy section (hostname -> tenantKey ->
per-tenant bootstrap config), corrected the install and deploy notes, and
recorded that no CD pipeline exists
- PACKAGE-EXTRACTION / PACKAGES-USAGE rewritten for the git-branch flow
Verified: npm ci, arch:check:boundaries, ng build, 103/103 tests, all with
no credentials configured.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- docs/backend/BACKEND-HANDOFF.md: single entry point for a backend dev -
reading order, verified infrastructure state (nginx running, Postgres
inactive, no API on :8080, no TLS, no DNS automation, no CI runner),
auth surface, and the day-one setup that is still outstanding
- docs/PACKAGES-USAGE.md: install, required DI providers, full exported
API for both auth mechanisms, and how to ship a package change
- PACKAGE-EXTRACTION.md now covers build/release/infra only and points at
the usage guide; CI section reflects the two real workflows
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Stood up Verdaccio (Docker, on the dev server) as a private npm registry
since no public registry/NPM_TOKEN exists yet. Published @marketplaces/auth
and @marketplaces/payment there, removed the local packages/ staging copy
from this repo, and switched marketplaces to install @marketplaces/auth
0.1.0 as a real npm dependency through the registry.
- .npmrc scopes @marketplaces to the Verdaccio registry (no token committed;
each installer/CI supplies its own via npm login or an env-injected token)
- Verified: fresh npm install, ng build, arch:check:boundaries, and full
test suite (103/103) all pass against the registry-installed package
- Registry is reachable only via SSH tunnel today (firewall allows 80/443/
SSH only); public/CI access is a follow-up decision, documented in
docs/PACKAGE-EXTRACTION.md
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- ADR-0001: decision to extract auth/payment into shared @marketplaces/* packages
- Scaffold packages/auth, packages/payment; @marketplaces/auth now holds the real
telegram (customer+admin QR/session) and ed25519 (future admin challenge/response)
auth implementation, pushed to sources.vitanova.network/sdarbinyan/vitanovaPackages
- Rewire ~30 call sites to import from @marketplaces/auth; delete migrated originals
from core/auth, core/admin-auth, services/, models/
- Replace environment coupling with AUTH_API_URL/TELEGRAM_BOT_USERNAME injection
tokens and isDevMode(); wired as file:packages/auth pending registry publish
- Add TRACK-S §8: bootstrap per-marketplace admin login + marketplace-scoped
sub-admin invite/role endpoints
- Build, arch:check:boundaries, and full test suite (103/103) all green
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Track A: analytics event pipeline (traffic/catalog/commerce/operational/
quality events), synthetic-traffic separation enforced server-side by
environment/token, never a client-settable flag.
- Track S: 17-role/3-scope RBAC enforcement, audit log, secrets, rate
limiting, step-up auth - closes this session's most serious finding
(admin role model is decorative today, any authenticated admin has
full access regardless of assigned role).
- docs/backend/README.md: index of all 12 contract docs (Phases 1-10 +
2 tracks) in build order, plus what's deliberately excluded (namespace
migration, per-connector adapters, extra payment providers) and the
one thing still genuinely open across all of them - backend ownership.
- Cross-linked from BACKEND-API-REFERENCE.md and the delivery plan so the
index is discoverable from either entry point.
This closes out documentation for every phase/track in
PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md that doesn't require a further business
decision. Nothing left undocumented on our side pending only implementation
and backend-ownership assignment.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Phase 8: Customer/ExternalIdentity/ContactChannel, VK ID OAuth 2.1/PKCE
built first per Sprint 0.1 ("do all after vk"), then OTP, then MAX/
Telegram bot linking, then the Notification Orchestrator + Delivery
Conversation State Machine. Hard rule carried through: bots never touch
financial statuses, only delivery fields via a dedicated Delivery Service.
- Phase 9: Marketplace/MarketplaceDomain/MarketplaceFeatureSet/
MarketplaceRevision, full Hostinger DNS automation sequence (snapshot
before change, never touch MX/SPF/DKIM/DMARC/CAA), lifecycle state
machine that must expose its own blocker on every transition, publish
model with orders/payments/inventory explicitly excluded from revisions.
- Phase 10: Gorbushka-class content entities (Shop/Service/Floor/
SchemePin/RentListing/News/Lead/MallSettings), explicitly lowest
priority and gated on Commerce Core being real first.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Phase 5: Seller Portal from scratch (zero backend bytes exist today) -
SellerOrganization/SellerUser/SellerMarketplaceMembership, all endpoints
scoped server-side to the unified-orders Fulfillment model from Phase 2.
- Phase 6: server-owned Cart/CartLine/CheckoutSession, extending Phase 1's
server-authoritative-amount contract into the cart itself. Replaces
localStorage/Telegram-CloudStorage cart persistence.
- Phase 7: Refund and ReconciliationRecord entities, settlement contract.
Flags additional payment providers (wallets/BNPL) as still an open
business decision - not blocking, schema is provider-agnostic already.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Continues the Phase 1 contract doc with the same wire-contract-only style.
All three build on Sprint 0.1's answered decisions - no further business
input needed to start implementation once backend ownership is confirmed:
- Phase 2: canonical Order/OrderLine/Fulfillment/OrderEvent per the unified
multi-seller decision (one Order, per-seller Fulfillment groups), event
bus, Notification Center contract.
- Phase 3: Product/Offer split, InventoryRecord, publish-time executability
validation (the mechanism behind "no branch may distinguish an inspector
from a normal buyer").
- Phase 4: generic config-driven connector framework per the "no fixed
marketplace list" decision - onboarding a new partner is configuration
against a fixed pipeline, not a bespoke integration.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
User answered 8 of 9 Sprint 0.1 blocking decisions (2026-08-17); backend
ownership stays open pending a clearer re-ask. Recorded and propagated:
- Payment chain unfrozen -> BACKEND-API-REFERENCE.md §7 and the Phase 1
contract doc's status banner both updated; Phase 1/6/7 unblocked.
- No fixed external-marketplace list -> Phase 4's connector framework
respecified as config-driven/generic; Sprint 4.2 retired as "per named
marketplace," replaced with a generic onboarding runbook.
- FX rate source: ours, in-house, as the default (not just a fallback) ->
Phase 1 contract's `source` field can read "internal" as the normal case.
- VK ID before OTP -> Phase 8 sprints resequenced (VK ID now 8.2, OTP 8.3).
- Multi-seller orders: unified -> Phase 3.3, Phase 5.2, and Z16 updated to
the resolved model (one Order, per-seller Fulfillment groups).
- "Fixed 5-second payment" claim: confirmed non-issue, PAYMENT_POLL_INTERVAL_MS
is already 5000 (real polling cadence, not an artificial delay).
- API namespace: new endpoints only (/api/v2/...), no forced migration of
legacy endpoints.
- Document version: v3.1 is canonical.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- models/category.model.ts: Category -> CategoryApiModel, disambiguated
from core/categories/models/category-domain.model.ts's Category (admin
domain shape). Removes a dead unused import in item.utils.ts along the
way. Only live consumer was services/api.service.ts, updated in place.
- BACKEND-API-REFERENCE.md §5: corrected two rows documenting the
TOKEN_EXPIRED/INVALID_SIGNATURE auth-error bug as still open - the fix
(reading error.error.code before falling back to HTTP status) is
already in auth.service.ts. Doc was stale, not the code.
- Sprint 0.2 audit: AdminRole duplication and the
PRODUCT_DATA_PROVIDER/CATEGORY_REPOSITORY dead mock branches were
already resolved in a prior pass - verified, no code change needed.
- docs/backend/PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md: new wire contract
for Money/FxQuote/PriceSnapshot/payment state machine, so backend can
start Phase 1 the moment the frozen payment chain is unblocked.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds InjectionToken + factory for Orders, Products, Users, Transactions,
Monitoring, Moderation (mirrors existing Categories/Dashboard pattern) and
repoints their facades plus the derived Analytics/Customers facades and
admin-order-watcher off the mock LocalGateway class directly. No behavior
change today - still resolves to the mock - but a real backend can now be
bound per domain with zero facade edits.
Docs: full gap analysis of Product Plan v3.1 against current repo state,
and a phased delivery plan (10 phases, 34 sprints, 5 tracks) breaking every
identified gap into scoped, sequenced work.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Removes all tracked repo documentation (root status docs, docs/,
docs/architecture/foundation/**, docs/archive/**, docs/context/BACKEND-AUDIT.md
+ adrs, src/assets/mock/README.md) and replaces it with:
- GAPS-AND-IMPROVEMENTS.md — role-based findings (user, PO, QA, backend,
accessibility, engineering) plus automated code-review passes over the
storefront and backoffice, each with file:line references. Findings only,
no fixes applied.
- BACKEND-API-REFERENCE.md — single consolidated backend contract: auth
(both mechanisms), bootstrap, pagination/sorting/filtering conventions,
error model, every live/mock-only endpoint with JSON examples, and the
admin-domain DI-token seam gaps.
Open items and unresolved decisions from the deleted docs (KNOWN-ISSUES,
PRODUCT_BACKLOG, SPRINT-PLAN-NEXT, Seller-Management audits, etc.) were
harvested into the two new files before deletion, not lost.
CLAUDE.md/AGENTS.md/GEMINI.md/.claude/ and docs/context/{INDEX,LOG,
MAINTENANCE,README}.md are untouched — confirmed gitignored, never part of
git history, outside this cleanup's scope.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Third attempt, done properly this time - first two were reverted
(one stopped cleanly on real conflicts, one botched sequencing and
deleted the old focus-trap before finishing the swap).
DialogComponent gains closeOnEscape/closeOnBackdropClick (default true,
backward-compatible with its 13 other call sites) and ariaLabel (for
dialogs with no visible title header). FOCUSABLE_SELECTOR now includes
iframe for the bank-payment panel's focus trap.
Cart wires closeOnBackdropClick=false on both dialogs (in-flight payment
shouldn't cancel on a stray click) and closeOnEscape tied to the bank
popup's open state, so Escape closes the nested bank iframe first and
falls back to the QR view - matches the original priority exactly.
Original geometry (500px QR modal/40px padding, 960x760 bank modal/
56-16-16 padding, both mobile breakpoints) preserved via :host ::ng-deep
overrides scoped per dialog instance - same pattern already used by
product-carousel-widget.component.ts.
cart.component.ts loses ~90 lines of hand-rolled ViewChild/HostListener/
focus-trap code - app-dialog owns all of it now.
Verified live in browser: dialog sizing/padding/aria-label correct at
mobile+desktop, backdrop-click confirmed inert, Escape-priority confirmed
(bank closes first, then QR), initial focus lands on close button.
83/83 tests pass, tsc/build clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@lucide/angular shipped its entire ~1500-icon set in the initial bundle
despite the app only using 85 named-imported icons - confirmed upstream
tree-shaking failure (sideEffects:false, clean named imports, single
non-splittable fesm file). Replaced icon-registry.ts/icon.component.ts
with hand-rolled inline SVG rendering of just the 85 used icons,
transcribed from lucide's own node data for pixel-identical output.
Zero call-site changes - AppIconName and app-icon's public API unchanged.
Also: karma-coverage wired (npm run test:coverage), baseline captured
in docs/SPRINT-PLAN-NEXT.md (32% statements / 18.5% branches).
Cart-modal -> app-dialog migration was attempted and reverted - real
conflicts (backdrop-close, nested-modal escape priority, iframe sizing),
documented in docs/FUTURE_FEATURES.md for a properly scoped follow-up.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
11MB of the ~14MB initial bundle is the full @lucide/angular icon set
despite clean named imports for ~85 icons - confirmed by build inspection,
previously undocumented (existing note only covered the two lazy chunks).
Root cause is upstream tree-shaking, not app code. Real fixes (package
upgrade or dropping the dependency) need sign-off before touching.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sprint G: audited every BootstrapConfig field for a real runtime consumer
(docs/DEAD-CONFIG-AUDIT.md). Wired 3 previously-dead editable fields:
footer.logoUrl, company.address.street/contacts.phone, catalog.suggestionsEnabled.
Remaining dead fields needing a business/design decision tracked in
PRODUCT_BACKLOG.md/KNOWN-ISSUES.md, not silently left.
Sprint H: 6 new spec files (test count 57 -> 83), covering ProjectEditorFacade
(undo/redo, draft persistence, publish gating), AdminAnalyticsFacade
(never-fabricate-a-number contract), and regression coverage for this
session's carousel/hero/profile-toggle fixes.
Sprint I: widget settingsSchema (declared in widget-manifest.json, never
validated) now enforced via a new lightweight schema check in
ProjectValidator, surfaced through the existing issuesByField pipeline.
Same check reused in diagnostics so editor and diagnostics can't disagree.
Verification: tsc clean, ng build clean, 83/83 tests pass, barry-cache
validate clean (2 pre-existing unrelated warnings only).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sprint E: homepage section editor now filters the layout-strategy picker
to each widget's widget-manifest.json supportedLayouts instead of always
showing all 5 strategies. columns field gated to widgets that read it
(hero, product-collection carousel).
Sprint F: closes client bug report (no items-per-page control, hero
carousel not manually/automatically scrollable, no 1-2 slide big-carousel
option). Product carousel item width now driven by layout.columns
(reused, was already editable but dead). Hero widget gains prev/next
arrows, touch swipe, and 1-2 panel mode via the same field.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sprint A: storefront header profile control (login/logout only, no menu),
wired to existing customer Telegram auth (AuthService).
Sprint B: backoffice/reports page, reuses AdminAnalyticsFacade (Sales,
Top Products, Marketplace Health cards + CSV export).
Sprint C: backoffice/settings page, admin UI density preference
(comfortable/compact), localStorage-persisted, applied to app-table
across all admin list pages.
Sprint D: admin bottom-nav Help -> mailto using existing supportEmail,
Documentation -> external link via new TenantConfig.documentationUrl.
AdminNavLink gains externalHref for non-routerLink nav entries.
Docs: docs/GLOBAL-SPRINT-PLAN.md tracks the full sprint breakdown.
docs/COMING-SOON-AUDIT.md removed, folded into docs/KNOWN-ISSUES.md.
docs/BACKEND.md updated with the new documentationUrl bootstrap field.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Principal-architect-level review of the entire Seller Management body
of work (7 prior docs + all touched code), verified against fresh
tsc --noEmit and arch:check runs, not recalled from memory.
Real bug found and fixed (in scope per this mission's "unless
absolutely required" carve-out - a one-line correctness fix to
already-committed code, not new feature work):
AdminSellerManagementPageComponent.sellerManagementEnabled read the
bootstrap snapshot once via a plain signal() at construction, not
reactively via bootstrapRevision() the way UiRuntimeFacade/SeoService
both correctly do elsewhere in this codebase. Fixed to computed() keyed
on bootstrapRevision(). Currently invisible (flag is always false,
signal was never even read in the template) but would have gone stale
the moment bootstrap ever reloaded with the flag true. tsc clean after
the fix.
Findings documented in Seller-Management-Final-Design-Review.md (no
Critical/High severity found anywhere):
- Medium: SellerConfig (bootstrap wire shape) and Seller/SellerBranding
(domain entity) are two unreconciled type hierarchies for the same
concept - self-flagged already in BACKEND.md SS11.6, restated here as
an independently-confirmed finding rather than letting it drift.
- Medium: no reusable capability-guard abstraction exists anywhere in
the codebase, despite ADR-009/ADR-011 both prescribing "check the
flag in one place" - ADR-009's own described FeatureFlagService was
never built. Fine with one consumer, a real drift risk the moment a
second one needs the same check.
- Medium: the flag's true branch has never been exercised, even
manually - every verification claim in this whole body of work was
tested at the flag's real value (false).
- Low/nice-to-have: sellerId typed as bare string instead of the UUID
alias used everywhere else in the new sellers domain; MarketplaceRef
vs TenantConfig overlap (deliberate, documented, but worth watching);
documentation-to-code ratio (8 docs, zero backend bytes) carries a
consolidation-burden risk, especially the Unified/Split-Orders
question restated independently in 4 different docs.
- Explicitly checked for and did NOT find: circular dependencies,
scattered tenant/seller conditionals, over-engineering relative to
the typed-models-only mandate, or any auth/payment code touched.
Verdict: not an unqualified "ready for implementation" - two Medium
findings should be resolved by decision/small build before real
backend work starts, not because they block anything today but
because both compound in cost the longer they're left unresolved.
Everything actually built (typed foundation, disabled-by-default flag,
Phase 1 UI, plus the bug this review fixed) is solid and ready to
stay exactly as-is. No Critical or High-severity issue found anywhere.
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.
docs/BACKEND_API.md no longer exists as a live file (merged into
BACKEND.md in an earlier consolidation pass, per that doc's own intro
- only docs/archive/BACKEND_API.md remains, historical only). This
mission's "update BACKEND_API.md" instruction is fulfilled by
extending the doc that actually supersedes it: new §11 "Seller
Management (Optional Capability)", added to the top-of-file table of
contents, no existing section renumbered or altered.
Every subsection explicitly tagged Implemented / Planned / Future,
matching the same legend used in docs/architecture/foundation/
Seller-Management.md (the frontend-side capability doc this section
is the backend counterpart to):
- 11.2 Future entities: Marketplace (Implemented, existing
TenantConfig unchanged), Seller/SellerBranding (Planned - frontend
types exist, no backend schema), SellerUser/SellerSettings/
SellerInvitation (Future - no type, no concept, named for roadmap
completeness only).
- 11.3 Future endpoints: Seller CRUD/Activation/Invitations/Branding/
Analytics/Dashboard - all Future, none designed, each noted as
following the existing mock-to-API-gateway pattern (SS8) once built.
- 11.4 Authentication: SellerPermissionRole (4 roles) explicitly
flagged as a separate vocabulary from the existing, live AdminRole -
not merged, no guard wired, zero auth change.
- 11.5 Domain resolution: market.com -> Marketplace is Implemented
today (ADR-001, backend-Host-resolved); nike.market.com -> Marketplace
-> Seller is Future, no backend resolves it - and per the storefront
audit, needs no frontend routing change once it does.
- 11.6 Bootstrap additions: modules/modules.sellerManagement documented
as Implemented-as-contract (typed, always false/absent today);
sellerScope/sellerBranding as Planned with an explicitly flagged open
question (SellerConfig vs SellerBranding nesting not reconciled);
permissions noted as existing/unrelated today.
- 11.7 Checkout modes: Unified Order vs Split Orders - Future, not
designed, flagged as the single most consequential undecided item
for backend design given payments/refunds/reporting all depend on it.
- 11.8 Product ownership: sellerId? on Item/AdminProduct/AdminOrder -
Implemented as schema only (optional, absent = marketplace-owned,
verified backward-compatible via tsc staying clean). Existing
products remain valid with no migration required - NULL/absent
ownership documented as a permanent state, not transitional.
No backend implemented. No frontend code touched. Documentation only.
Audit only, no code changed - facts gathered by reading current
source (routes, containers, header/footer, SeoService), not assumed.
Covers Homepage, Categories, Products, Search, Favorites, Cart,
Checkout, Reviews, SEO, Breadcrumbs, Header, Footer.
Core finding: tenant resolution is already entirely backend-side by
request Host (ADR-001) - the frontend just consumes whatever bootstrap
comes back for whatever hostname it's running on. A seller subdomain
is architecturally closer to already working than any part of the
Backoffice audit found; the real gaps are all about whether the
*data* rendered carries a seller-aware value, not about routing/
hosting.
Key findings:
- Canonical URLs already correct today - SeoService.siteUrl derives
from location.origin dynamically, not hardcoded. Nothing to change.
- Header/Footer/SEO branding all read through one shared facade
(UiRuntimeFacade.reloadFromBootstrap()) - a single future injection
point that would cascade to all three for free, rather than three
separate fixes.
- SeoService.setItemMeta() (per-product OG/canonical tags) is defined
but never called anywhere in the codebase today - a pre-existing
dead hook, unrelated to seller-scoping but blocking any future
per-product/per-seller SEO work until wired.
- No dedicated breadcrumb component/service exists anywhere in the
storefront - the only breadcrumb logic in the app is one local
signal in catalog-container.component.ts.
- Checkout is not a separate route - it's an inline popup flow in
cart.component.ts, with no multi-vendor/multi-seller cart concept
at all. This is where Checkout Modes and Unified/Split Orders (both
marked Future in Seller-Management.md) would actually need to land.
- Structured data (JSON-LD) and sitemap generation don't exist for
anyone today, marketplace or seller - net-new work either way, not
seller-specific gaps.
- One pre-existing, unrelated issue noted in passing: og:locale is
hardcoded 'ru_RU' in SeoService - flagged, not fixed (out of scope).
Linked from docs/architecture/foundation/README.md alongside the
other Seller Management docs.
Audit only, no code changed - every fact gathered by reading current
facades/gateways/components on this branch, not assumed. Covers all
13 admin modules (Dashboard, Products, Categories, Orders, Customers,
Users, Analytics, Reviews/Moderation, Media, CMS, Builder, Settings,
Monitoring, Transactions).
Per module: answers the 3 readiness questions (does Marketplace Owner
see everything / would Seller see only their own / would Seller Staff
be limited), documents where a future scope would be injected (an
existing method/interface parameter to extend - no "if seller" checks
introduced anywhere), lists components that currently assume global
ownership, and classifies Ready / Needs scope / Needs permissions /
Needs API change.
Key findings:
- Only 3 of 13 gateways (Categories, Dashboard-metrics, Media) are
DI-token-swappable today; everything else needs that seam added
first, independent of seller scoping.
- Orders is the load-bearing blocker: Customers, Transactions, and
half of Analytics all derive from its same unscoped full-fetch order
list, and AdminOrderItem has no per-item seller attribution at all -
the concrete gap behind Seller-Management.md's open Unified-vs-Split-
Orders question.
- Users already carries an AdminUserScope/AdminRole concept (label-
only today) - the natural future home for the Marketplace Owner/
Seller/Seller Staff/Platform Admin role vocabulary.
- CMS/Static Pages and Builder/Project Editor are structurally not
about data scoping at all (marketplace-wide content, single global
config document respectively) - seller-level work there is new
product surface, not an extension.
- No admin module anywhere does role-based hiding of buttons or data
today - confirmed, not assumed.
Linked from docs/architecture/foundation/README.md alongside the
other Seller Management docs.
Master entry-point doc (Seller-Management.md) consolidating everything
built across the prior 4 commits (ADR-011, domain models, Phase 1 UI,
UX review) plus the full roadmap, with every section explicitly
tagged Implemented / Planned / Future so nothing reads as built that
isn't.
Covers: Overview, Architecture & Hierarchy, Marketplace, Seller,
Roles & Permissions, Feature Flags, Bootstrap, Future API, Seller
Storefronts, Seller Branding, Seller Ownership, Checkout Modes,
Unified/Split Orders, Migration & Compatibility (why existing
marketplaces stay unchanged, with the concrete verification evidence
for each claim), Developer Notes, Builder Notes, Backend Notes.
Explicitly marked Future (not designed, no shape decided) rather than
documented as if real: the API surface, seller storefronts, checkout
modes, and the unified-vs-split-order decision - none of these have
any code or ADR behind them yet, unlike the typed models/feature flag/
Phase 1 UI which are genuinely Implemented.
Added a rollout-stage diagram (types+flag -> Phase 1 UI -> backend
decisions -> CRUD -> branding/storefronts -> checkout modes) showing
work stops after "Phase 1 UI" today. Linked as the entry point from
docs/architecture/foundation/README.md and docs/PROJECT_INDEX.md,
ahead of ADR-011/diagrams/domain-models/UX-review which stay as
detail references.
No code changed.
Reviewed the Phase 1 UI against every other Backoffice page. Found and
fixed 2 real issues; everything else verified already consistent
(built entirely from shared components, so hover/focus/dialog-a11y/
dark-readiness/contrast come from those components, not reinvented).
Fixed:
- Message textarea had no id/aria-describedby wiring (app-input
self-wires this via injected FormFieldContext; the raw textarea -
no dedicated textarea component exists yet - never got it, so the
visible label's `for` pointed nowhere). Added explicit aria-label
bound to the same translation key as the visible label.
- Learn More dialog's feature list would render native browser
bullets (no global list-style reset exists outside details>summary
in styles.scss). Replaced with checkCircle icon + text rows,
consistent with how the rest of the app pairs icons with list/status
meaning.
Added docs/architecture/foundation/Seller-Management-UX-Review.md
documenting both fixes plus everything checked and confirmed already
consistent (empty-state usage, icon reuse, translations completeness
across en/ru/hy, responsive at 1280px/375px, dialog a11y verified via
accessibility tree not assumed).
tsc --noEmit clean, arch:check (boundaries + cycles) clean. Live-
verified: Learn More dialog shows all 6 items each with an icon
(confirmed via DOM query), textarea aria-label confirmed
"Сообщение", no console errors.
Typed models only, per mission. Nothing outside the new files reads
or writes any of this yet.
New core/sellers/models/ (mirrors core/products/models,
core/auth/models convention):
- MarketplaceRef - minimal {id,slug,name} reference from a seller
back to its marketplace, distinct from bootstrap's TenantConfig.
- SellerStatus - 'pending'|'active'|'suspended'|'disabled', no
transition logic.
- SellerScope - {sellerId, marketplaceId}, domain-level counterpart
to BootstrapConfig.seller (SellerConfig from the ADR-011 pass).
- SellerBranding (+SellerContact/SellerAddress/SellerThemeOverrides)
- logo/banner/description/contacts/address/theme overrides, every
field optional. Marketplace branding/theme remain default;
nothing consumes this yet.
- SellerPermissionRole/SellerPermissions - marketplaceOwner/seller/
sellerStaff/platformAdmin. Separate vocabulary from the existing
AdminRole (core/auth/models/permission.model.ts) - not merged, not
wired into any guard, zero auth behavior change.
- Seller - the eventual entity, composed from the above.
Changed (optional-only, verified backward compatible):
- Item (models/item.model.ts) gained sellerId?: string
- AdminProduct (features/admin/products/models/) gained
sellerId?: string
- AdminOrder (features/admin/orders/models/) gained sellerId?: string
Absent means marketplace-owned in every case, exactly like every
existing product/order today. No consumer of any of these three
models needed updating. AdminOrderItem (per-line-item ownership) and
the existing PermissionsConfig/AdminRole system were deliberately not
touched - out of scope for this pass.
Added docs/architecture/foundation/Seller-Management-Domain-Models.md
documenting every new type, every changed field, and the explicit
non-goals list. Linked from the foundation README alongside ADR-011
and the diagrams doc.
tsc --noEmit clean, arch:check (boundaries + cycles) clean.
Pointer-only updates, no rewrite: added ADR-011 to both docs' existing
ADR lists/counts, plus a one-line Seller Management entry in
PROJECT_INDEX.md's capability summary noting it's typed-foundation-
only, disabled by default, not implemented.