docs: consolidate scattered docs into canonical set

Replace ~35 organically-grown docs (docs/platform/*, docs/backend-platform/*,
one-off sprint reports, Search.md, Diagnostics.md, Content-Management.md,
Backend-Handoff-Sprint16.md, docs/superpowers/*, docs/Project-Editor.md,
untracked docs/total.md) with the six canonical docs declared in
.claude/CLAUDE.md: PROJECT.md, ARCHITECTURE.md, BACKEND.md, FRONTEND.md,
BOOTSTRAP.md, EDITOR.md, plus a new PROJECT-STRUCTURE.md.

- BACKEND.md is a punch list per domain (auth, bootstrap draft/publish,
  static pages, categories, products, orders, dashboard metrics, activity,
  translations, search, product engagement) plus a Known reliability issues
  section on the prod 502/504 root cause.
- ARCHITECTURE.md links to (does not duplicate) the enforced
  docs/architecture/foundation/** ADRs and standards docs.
- docs/ADMIN.md and docs/architecture/foundation/** and docs/context/** are
  left untouched per instructions.
- Updated the one dangling docs/Project-Editor.md reference in
  admin-auth.service.ts to point at docs/BACKEND.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-07-14 12:28:41 +04:00
parent 94e59ab878
commit 76831b8485
46 changed files with 627 additions and 6857 deletions

153
docs/BOOTSTRAP.md Normal file
View File

@@ -0,0 +1,153 @@
# BOOTSTRAP
The `BootstrapConfig` model (`src/app/shared/models/config/bootstrap-config.model.ts`) is the single JSON contract that drives the entire storefront for a tenant. `ConfigService` loads it once at startup via `GET /bootstrap` (tenant resolved server-side by request host); `PlatformRuntimeService` applies it and can re-apply an edited in-memory copy for preview.
## Top-level shape
```ts
interface BootstrapConfig {
schemaVersion: string;
generatedAt: string;
tenant: TenantConfig; // required
branding: BrandingConfig; // required
theme: ThemeConfig; // required
company: CompanyConfig; // required
featureFlags: FeatureFlagsConfig; // required
features?: MarketplaceFeaturesConfig; // optional, centralized feature toggles
apiEndpoints: ApiEndpointsConfig; // required
localization: LocalizationConfig; // required
seo: SeoConfig; // required
permissions: PermissionsConfig; // required
header?: HeaderConfig;
catalog?: CatalogConfig;
layout?: PlatformLayoutConfig;
navigation: NavigationConfig; // required
footer?: FooterConfig;
productPage?: ProductPageConfig;
userExperience?: UserExperienceConfig;
pages: PageConfig[]; // required
staticPages?: StaticPagesConfig;
widgetRegistry?: WidgetRegistryConfig;
}
```
## Field-by-field
| Key | Meaning |
|---|---|
| `schemaVersion` | Contract version. Breaking changes require a bump; frontend must stay compatible within a minor line. |
| `generatedAt` | Payload generation timestamp. |
| `tenant` | `id`, `slug`, `host`, `name`, `defaultLocale`, `supportedLocales`, `defaultCurrency`, `websiteBaseUrl`, etc. Tenant is resolved by domain only — never re-derived on the frontend. |
| `branding` | `logoUrl`, `logoCompactUrl`, `faviconUrl`, `brandName`. |
| `theme` | `themeId`, `mode` (`light\|dark\|system`), `palette` (12 semantic colors), `typography`, `spacing`, `borderRadiusScale`, `shadows`, `iconSet`. See `docs/ARCHITECTURE.md` theme engine section. |
| `company` | Legal/contact info used in the footer: `companyName`, `address`, `contacts.phone`/`email`. |
| `featureFlags` | Simple boolean toggles: `wishlist`, `compare`, `reviews`, `comments`, `recommendations`, etc. |
| `features` | Newer centralized feature surface (`MarketplaceFeaturesConfig`) — wishlist/compare/reviews/comments/questions/recommendations/recentlyViewed/searchHistory/recentlySearched/ratings/share/brands/manufacturers/availability/discounts/badges. Resolvers fall back to `featureFlags`/`productPage`/`userExperience`/`catalog` for older bootstraps. |
| `apiEndpoints` | Public endpoint map the frontend's API layer reads (base URLs, paths, timeouts). Never contains secrets. |
| `localization` | `defaultLocale`, `supportedLocales`, optional `currencyByLocale`. |
| `seo` | `default.title`/`default.description` plus per-page SEO overrides. |
| `permissions` | Roles/permissions for admin surfaces (currently minimal; see `docs/BACKEND.md`). |
| `header` | Boolean toggles: `showLogo`, `showSearch`, `showCategories`, `showLanguages`, `showCart`, `showProfile`, `showWishlist`, `showCompare`, `showRegion`. |
| `catalog` | UI/feature config only (no product data) — see Catalog Config below. |
| `layout` | `PlatformLayoutConfig`: `{ type: 'default'|'sidebar-left'|'carousel-home'|'minimal', options?: Record<string, unknown> }`. Global page-chrome mode. |
| `navigation` | `header[]` / `footer[]` link arrays: `id`, label (translatable), `route`, `order`, `visible`. |
| `footer` | Payment icons, social links, copyright (per-locale), static-page references. |
| `productPage` | Feature config only for the product detail page — rating/reviews/questions/tabs/relatedProducts/actions enablement, pagination size, mode. No review/question *data* lives here. |
| `userExperience` | Feature config only for wishlist/compare/recentlyViewed/share/savedSearches — flags and limits, never user-specific lists. |
| `pages` | Array of `PageConfig`: `id`, `key`, `route.path`, `sections: SectionConfig[]`. |
| `staticPages` | CMS-style informational/legal pages — see `staticPages` below. |
| `widgetRegistry` | Pointer/metadata for the widget manifest (see `docs/ARCHITECTURE.md` widget engine). |
### Section config (`shared/models/config/section.model.ts`)
```ts
type SectionLayoutStrategy = 'stack' | 'grid' | 'hero' | 'carousel' | 'split';
interface SectionConfig {
id: string; type: string; order: number;
layout?: { strategy?: SectionLayoutStrategy; columns?: number; gap?: string; align?: 'start'|'center'|'end'|'stretch' };
visibility?: { desktop?: boolean; tablet?: boolean; mobile?: boolean };
widgets: WidgetConfig[];
featureFlag?: string;
visible?: boolean;
}
```
### Widget config (`shared/models/config/widget.model.ts`)
Each widget has `id`, `type`, `version`, optional `title`/`subtitle`/`order`/`padding`/`visibility`/`animation`/`style`/`permissions`/`actions`/`featureFlag`/`visible`, and `props: Record<string, unknown>` (widget-specific). Typed editors exist in the Project Editor for `hero`, `categories`, `product-collection`; everything else edits `props` as raw JSON (see `docs/EDITOR.md`).
### Catalog Config (`shared/models/config/catalog-config.model.ts`)
```ts
type CatalogLayoutModeConfig = 'grid'|'large-grid'|'compact-grid'|'grid-2'|'grid-3'|'grid-4'|'compact'|'list';
type CatalogNavigationModeConfig = 'default'|'left-category-navigation'|'mega-category-layout'|'top-category-carousel';
type CatalogLoadingStrategy = 'pagination'|'loadMore'|'infiniteScroll';
```
Plus `defaultSort`/`availableSorts` (`relevance|latest|price_asc|price_desc|rating|popular|discount`), `enabledFilters: string[]`, and `show*`/`*Enabled` booleans (breadcrumbs, category banner, subcategory chips, ratings, discounts, availability, suggestions, search history). This is feature-configuration only — no product/filter *data* lives in bootstrap.
### `staticPages`
Each entry: `id`, `slug`, `title`, `showInHeader`, `showInFooter`, `showInSitemap`, `icon`, `order`, `visibility`, `requiresAuthentication`, `footerGroup`, `translations[locale] = { title, html, seo }`. Rendered dynamically (no hardcoded page list); HTML is sanitized on render. **Known inconsistency:** the model requires `slug`, but the mock bootstrap only populates `route` for some pages — the frontend's duplicate-slug validator falls back to `route` when `slug` is empty (see `docs/BACKEND.md`).
## Representative example (trimmed)
```json
{
"schemaVersion": "2.1.0",
"generatedAt": "2026-07-05T10:30:00Z",
"tenant": {
"id": "tenant-dexar-ru", "slug": "dexar-ru", "host": "dexarmarket.ru",
"name": "Dexar Market", "defaultLocale": "ru", "supportedLocales": ["ru", "en", "hy"],
"defaultCurrency": "RUB", "websiteBaseUrl": "https://dexarmarket.ru"
},
"branding": { "logoUrl": "/assets/brand/logo.svg", "faviconUrl": "/assets/brand/favicon.ico", "brandName": "Dexar Market" },
"theme": {
"themeId": "dexar-light", "mode": "light",
"palette": { "primary": "#2F6E5D", "secondary": "#8FA9A2", "backgroundPrimary": "#FFFFFF", "textPrimary": "#1F322D" },
"typography": { "primaryFontFamily": "DM Sans, sans-serif", "baseFontSize": 16 }
},
"layout": { "type": "default" },
"catalog": { "layout": "grid-4", "navigationMode": "default", "defaultSort": "relevance", "showRatings": true },
"navigation": {
"header": [ { "id": "nav-home", "label": "Home", "route": "/", "order": 1, "visible": true } ],
"footer": [ { "id": "nav-privacy", "label": "Privacy", "route": "/privacy-policy", "order": 1, "visible": true } ]
},
"pages": [
{
"id": "page-home", "key": "home", "route": { "path": "/", "exact": true },
"sections": [
{
"id": "home-hero", "type": "hero", "order": 1,
"layout": { "strategy": "hero" },
"widgets": [ { "id": "w-hero", "type": "hero", "version": "1.0.0", "props": { "title": "Welcome", "layout": "full-bleed" } } ]
},
{
"id": "home-categories", "type": "categories", "order": 2,
"layout": { "strategy": "grid", "columns": 4 },
"widgets": [ { "id": "w-categories", "type": "categories", "version": "1.0.0", "props": { "columns": 4 } } ]
}
]
}
],
"staticPages": [
{ "id": "static-about", "slug": "about", "title": { "en": "About Us" }, "showInFooter": true, "showInHeader": false, "translations": { "en": { "html": "<h1>About Us</h1>" } } }
]
}
```
## How `ConfigService` / `PlatformRuntimeService` consume it
1. `ConfigService.loadBootstrap()` fetches (or, in mock mode, reads local JSON under `src/assets/mock/bootstrap/`) and parses `BootstrapConfig`.
2. `PlatformRuntimeService` applies theme tokens as CSS variables, sets branding, and exposes the parsed pages/navigation/footer/static-pages to the rest of the app.
3. Section Engine / Widget Host render pages from `bootstrap.pages` on route match (see `docs/ARCHITECTURE.md`).
4. `PlatformRuntimeService.reloadFromBootstrap(next)` re-applies an entire new `BootstrapConfig` in-memory — this is what the Project Editor's Publish action (and Preview) use, without a full browser reload.
## How the Project Editor edits it, and draft/publish/preview
The Project Editor (`docs/EDITOR.md`) edits an in-memory copy of the exact same `BootstrapConfig` — there is no parallel editor model or DTO translation layer. Today:
- **Load**: `GET /bootstrap` (same endpoint the storefront uses).
- **Save**: in-memory snapshot only, persisted to `localStorage` as a draft (`projectEditor.draftBootstrap.v1`, scoped by `tenant.id`) so it survives reloads on the same browser.
- **Publish**: runs `ProjectValidator`, then calls `PlatformRuntimeService.reloadFromBootstrap()` for live in-memory preview and flips a local `status` flag — **no backend call happens**. This is the largest gap covered in `docs/BACKEND.md`.
- **Preview**: same in-memory re-apply mechanism, without marking the state published.