From a8b2b4bf0bbcd50ca84d6be74fd564091b983d1e Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Mon, 13 Jul 2026 15:29:21 +0400 Subject: [PATCH] docs(project-editor): document Sprint 16 tabs, draft/publish gap, and validation rules --- docs/Project-Editor.md | 45 +++++++++++++++---- .../features/project-editor/FACTS.jsonl | 5 +++ 2 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 docs/context/features/project-editor/FACTS.jsonl diff --git a/docs/Project-Editor.md b/docs/Project-Editor.md index 5bad937..d8513fc 100644 --- a/docs/Project-Editor.md +++ b/docs/Project-Editor.md @@ -88,6 +88,14 @@ Future backend integration: - export JSON - import JSON - runtime preview without full browser refresh +- Languages (Sprint 16) + - add/remove supported locale + - set default locale + - generically syncs translation keys across static pages and navigation labels (`LocaleSyncService`) +- Navigation (Sprint 16) + - header navigation: add/remove/reorder/edit label/URL/visibility + - flat footer navigation: same actions + - grouped footer navigation (column-based) is read-only in this tab for now ## Preview Strategy @@ -120,15 +128,36 @@ Current widget editor supports explicit fields for: Other widgets use JSON props fallback until dedicated editors are added. -## Future Backend Endpoints +## Draft / Publish (Sprint 16) -Recommended future builder endpoints: -- `GET /builder/bootstrap` -- `PUT /builder/bootstrap` -- `POST /builder/bootstrap/preview` -- `POST /builder/bootstrap/validate` -- `POST /builder/bootstrap/import` -- `GET /builder/bootstrap/export` +There is still no backend draft/publish API. This sprint models it client-side +in `ProjectEditorFacade`: +- `status: 'draft' | 'published'` and `dirty` (diffed against the + last-saved snapshot) live in facade state. +- `save()` snapshots the current in-memory bootstrap as "last saved" (no + network call yet). +- `publish()` runs `ProjectValidator`, and if there are no issues, applies + the bootstrap via `PlatformRuntimeService.reloadFromBootstrap` and marks + status `published`. + +**Backend gap, not yet implemented:** real persistence needs +`PUT /builder/bootstrap/draft` and `POST /builder/bootstrap/publish` +endpoints so drafts/publishes survive a reload and are shared across editors. + +## Validation + +`ProjectValidator` (`services/project-validator.service.ts`) runs on every +render of the save bar: missing logo, no languages, invalid marketplace URL, +duplicate static-page slugs, empty homepage, a homepage widget with no +`type`, duplicate header navigation links, invalid theme colors. Publish is +blocked while any issue is present; Save is not. + +## Rich HTML editing + +Static page HTML is edited via `MarketplaceHtmlEditorComponent` +(`components/html-editor/`), a `contentEditable` + toolbar component with no +external dependency. It emits raw HTML on every change and never sanitizes — +sanitization remains a storefront-render concern. ## Constraints diff --git a/docs/context/features/project-editor/FACTS.jsonl b/docs/context/features/project-editor/FACTS.jsonl new file mode 100644 index 0000000..aee11ec --- /dev/null +++ b/docs/context/features/project-editor/FACTS.jsonl @@ -0,0 +1,5 @@ +{"id":"PE-20260713T010000Z-0001","subject":"project-editor-routing","predicate":"is","object":"flat routes under /edit/:section (no projectId — a project is the domain-resolved tenant); /builder and /project-editor redirect to /edit/general","src":["docs/superpowers/specs/2026-07-13-marketplace-project-editor-sprint16-design.md","src/app/app.routes.ts"],"status":"active","kind":"decision","updated_at":"2026-07-13T01:00:00Z","confidence":"high","tags":["project-editor","routing"]} +{"id":"PE-20260713T010000Z-0002","subject":"locale-sync","predicate":"is-implemented-by","object":"LocaleSyncService, which generically adds/removes a locale key across static page translations and navigation labels without per-field hardcoding","src":["src/app/features/project-editor/services/locale-sync.service.ts"],"status":"active","kind":"implemented","confidence":"high","updated_at":"2026-07-13T01:00:00Z","tags":["project-editor","i18n"]} +{"id":"PE-20260713T010000Z-0003","subject":"draft-publish-flow","predicate":"is","object":"client-side only (ProjectEditorFacade.status/dirty/save/publish) because no backend draft/publish endpoint exists yet; PUT /builder/bootstrap/draft and POST /builder/bootstrap/publish are the documented backend gap","src":["docs/Project-Editor.md","src/app/features/project-editor/facade/project-editor.facade.ts"],"status":"active","kind":"constraint","confidence":"high","updated_at":"2026-07-13T01:00:00Z","tags":["project-editor","backend-gap"]} +{"id":"PE-20260713T010000Z-0004","subject":"html-editing","predicate":"uses","object":"MarketplaceHtmlEditorComponent, a contentEditable + toolbar component with no external rich-text dependency; emits raw HTML, never sanitizes during editing","src":["src/app/features/project-editor/components/html-editor/marketplace-html-editor.component.ts"],"status":"active","kind":"decision","confidence":"high","updated_at":"2026-07-13T01:00:00Z","tags":["project-editor","html-editor"]} +{"id":"PE-20260713T010000Z-0005","subject":"navigation-tab","predicate":"supports","object":"header navigation and flat-list footer navigation (add/remove/reorder/edit); grouped-column footer navigation is read-only until a future sprint","src":["src/app/features/project-editor/sections/navigation-section.component.ts"],"status":"active","kind":"constraint","confidence":"high","updated_at":"2026-07-13T01:00:00Z","tags":["project-editor","navigation"]}