diff --git a/docs/context/adrs/ADR-0001-marketplace-platform-vision.md b/docs/context/adrs/ADR-0001-marketplace-platform-vision.md new file mode 100644 index 0000000..9a58ea2 --- /dev/null +++ b/docs/context/adrs/ADR-0001-marketplace-platform-vision.md @@ -0,0 +1,67 @@ +--- +id: ADR-0001 +title: Multi-tenant marketplace platform vision and config-driven architecture +status: active +date: 2026-07-13 +tags: ["architecture", "philosophy", "multi-tenant", "bootstrap"] +--- + +## Context + +This is not a single marketplace — it is a multi-tenant platform powering unlimited +marketplaces (e.g. electronics.example.com, books.example.com) from one codebase. +Every marketplace is configured from the backend via a bootstrap configuration +(`GET /bootstrap`). No marketplace-specific code may exist in the frontend. + +## Decision + +- The frontend (Angular 20, standalone components, Signals, RxJS, SCSS) is a pure + renderer. It owns render, navigation, interaction, validation, animations only. +- The backend (ASP.NET Core REST API) owns branding, pages, layouts, languages, + homepage, navigation, categories, products, footer, static pages, payment + configuration, and enabled features. +- Flow: Bootstrap → Runtime Provider → Configuration Store → Renderer → Widgets. + Nothing depends on build-time environments; everything depends on runtime + configuration. +- Bootstrap contains only data needed before the app starts (name, logo, colors, + languages, footer pages, homepage layout, navigation, enabled widgets). It must + never contain products, orders, cart, or users. +- Widgets never own page spacing — only their own internal layout. The renderer + owns sections, spacing, and page width. +- Homepage is composed from a configurable, ordered list of sections (Section + Engine): Hero, Categories, Featured Products, Banner, Latest Products, Custom + HTML, Newsletter, etc. +- All layouts (homepage, PLP, etc.) must be backend-configurable without frontend + changes. +- All user-facing text is translatable via a `translations.{lang}` shape, not a + flat `title` field. Adding/removing a supported language must automatically + expose/remove translation fields across all translatable objects, generically — + never per-field hardcoding. +- Static pages (About Us, Privacy, Terms, Contacts, Return Policy, Delivery, + custom pages) are backend-delivered HTML, multilingual, and drive the footer. +- Admin and storefront share a domain but are fully separate applications: the + marketplace bundle never ships admin code and vice versa. Bootstrap is public; + Admin is protected by JWT + roles/permissions + tenant isolation (Super Admin, + Marketplace Admin, Moderator, Editor, Support, Customer). + +## Coding rules + +- Never hardcode marketplace data or introduce marketplace-specific conditionals. +- Never use environment flags to drive UI — everything is config-driven. +- Keep components small; prefer composition and reusable widgets; never + duplicate layouts. +- Business logic lives in services/facades, not components. +- Prefer Signals and standalone components. +- Every new feature ships with docs: frontend docs, backend contract, bootstrap + updates, API examples, migration notes if needed. + +## Guiding question + +Before implementing anything: "Will this still make sense after 50 marketplaces +and 100 developers?" If not, redesign before coding. + +## Consequences + +Any feature (including the Sprint 16 Project Editor) must edit the same Bootstrap +model the storefront consumes — no parallel/duplicate configuration models are +permitted anywhere in the platform. diff --git a/docs/context/features/platform-vision/FACTS.jsonl b/docs/context/features/platform-vision/FACTS.jsonl new file mode 100644 index 0000000..49ebcf3 --- /dev/null +++ b/docs/context/features/platform-vision/FACTS.jsonl @@ -0,0 +1,6 @@ +{"id":"PV-20260713T000000Z-0001","subject":"platform","predicate":"is-architected-as","object":"multi-tenant marketplace platform powering unlimited marketplaces from one codebase, driven entirely by backend bootstrap configuration","src":["docs/context/adrs/ADR-0001-marketplace-platform-vision.md"],"status":"active","kind":"decision","updated_at":"2026-07-13T00:00:00Z","confidence":"high","tags":["architecture","multi-tenant"]} +{"id":"PV-20260713T000000Z-0002","subject":"frontend","predicate":"must-not","object":"contain marketplace-specific code, hardcoded marketplace data, or environment-flag-driven UI","src":["docs/context/adrs/ADR-0001-marketplace-platform-vision.md"],"status":"active","kind":"constraint","updated_at":"2026-07-13T00:00:00Z","confidence":"high","tags":["frontend","constraint"]} +{"id":"PV-20260713T000000Z-0003","subject":"bootstrap","predicate":"must-only-contain","object":"data needed before app start (branding, languages, homepage layout, navigation, enabled widgets, footer pages) and must never contain products, orders, cart, or users","src":["docs/context/adrs/ADR-0001-marketplace-platform-vision.md"],"status":"active","kind":"constraint","updated_at":"2026-07-13T00:00:00Z","confidence":"high","tags":["bootstrap","constraint"]} +{"id":"PV-20260713T000000Z-0004","subject":"translatable-fields","predicate":"must-be-modeled-as","object":"generic translations.{lang} map so adding/removing a language automatically exposes/removes translation fields across all translatable objects","src":["docs/context/adrs/ADR-0001-marketplace-platform-vision.md"],"status":"active","kind":"constraint","updated_at":"2026-07-13T00:00:00Z","confidence":"high","tags":["i18n","constraint"]} +{"id":"PV-20260713T000000Z-0005","subject":"admin-app","predicate":"is-isolated-from","object":"marketplace storefront bundle: admin code never ships to storefront and vice versa, though they may share a domain","src":["docs/context/adrs/ADR-0001-marketplace-platform-vision.md"],"status":"active","kind":"constraint","updated_at":"2026-07-13T00:00:00Z","confidence":"high","tags":["admin","security"]} +{"id":"PV-20260713T000000Z-0006","subject":"widgets","predicate":"must-not-own","object":"page spacing or page width; the renderer owns sections, spacing, and page width, widgets own only their internal layout","src":["docs/context/adrs/ADR-0001-marketplace-platform-vision.md"],"status":"active","kind":"constraint","updated_at":"2026-07-13T00:00:00Z","confidence":"high","tags":["widgets","layout"]} diff --git a/docs/superpowers/specs/2026-07-13-marketplace-project-editor-sprint16-design.md b/docs/superpowers/specs/2026-07-13-marketplace-project-editor-sprint16-design.md new file mode 100644 index 0000000..7420360 --- /dev/null +++ b/docs/superpowers/specs/2026-07-13-marketplace-project-editor-sprint16-design.md @@ -0,0 +1,175 @@ +# Sprint 16 — Marketplace Project Editor MVP + +Status: approved for planning +Date: 2026-07-13 +Related: [ADR-0001](../../context/adrs/ADR-0001-marketplace-platform-vision.md), [Project-Editor.md](../../Project-Editor.md) + +## Goal + +A client can open the editor for their marketplace, edit settings, save a +draft, preview, and publish — without touching JSON by hand. The editor edits +the same `BootstrapConfig` the storefront consumes. No parallel/duplicate +configuration model is introduced anywhere in this work. + +## Current state (as of this sprint) + +A working editor already exists at `/builder` +(`src/app/features/project-editor/`): `ProjectEditorPageComponent` + signal-based +`ProjectEditorFacade` (no NgRx), sections for general, branding, theme, header, +footer, homepage (already has drag-and-drop reordering), widgets, +static-pages (via `StaticPagesEditorComponent`), features, preview. Static +page HTML is edited via a plain `