diff --git a/docs/EDITOR.md b/docs/EDITOR.md index a83e257..330d599 100644 --- a/docs/EDITOR.md +++ b/docs/EDITOR.md @@ -10,6 +10,7 @@ src/app/features/project-editor/ sections/ one component per editor tab (see below) components/ shared editor UI (save bar, HTML editor) models/ ProjectEditorState, EDITOR_SECTION_BOOTSTRAP_KEYS + schema/ field-schema registry, validators/, history.util (Sprint X+1, see below) services/ ProjectValidator, ProjectEditorDraftStorageService, LocaleSyncService facade/ ProjectEditorFacade ``` @@ -18,7 +19,7 @@ Route: `/edit/:section` or `/{lang}/edit/:section`. ## Facade -`ProjectEditorFacade` exposes: `loadBootstrap()`, `updateBootstrap(updater)`, `exportBootstrap()`, `importBootstrap()`, `preview()`, `save()`, `publish()`, plus signals `bootstrap`, `status` (`draft|published`), `dirty`, `lastSavedAt`, `lastPublishedAt`, `validationIssues`, `homepageWidgets`, `homepagePage`. Components in `sections/*` inject this facade directly (an accepted exception to the presentational-component rule, per ADR-006 — these are container/section components, not shared UI). +`ProjectEditorFacade` exposes: `loadBootstrap()`, `updateBootstrap(updater)`, `exportBootstrap()`, `importBootstrap()`, `preview()`, `save()`, `publish()`, `undo()`, `redo()`, plus signals `bootstrap`, `status` (`draft|published`), `dirty`, `canUndo`, `canRedo`, `lastSavedAt`, `lastPublishedAt`, `validationIssues`, `blockingIssues`, `hasBlockingIssues`, `issuesByField`, `issuesBySection`, `modifiedFields`, `modifiedSections`, `changeSummary`, `homepageWidgets`, `homepagePage`, plus the `fieldError(key)` method. Components in `sections/*` inject this facade directly (an accepted exception to the presentational-component rule, per ADR-006 — these are container/section components, not shared UI). See "Configuration schema, form engine, and validation architecture" below for the schema/validator/undo internals. ## Sections @@ -46,9 +47,43 @@ Route: `/edit/:section` or `/{lang}/edit/:section`. - **Per-field reset is not implemented** — no per-field default registry exists; only section- and project-level reset. - **No backend persistence exists for any of this today** — see `docs/BACKEND.md` item 2 for the endpoints needed. -## Validation +## Configuration schema, form engine, and validation architecture (Sprint X+1) -`ProjectValidator` (`services/project-validator.service.ts`) runs on every save-bar render and blocks Publish (not Save) on: missing `branding.logoUrl`, no supported locales, invalid `tenant.websiteBaseUrl`, duplicate static-page slugs (falls back to `route`), empty homepage, a homepage widget with no `type`, duplicate header nav links, invalid theme colors, missing translations for a supported locale, and layout/section-layout values outside the known enums (`PlatformLayoutType`, `SectionLayoutStrategy`). +**Approach: metadata-augmented, not fully schema-driven.** Section templates stay hand-authored (`sections/*.component.html`); a field-schema registry sits alongside them as the single source of truth for field identity, labels, and validator wiring. This was chosen over a schema-driven renderer to preserve every existing template/UX pixel-for-pixel while still centralizing metadata and validation — the highest-value, lowest-regression-risk option given 11 mature section templates already built on the `shared/ui` primitives (see the primitives table above). + +### Field-schema registry (`schema/`) + +- `field-schema.model.ts` — `FieldSchema`: `{ key, section, type, labelKey, hintKey?, default?, required?, validators? }`. `key` is a dot path into `BootstrapConfig` (e.g. `theme.palette.primary`), unique per section. `validators` references reusable validator names (`hexColor`, `url`, `email`, `json`, `css`, `localeCompleteness`, `duplicateRoutes`, `widgetConfig`) rather than embedding logic. +- `editor-schema.ts` — `SECTION_FIELD_SCHEMAS`: every editable field, one entry per section, sourced from what each template already renders. `ALL_FIELD_SCHEMAS` flattens it. +- `editor-schema.service.ts` (`EditorSchemaService`, `providedIn: 'root'`) — `getFields(section)`, `getField(key)`, `all()`, `getByPath(source, key)` (safe dot-path resolver, never throws on a missing segment). + +The schema is currently consumed by the facade (validation issue → field mapping, modified-field diffing, change-summary labels), not by the templates directly — templates keep calling `facade.updateBootstrap()` the same way they always did. + +### Centralized validators (`schema/validators/`) + +`primitives.ts` holds pure, framework-free functions — one per concern, reused everywhere that concern appears: `isValidHexColor`, `isValidHttpUrl`, `isValidEmail`, `validateJson`, `validateCss` (brace-balance check, comments stripped), `extractStyleBlocks` (pulls `