# Backend Surface Audit

Machine-oriented, exhaustive audit of every backend touch-point the Angular frontend
expects — derived from the current source tree on branch `B2B`, not copied from prior
docs. Purpose: single input for downstream backend-integration documentation tasks.

Legend for maturity (mirrors `docs/BACKEND_API.md`'s tagging so the two stay reconcilable):

- **LIVE** — real `HttpClient` call exists in code today (file cited).
- **MOCK-SWAPPABLE** — interface + mock implementation exist, wired through an Angular
  DI token so a real `*Api*` class can be dropped in without touching UI. A real impl
  may or may not exist yet.
- **MOCK-ONLY (no seam)** — mock/local implementation exists but the facade injects the
  concrete local class **directly** (no DI token). Adding a backend here first requires
  introducing a token seam. This is the single most important structural finding below.
- **LOCAL-ONLY** — never talks to a backend by design (localStorage / in-memory /
  derived from already-loaded bootstrap). Listed for completeness.

## Table of contents

1. [Executive summary & key findings](#1-executive-summary--key-findings)
2. [Runtime provider strategy & environment](#2-runtime-provider-strategy--environment)
3. [HTTP interceptor pipeline](#3-http-interceptor-pipeline)
4. [Live HTTP endpoints (verified in code)](#4-live-http-endpoints-verified-in-code)
5. [Domain: Auth (customer + admin)](#5-domain-auth-customer--admin)
6. [Domain: Bootstrap / config / tenant](#6-domain-bootstrap--config--tenant)
7. [Domain: Products & catalog](#7-domain-products--catalog)
8. [Domain: Categories](#8-domain-categories)
9. [Domain: Backoffice storefront data](#9-domain-backoffice-storefront-data)
10. [Domain: Cart / orders / payments](#10-domain-cart--orders--payments)
11. [Domain: Reviews & questions (engagement)](#11-domain-reviews--questions-engagement)
12. [Domain: Location / regions](#12-domain-location--regions)
13. [Domain: Widgets / dynamic renderer](#13-domain-widgets--dynamic-renderer)
14. [Admin gateways (feature area)](#14-admin-gateways-feature-area)
15. [Domain: Media library](#15-domain-media-library)
16. [Domain: Content management / static pages](#16-domain-content-management--static-pages)
17. [Domain: Project editor / builder](#17-domain-project-editor--builder)
18. [Domain: Search](#18-domain-search)
19. [Domain: User experience (wishlist/compare/etc.)](#19-domain-user-experience-wishlistcomparetc)
20. [Domain: Diagnostics](#20-domain-diagnostics)
21. [Facade catalog](#21-facade-catalog)
22. [Gateway / provider master table](#22-gateway--provider-master-table)
23. [Model / DTO catalog](#23-model--dto-catalog)
24. [Endpoint URL literals found in code](#24-endpoint-url-literals-found-in-code)
25. [Cross-check against existing docs](#25-cross-check-against-existing-docs)

---

## 1. Executive summary & key findings

- **~9 real HTTP-speaking domains** exist today: product/catalog, categories, cart/orders/
  payments, reviews/questions, telegram session auth, bootstrap, backoffice storefront data,
  widget manifest, location/regions. Plus **Ed25519 admin auth** — wired to real `HttpClient`
  but the endpoints are not implemented server-side yet (calls 404 today, by design).
- **Two provider seams are token-bound and API-ready today**: `PRODUCT_DATA_PROVIDER`
  (→ `ApiProductDataProvider`, LIVE) and `CATEGORY_REPOSITORY` (→ `ApiCategoryRepository`, LIVE),
  plus `CONFIG_PROVIDER` and `BACKOFFICE_DATA_PROVIDER` which switch mock↔api by strategy.
- **KEY STRUCTURAL FINDING — most admin CRUD domains have no swap seam.** Of the 11 admin
  gateway domains, only **categories** (`ADMIN_CATEGORIES_GATEWAY`) and **dashboard-metrics**
  (`ADMIN_DASHBOARD_METRICS_GATEWAY`) are injected via DI token. The other 9 (orders, products,
  users, transactions, monitoring, moderation, customers, analytics, and the products/orders
  gateways reused by analytics/customers) have their facades inject the concrete
  `Admin*LocalGateway` **class directly**. A backend engineer cannot "just rebind a token" for
  those — a token must be introduced first. This partially contradicts the blanket
  "PLANNED / rebind the token" framing in `docs/BACKEND_API.md`.
- **Only one real `*Api*Gateway` exists in the admin area**: `AdminCategoriesApiGateway`
  (`src/app/features/admin/categories/services/admin-categories-api.gateway.ts`). Every other
  admin domain is local-mock only.
- **Media** is bound by class token (`MediaRepository` abstract class → `MockMediaRepository`
  via `app.config.ts`), so it is MOCK-SWAPPABLE but no real impl exists.
- **Content-management and project-editor never hit a dedicated backend** — they read/mutate
  the in-memory `BootstrapConfig` (loaded once from `GET /bootstrap`) and persist drafts to
  localStorage. Publishing a marketplace = writing bootstrap back, for which no client write
  call exists yet (LOCAL-ONLY today; a builder publish endpoint is FUTURE).
- **Two API base URLs are in play**: the tenant marketplace API (`ApiConfigService.getBaseUrl()`,
  default `https://api.dexarmarket.ru:445`, `/api` on localhost) and a separate payment/QR API
  (`environment.qrApiUrl` = `https://qr.vitanova.network/api`). Auth session API uses
  `environment.authApiUrl` (= `https://api.dexarmarket.ru:445`).

---

## 2. Runtime provider strategy & environment

`src/app/core/providers/runtime-provider-strategy.service.ts` — `RuntimeProviderStrategyService`
decides mock vs api per domain. Modes: `'mock' | 'api' | 'remote-config'`.

| Method | Returns `mock` when | Else |
|---|---|---|
| `getBootstrapProviderMode()` | `useMockData` true, OR `useMockBootstrapOnLocal && isLocalhost()` | `api` |
| `getBackofficeProviderMode()` | `useMockData` true | `api` |
| `getProductProviderMode()` | `useMockData` true | `api` (mock/remote-config fall through to api in token factory) |
| `getCategoryProviderMode()` | `useMockData` true, OR `useMockBootstrapOnLocal && isLocalhost()` | `api` |

Note: `PRODUCT_DATA_PROVIDER` and `CATEGORY_REPOSITORY` token factories currently return the
**Api** provider for every mode (the `case 'mock'` falls through) — there is no mock product/
category provider class bound. `getCategoryProviderMode()` returning `mock` only matters for
`ADMIN_CATEGORIES_GATEWAY` (which does honor it → `AdminCategoriesLocalGateway`).

`src/environments/environment.ts` relevant keys:

```
useMockData: false
useMockBootstrapOnLocal: true
allowBootstrapApiOverride: false
localhostApiUrl: '/api'
tenantApiTemplate: 'https://{tenant}.api.dexarmarket.ru:445'
tenantApiBaseUrls: { default: 'https://api.dexarmarket.ru:445', dexarmarket: 'https://api.dexarmarket.ru:445' }
apiUrl: '/api'
authApiUrl: 'https://api.dexarmarket.ru:445'
qrApiUrl: 'https://qr.vitanova.network/api'
telegramBot: 'myAMLKYCBOT'   (fallback in code: 'DexarSupport_bot')
```

`src/app/core/config/api-config.service.ts` — `ApiConfigService.getBaseUrl()` resolves the
tenant marketplace API base: localhost → `localhostApiUrl`; else `tenantApiBaseUrls[tenantKey]`;
else `tenantApiTemplate` with `{tenant}` substituted; else optional bootstrap override
(gated by `allowBootstrapApiOverride`, reads `bootstrap.apiEndpoints.website.baseUrl` /
`bootstrap.tenant.apiBaseUrl`). `isApiRequest(url)` = starts with `/api` or the base URL.
`toApiUrl(url)` rewrites a `/api`-prefixed relative URL onto the resolved base.

Tenant key comes from `TenantResolverService` (`src/app/core/config/tenant-resolver.service.ts`).

---

## 3. HTTP interceptor pipeline

Registered in `src/app/app.config.ts` in this order:

```
withInterceptors([mockDataInterceptor, apiBaseUrlInterceptor, apiHeadersInterceptor, adminAuthHeadersInterceptor, cacheInterceptor])
```

| Interceptor | File | Responsibility |
|---|---|---|
| `mockDataInterceptor` | `src/app/interceptors/mock-data.interceptor.ts` | When `environment.useMockData`, short-circuits marketplace endpoints with in-memory fixtures (categories, items, search, cart, qr, callback, purchase-email, sessions). Matches URL patterns — see §24. |
| `apiBaseUrlInterceptor` | `src/app/interceptors/api-base-url.interceptor.ts` | Rewrites `/api/*` relative URLs to `ApiConfigService.toApiUrl()`. |
| `apiHeadersInterceptor` | `src/app/interceptors/api-headers.interceptor.ts` | For marketplace API requests, sets headers: `X-Region`, `X-Language` (RU/EN/AM), `Currency` (default RUB), `WebSessionID` (auth session id or persisted anonymous 32-hex id in localStorage key `web_session_id`). |
| `adminAuthHeadersInterceptor` | `src/app/core/admin-auth/admin-auth-headers.interceptor.ts` | For requests whose URL contains `/admin/`, `/backoffice/`, `/builder/`, `/media/`, sets `AdminWebSessionID` header (from `AdminAuthService.session()`) and `Authorization: Bearer <token>` if an admin token is stored. |
| `cacheInterceptor` | `src/app/interceptors/cache.interceptor.ts` | Client-side GET response caching. |

Header value maps (from `apiHeadersInterceptor`): language `ru→RU, en→EN, hy→AM`;
region `moscow→Moscow, spb→ST. Petersburg, yerevan→Yerevan`.

---

## 4. Live HTTP endpoints (verified in code)

All paths relative to `ApiConfigService.getBaseUrl()` unless a full origin is shown. Payment
endpoints use `environment.qrApiUrl`; session endpoints use `environment.authApiUrl`.

### Marketplace API — `src/app/services/api.service.ts` (`ApiService`)

| Method | HTTP | Path | Notes |
|---|---|---|---|
| `ping()` | GET | `/ping` | `{ message }` |
| `getCategories()` | GET | `/category` | normalized to `Category[]` |
| `getCategoryItems(id,count,skip)` | GET | `/category/{categoryID}?count&skip` | `Item[]` |
| `getItem(id)` | GET | `/items/{itemID}` | single `Item` |
| `searchItems(search,count,skip,opts)` | GET | `/searchitems?search&count&skip[&categoryIDs&minPrice&maxPrice&tag&sort]` | `{ items, total }` |
| `getRandomItems(count,categoryID?)` | GET | `/items/randomitems?count[&category]` | `Item[]` (featured) |
| `addToCart(sessionId,items)` | POST | `/websession/{sessionId}` | body = item array |
| `submitReview(data)` | POST | `/items/{itemID}/callback` | body: rating, comment, sessionID, timestamp |
| `submitQuestion(data)` | POST | `/items/{itemID}/questiion` | **NOTE: literal typo `questiion`** matches backend spec |
| `createCartPayment(payload)` | POST | `/cart` | `CartPaymentRequest` → `QrCreateResponse` |
| `createOrder(payload)` | POST | `/orders` | `CreateOrderRequest` → `CreateOrderResponse`; fire-and-forget after payment |
| `submitPurchaseEmail(data)` | POST | `/purchase-email` | email receipt |
| `createPayment(payload,headers)` | POST | `{qrApiUrl}/qr` | headers `authorization-key`, `userid-value` |
| `checkCartPaymentStatus(qrId)` | GET | `{qrApiUrl}/qr/dynamic/{partnerId}/{qrId}` | partnerId const `web-97ec-9c57-4dde-9037-3a68f7f83750` |
| `checkCartCardPaymentStatus(orderId)` | GET | `{qrApiUrl}/card/{partnerId}/{orderId}` | |
| `checkPaymentStatus(partnerQrId,qrId)` | GET | `{qrApiUrl}/qr/dynamic/{partnerQrId}/{qrId}` | |

Also builds an external QR image URL (`https://api.qrserver.com/v1/create-qr-code/...`) — not a backend of this platform.

### Other live callers

| Caller (file) | HTTP | Path | Base |
|---|---|---|---|
| `ApiHealthService` (`src/app/services/api-health.service.ts`) | GET | `/ping` | marketplace base |
| `ApiCategoryRepository` (`src/app/core/categories/repositories/api-category.repository.ts`) | GET | `/category` | marketplace base; retry x2 |
| `ApiBootstrapProvider` (`src/app/core/bootstrap/providers/api-bootstrap.provider.ts`) | GET | `/bootstrap` | relative |
| `MockBootstrapProvider` | GET | `/assets/mock/bootstrap/bootstrap.json` | static asset |
| `ApiBackofficeDataProvider` (`src/app/core/backoffice/providers/api-backoffice-data.provider.ts`) | GET | `/api/backoffice/products`, `/api/backoffice/categories` | |
| `WidgetManifestService` (`src/app/widgets/registry/widget-manifest.service.ts`) | GET | `bootstrap.widgetRegistry.manifestUrl` or `/assets/mock/bootstrap/widget-manifest.json` | |
| `LocationService` (`src/app/services/location.service.ts`) | GET | `/regions` (marketplace base); `http://ip-api.com/json/...` (external geo-IP) | |
| `TelegramSessionApiService` (`src/app/services/telegram-session-api.service.ts`) | POST/GET/DELETE | `{authApiUrl}/users/sessions`, `/users/sessions/{id}` | session auth |
| `AuthApiService` (`src/app/core/auth/services/auth-api.service.ts`) | GET/POST | `{authApiUrl}/api/admin/auth/challenge|verify|refresh|logout` | **not implemented server-side yet** |
| `ApiProductDataProvider` | (delegates to `ApiService`) | see above | |

---

## 5. Domain: Auth (customer + admin)

Two distinct auth mechanisms coexist.

### 5a. Telegram session auth (LIVE) — customer AND admin

`src/app/services/telegram-session-api.service.ts` — `TelegramSessionApiService`. Single source
for both customer (`AuthService`) and admin (`AdminAuthService`) login; there is no separate
admin backend endpoint. Only storage is kept separate (distinct cookie/signals).

| Method | HTTP | Path | Request | Response (normalized) |
|---|---|---|---|---|
| `createSession()` | POST | `{authApiUrl}/users/sessions` | `{ webSessionID }` + header `WebSessionID` | `WebSessionStart { webSessionID, url }` (url = `https://t.me/{bot}?start={id}`) |
| `checkSessionOnce(id)` | GET | `{authApiUrl}/users/sessions/{id}` | — | `AuthSession | null` (heavily field-tolerant normalizer) |
| `logout(id)` | DELETE | `{authApiUrl}/users/sessions/{id}` | header `WebSessionID` | ignored |

Consumers: `AuthService` (`src/app/services/auth.service.ts`, customer),
`AdminAuthService` (`src/app/core/admin-auth/admin-auth.service.ts`, admin — separate cookie
`adminSessionID`, has dev-only `devBypassLogin()`), `AuthFacade`
(`src/app/core/auth/services/auth-facade.service.ts`) wrapping AuthService/SessionService/
PermissionService for components. Also `src/app/shared/qr-login/`.

Models: `AuthSession`, `WebSessionStart`, `AuthStatus` (`src/app/models/auth.model.ts`);
`AdminAuthStatus` (`src/app/models/admin-auth.model.ts`).

### 5b. Ed25519 challenge/response admin auth (LIVE wiring, backend absent)

`src/app/core/auth/services/auth-api.service.ts` — `AuthApiService`. Real `HttpClient` wiring
against a documented contract that the backend has NOT implemented yet (calls 404 today,
mapped to a `backend-unavailable` error screen). No mocks fabricated.

| Method | HTTP | Path (`{authApiUrl}/api/admin/auth`) | Request | Response |
|---|---|---|---|---|
| `requestChallenge()` | GET | `/challenge` | — | `AuthChallenge { nonce, issuedAt, expiresAt }` |
| `verifySignature(req)` | POST | `/verify` | `VerifySignatureRequest { publicKey, signature, nonce }` | `AuthTokenPair { token, refreshToken }` |
| `refresh(req)` | POST | `/refresh` | `RefreshTokenRequest { refreshToken }` | `AuthTokenPair` |
| `logout(refreshToken)` | POST | `/logout` | `{ refreshToken }` | void |

Models: `src/app/core/auth/models/auth-api.model.ts` (`AuthChallenge`, `VerifySignatureRequest`,
`AuthTokenPair`, `RefreshTokenRequest`, `JwtClaims`). Supporting:
`src/app/core/auth/services/ed25519-keypair.service.ts` (keypair gen/signing);
`src/app/core/admin-auth/ed25519-verification.model.ts` +
`noop-ed25519-verification.service.ts` (bound in `app.config.ts` via
`{ provide: Ed25519VerificationService, useClass: NoopEd25519VerificationService }`).

Permissions/roles: `src/app/core/auth/models/permission.model.ts` — `AdminRole`
(`Owner|Administrator|Editor|Support|ReadOnly`), `Permission` union.
Errors: `src/app/core/auth/models/auth-error.model.ts` — `AuthErrorCode`, `AuthError`.
Guards: `src/app/core/admin-auth/admin-auth.guard.ts`, `src/app/guards/**`.

---

## 6. Domain: Bootstrap / config / tenant

The runtime configuration document that drives the entire multi-tenant platform.

- **Contract interface**: `ConfigProvider` (`src/app/core/config/config-provider.interface.ts`)
  — `loadBootstrap(): Observable<BootstrapConfig>`.
- **DI token**: `CONFIG_PROVIDER` (`src/app/core/config/config-provider.token.ts`), factory
  switches on `getBootstrapProviderMode()`: `mock` → `MockBootstrapProvider`
  (`/assets/mock/bootstrap/bootstrap.json`), else → `ApiBootstrapProvider` (`GET /bootstrap`).
- **Implementations**: `ApiBootstrapProvider`, `MockBootstrapProvider`
  (`src/app/core/bootstrap/providers/*`).
- **Consuming services**: `ConfigService` (`src/app/core/config/config.service.ts`,
  holds the bootstrap snapshot), `ApiConfigService`, `FeatureConfigService`,
  `TenantResolverService`, `FooterResolverService`, `StaticPageResolverService`
  (all `src/app/core/config/*`).
- **Consuming facades**: `UiRuntimeFacade` (`src/app/facades/runtime/ui-runtime.facade.ts`),
  `WebsiteRuntimeFacade` (`src/app/facades/website/website-runtime.facade.ts`),
  `ProjectEditorFacade`, `ContentManagementFacade`, `DiagnosticsFacade`.

`BootstrapConfig` (`src/app/shared/models/config/bootstrap-config.model.ts`) aggregates ~24
sub-configs, each its own file under `src/app/shared/models/config/`:

`schemaVersion, generatedAt, tenant, branding, theme, company, featureFlags, features?,
apiEndpoints, localization, seo, permissions, header?, catalog?, layout?, navigation, footer?,
productPage?, userExperience?, pages[], staticPages?, widgetRegistry?`

Sub-config model files (all backend-shaped, served inside bootstrap):
`api-endpoints.model.ts` (`ApiEndpointConfig{path,method,timeoutMs?}`, `ApiEndpointsConfig{
bootstrap, website:Record<...>, builder:Record<...>, backoffice:Record<...>}`),
`tenant.model.ts` (`TenantConfig{id,slug,code,host,name,websiteBaseUrl,builderBaseUrl,
backofficeBaseUrl,defaultLocale,supportedLocales,defaultCurrency,supportedCurrencies,timezone}`),
`branding.model.ts`, `theme.model.ts`, `company.model.ts`, `feature-flags.model.ts`,
`features-config.model.ts`, `footer-config.model.ts`, `header-config.model.ts`, `layout.model.ts`,
`localization.model.ts`, `navigation.model.ts`, `page.model.ts`, `permissions.model.ts`,
`product-page-config.model.ts`, `catalog-config.model.ts`, `seo.model.ts`,
`static-page.model.ts`, `user-experience-config.model.ts`, `widget-registry.model.ts`,
`widget.model.ts`, `section.model.ts`. Barrel: `src/app/shared/models/config/index.ts`.

`ApiEndpointsConfig.website/builder/backoffice` are `Record<string, ApiEndpointConfig>` —
i.e. the bootstrap document is where a tenant's PLANNED endpoint paths are declared at runtime.
No literal builder/backoffice path constants exist in code (see §24).

---

## 7. Domain: Products & catalog

- **Contract interface**: `ProductDataProvider`
  (`src/app/core/products/providers/product-data-provider.interface.ts`).
- **DI token**: `PRODUCT_DATA_PROVIDER` (`src/app/core/products/product-data-provider.token.ts`)
  — factory returns `ApiProductDataProvider` for all modes (no mock provider class bound).
- **Real impl (LIVE)**: `ApiProductDataProvider`
  (`src/app/core/products/providers/api-product-data.provider.ts`) — delegates to `ApiService`
  + `CategoryService`; contains inline mapping (item→reviews/questions/rating summary).
- **Domain service**: `ProductDataService` (`src/app/core/products/product-data.service.ts`)
  injected by `ProductFacade`.
- **Consuming facade**: `ProductFacade` (`src/app/facades/platform/product.facade.ts`).
- **Consuming components**: `catalog-container.component.ts`,
  `product-details-container.component.ts` (`src/app/features/website/**`), home/catalog pages.

Interface methods: `getProducts(query?)`, `getProduct(productID)`, `getCategories()`,
`searchProducts(query)`, `getFeaturedProducts(query?)`, `getLatestProducts(query?)`,
`getProductsByCategory(categoryID,query?)`, `getRelatedProducts(query)`, `loadRating(productID)`,
`loadReviews(productID,query?)`, `loadQuestions(productID,query?)`, `submitReview(productID,input)`,
`submitQuestion(productID,input)`.

Models — `src/app/core/products/models/`:
- `product-domain.model.ts`: `Product = Item` (alias), `ProductCategory = Category`,
  `ProductSort`, `ProductFilters`, `ProductListQuery`, `ProductSearchQuery`, `ProductListResult`,
  `RelatedProductsQuery`, `RelatedProductCollection`, `ProductVariantSelection`.
- `product-engagement.model.ts`: `RatingStars`, `RatingDistributionEntry`, `RatingSummary`,
  `Review`, `Answer`, `Question`, `EngagementListQuery`, `EngagementListResult<T>`,
  `SubmitReviewInput`, `SubmitQuestionInput`.
- `catalog-experience.model.ts`: `SearchCriteria`, `FilterDefinition`, `FilterOption`,
  `SortDefinition`, `CatalogView`, `SearchResult`, layout/nav mode types.

The **backend-shaped** product DTO is `Item` (`src/app/models/item.model.ts`) — the raw wire
shape. `ApiService.normalizeItem()` is the adapter: it reconciles legacy marketplace format and
newer backOffice format (string `id`↔numeric `itemID`, `imgs[]`↔`photos[]`, `names[]`↔
`translations`, `itemDetails[]`, `description` key/value array↔string, `comments`↔`callbacks`,
`specificationGroups`, `variantOptions`, `relatedCollections`, delivery normalization, color
`0xRRGGBB`→`#RRGGBB`, remaining→stock band). This is the single largest inline mapper in the
codebase — a backend engineer should treat `normalizeItem`/`normalizeCategory` as the tolerance
contract. `Item` supporting types: `ProductMedia`, `DescriptionField`, `ItemName`,
`ProductSpecificationField/Group`, `ProductVariantOption(Group)`, `RelatedProductCollection`,
`DeliveryOption`, `ItemDetail`, `CartItem`.

---

## 8. Domain: Categories

Two parallel category stacks exist (legacy + clean-architecture):

**Clean stack (MOCK-SWAPPABLE, real impl LIVE):**
- **Interface**: `CategoryRepository` (`src/app/core/categories/repositories/category.repository.ts`)
  — `getCategories(): Observable<CategoryDto[]>`.
- **DI token**: `CATEGORY_REPOSITORY` (`src/app/core/categories/category-repository.token.ts`)
  → `ApiCategoryRepository` for all modes.
- **Real impl (LIVE)**: `ApiCategoryRepository` — `GET /category`, retry x2.
- **DTO**: `CategoryDto`, `CategoryNameDto` (`src/app/core/categories/dto/category.dto.ts`).
- **Adapter**: `CategoryMapper` (`src/app/core/categories/mappers/category.mapper.ts`) —
  `CategoryDto → Category` domain (flattens subcategory tree, dedupes by id, language
  normalization `am→hy`).
- **Domain model**: `Category`, `CategoryTranslation`
  (`src/app/core/categories/models/category-domain.model.ts`).
- **Facade**: `CategoryFacade` (`src/app/facades/platform/category.facade.ts`) via
  `CategoryService` (`src/app/core/categories/category.service.ts`). Utils:
  `category-tree.utils.ts`.

**Legacy stack**: `ApiService.getCategories()` → `Category` (`src/app/models/category.model.ts`,
with `Subcategory`) via `normalizeCategory()`. Used by `ApiProductDataProvider.getCategories()`.
Note: two different `Category` types exist (`src/app/models/category.model.ts` vs
`src/app/core/categories/models/category-domain.model.ts`) — a known duplication.

---

## 9. Domain: Backoffice storefront data

Storefront-facing "cards" data (distinct from the admin/backoffice feature area).

- **Interface**: `BackofficeDataProvider`
  (`src/app/core/backoffice/providers/backoffice-data-provider.interface.ts`) —
  `loadProducts(): Observable<ProductCardConfig[]>`, `loadCategories(): Observable<CategoryCardConfig[]>`.
- **DI token**: `BACKOFFICE_DATA_PROVIDER` (`src/app/core/backoffice/backoffice-data-provider.token.ts`)
  — `mock` → `MockBackofficeDataProvider`, else → `ApiBackofficeDataProvider`.
- **Impls**: `ApiBackofficeDataProvider` (LIVE, `GET /api/backoffice/products`,
  `GET /api/backoffice/categories`), `MockBackofficeDataProvider`
  (`src/app/core/backoffice/providers/*`).
- **Models**: `ProductCardConfig` (`src/app/shared/models/ui/product-card.model.ts`),
  `CategoryCardConfig` (`src/app/shared/models/ui/category-card.model.ts`),
  `ButtonConfig` (`button.model.ts`). Barrel: `src/app/shared/models/ui/index.ts`.

---

## 10. Domain: Cart / orders / payments

Cart state is **LOCAL-ONLY** but checkout produces LIVE payment/order calls.

- **`CartService`** (`src/app/services/cart.service.ts`) — signal-based cart, persisted to
  localStorage key `marketplace_cart` (+ Telegram CloudStorage when in Telegram WebApp). No
  backend for cart contents. Models: `CartItem` (extends `Item`), `DeliveryOption`.
- **Checkout → `ApiService`** (see §4): `POST /cart` (`CartPaymentRequest`),
  `POST /orders` (`CreateOrderRequest`→`CreateOrderResponse`), `POST /purchase-email`,
  QR/card status polling on `qrApiUrl`.
- Request/response DTOs live inline in `api.service.ts`: `QrCreateRequest`, `QrCreateResponse`,
  `CartPaymentRequest`, `CreateOrderRequest`, `CreateOrderResponse`, `QrDynamicStatusResponse`.
- Admin-side order/transaction views are a **separate** mock domain — see §14.

---

## 11. Domain: Reviews & questions (engagement)

Customer-facing. LIVE via `ApiService`. Interface methods on `ProductDataProvider`:
`loadRating`, `loadReviews`, `loadQuestions`, `submitReview`, `submitQuestion`.
Endpoints: `POST /items/{id}/callback` (review), `POST /items/{id}/questiion` (question, typo
preserved). Reads derive reviews/questions/rating from `GET /items/{id}` payload (no dedicated
list endpoints yet). Models in `product-engagement.model.ts` (§7). Admin **moderation** of
reviews/reports is a separate mock domain — see §14.

---

## 12. Domain: Location / regions

`LocationService` (`src/app/services/location.service.ts`), LIVE:
- `GET /regions` (marketplace base) → `Region[]`; falls back to 6 hardcoded regions on error.
- `GET http://ip-api.com/json/?fields=...` (external geo-IP, no key) for auto-detect.
Models: `Region`, `GeoIpResponse` (`src/app/models/location.model.ts`). Region id feeds the
`X-Region` header (§3).

---

## 13. Domain: Widgets / dynamic renderer

Widget manifest is LIVE (static/remote JSON), widget data is derived from products/categories.

- **`WidgetManifestService`** (`src/app/widgets/registry/widget-manifest.service.ts`) — GETs
  `bootstrap.widgetRegistry.manifestUrl` or fallback
  `/assets/mock/bootstrap/widget-manifest.json` → `WidgetManifestFile`.
- **`WidgetRegistryService`** (`src/app/widgets/registry/widget-registry.service.ts`),
  **`WidgetHostService`** (`src/app/dynamic-renderer/widget-host/widget-host.service.ts`).
- Contracts (`src/app/widgets/contracts/`): `widget-manifest.contract.ts`
  (`WidgetManifestEntry/File`, `WidgetSettingsSchema`, `WidgetMetadataSupport`,
  `WidgetLayoutSupport`, `WidgetDataSourceName`), `widget-component.contract.ts`
  (`WidgetRenderContext`, `RegisteredWidget`, `ResolvedWidget`), `widget-data.contract.ts`
  (`HeroWidgetData`, `CategoriesWidgetData`, `ProductCollectionWidgetData`, `BannerWidgetData`,
  `HtmlWidgetData`, `PartnersWidgetData`, `FooterWidgetData`, `HeroSlideData`,
  `WidgetResolvedContext`).
- Renderer models: `src/app/dynamic-renderer/{page-renderer,section-renderer,widget-host}/*.model.ts`.
- Widget data sources (`featured|latest|category|manual|related|root|parent`) map back onto
  the product/category providers of §7–§8.

---

## 14. Admin gateways (feature area)

`src/app/features/admin/**`. Each domain follows Facade → Gateway (interface) → LocalGateway.
**Only categories and dashboard-metrics use a DI token; all others inject the local class
directly (MOCK-ONLY, no seam).** Only `AdminCategoriesApiGateway` is a real HTTP impl.

| Domain | Interface | Local (mock) impl | Real impl | DI token | Facade | Seam status |
|---|---|---|---|---|---|---|
| Categories | `admin-categories-gateway.interface.ts` (`AdminCategoriesGateway`) | `admin-categories-local.gateway.ts` | `admin-categories-api.gateway.ts` (**HttpClient**) | `ADMIN_CATEGORIES_GATEWAY` (`admin-categories-gateway.token.ts`) | `AdminCategoriesFacade` | MOCK-SWAPPABLE (real impl exists) |
| Dashboard metrics | `admin-dashboard-metrics.gateway.interface.ts` (`AdminDashboardMetricsGateway`) | `admin-dashboard-metrics.local.gateway.ts` | none | `ADMIN_DASHBOARD_METRICS_GATEWAY` (`admin-dashboard-metrics-gateway.token.ts`) | `AdminDashboardFacade` | MOCK-SWAPPABLE (token only) |
| Orders | `admin-orders-gateway.interface.ts` (`AdminOrdersGateway`) | `admin-orders-local.gateway.ts` | none | **none** | `AdminOrdersFacade` (injects `AdminOrdersLocalGateway`) | MOCK-ONLY (no seam) |
| Products | `admin-products-gateway.interface.ts` (`AdminProductsGateway`) | `admin-products-local.gateway.ts` | none | **none** | `AdminProductsFacade` (injects local) | MOCK-ONLY (no seam) |
| Users | `admin-users-gateway.interface.ts` (`AdminUsersGateway`) | `admin-users-local.gateway.ts` | none | **none** | `AdminUsersFacade` (injects local) | MOCK-ONLY (no seam) |
| Transactions | `admin-transactions-gateway.interface.ts` (`AdminTransactionsGateway`) | `admin-transactions-local.gateway.ts` | none | **none** | `AdminTransactionsFacade` (injects local) | MOCK-ONLY (no seam) |
| Monitoring | `admin-monitoring-gateway.interface.ts` (`AdminMonitoringGateway`) | `admin-monitoring-local.gateway.ts` | none | **none** | `AdminMonitoringFacade` (injects local) | MOCK-ONLY (no seam) |
| Moderation | `admin-moderation-gateway.interface.ts` (`AdminModerationGateway`) | `admin-moderation-local.gateway.ts` | none | **none** | `AdminModerationFacade` (injects local) | MOCK-ONLY (no seam) |
| Customers | (no gateway of its own) | reuses `AdminOrdersLocalGateway` | none | **none** | `AdminCustomersFacade` (injects orders local) | MOCK-ONLY (derived) |
| Analytics | (no gateway of its own) | reuses orders/products/moderation local + `ADMIN_CATEGORIES_GATEWAY` + `AdminDashboardFacade` | none | partial (categories token) | `AdminAnalyticsFacade` | MOCK-ONLY (derived) |

Gateway interface method contracts (the shapes a backend must satisfy):

- **`AdminCategoriesGateway`**: `loadCategories(filters)`, `loadCategory(id)`, `createCategory`,
  `updateCategory`, `deleteCategory`, `restoreCategory`, `isSlugTaken(slug,excludingId)`.
- **`AdminDashboardMetricsGateway`**: `loadMetrics(): AdminDashboardMetrics`.
- **`AdminOrdersGateway`**: `loadOrders(filters)`, `loadOrder(id)`, `updateStatus(id,status)`,
  `requestRefund(id)`, `addNote(id,note,internal)`, `archiveOrder`, `restoreOrder`, `deleteOrder`.
- **`AdminProductsGateway`**: `loadProducts(filters)`, `loadProduct(id)`, `loadCategories()`,
  `createProduct`, `updateProduct`, `deleteProduct`, `duplicateProduct`, `archiveProduct`,
  `restoreProduct`.
- **`AdminUsersGateway`**: `loadUsers`, `loadRoles`, `loadInvitations`, `loadSessions(userId)`,
  `loadAudit(userId)`, `setUserRole`, `setUserStatus`, `inviteUser(email,roleId,scope)`,
  `revokeInvitation`, `revokeSession`.
- **`AdminTransactionsGateway`**: `loadTransactions(filters)`, `retryFailed(id)`,
  `setFraudFlag(id,flagged)`.
- **`AdminMonitoringGateway`**: `loadEvents(filters)`, `loadQueues()`, `loadWebhooks()`.
- **`AdminModerationGateway`**: `loadReviews(filters)`, `loadReview(id)`, `setReviewStatus`,
  `setReviewVisible`, `setReviewPinned`, `setReviewFeatured`, `addModeratorNote`, `deleteReview`,
  `loadReports()`, `setReportStatus(id,status)`.

Admin model files (all under `src/app/features/admin/<domain>/models/`) — see §23.

Note: `AdminRole` is defined **twice** with different meaning — `src/app/core/auth/models/
permission.model.ts` (auth roles `Owner|Administrator|Editor|Support|ReadOnly`) vs
`src/app/features/admin/users/models/admin-user.model.ts` (`AdminRole` interface {id,name,...}).
Flag for backend/naming reconciliation.

Local gateways are localStorage / in-memory backed (facades also inject `LocalStorageService`
for overlay persistence, e.g. orders/moderation/categories/products).

---

## 15. Domain: Media library

MOCK-SWAPPABLE via abstract-class token, no real impl.

- **Contract**: abstract class `MediaRepository` (`src/app/core/media/media-repository.ts`) —
  `list(params?)`, `upload(file,options?)`, `remove(id)`, `update(id,patch)`, `listFolders()`.
- **Binding**: `app.config.ts` → `{ provide: MediaRepository, useClass: MockMediaRepository }`.
- **Mock impl**: `MockMediaRepository` (`src/app/core/media/mock-media-repository.service.ts`,
  uses `HttpClient` to read seed assets). Also `MediaUsageService`
  (`src/app/core/media/media-usage.service.ts`).
- **Facade**: `MediaLibraryFacade` (`src/app/features/backoffice/media/facade/media-library.facade.ts`),
  page `media-library-page.component.ts`.
- **Models** (`src/app/core/media/models/media-asset.model.ts`): `MediaAsset`, `MediaAssetKind`,
  `MediaSort`, `MediaListParams`, `MediaUploadOptions`, `MediaListResult`.
- Admin-auth interceptor already gates `/media/` paths (§3), anticipating a real media backend.

---

## 16. Domain: Content management / static pages

**LOCAL-ONLY** — operates on the already-loaded `BootstrapConfig.staticPages`, no dedicated
backend calls. Publishing/writing bootstrap is not implemented client-side (FUTURE).

- **Facade**: `ContentManagementFacade` (`src/app/features/content-management/facade/content-management.facade.ts`)
  → `ContentPageService` (`.../services/content-page.service.ts`). Public API: `pages(bootstrap)`,
  `hasSeoContent(page)`, `contentHealth(bootstrap)`, `resolvePage(bootstrap,keyOrSlug,locale)`,
  `validatePages(bootstrap)`, `toBootstrapRecord(bootstrap)`, `serializePages(pages)`,
  `normalizeSlug`.
- `ContentPageService` maps between bootstrap `StaticPagesConfig` and the editor `ContentPage`
  view model (normalize / validate / `toBootstrapRecord`). This is the adapter.
- **Models** (`src/app/features/content-management/models/`): `ContentPage`,
  `ContentPageTranslation`, `ContentPageSeoConfig`, `ContentPageStatus`,
  `ContentPageBootstrapInput` (`content-page.model.ts`); `LegalPageKey`, `LegalPageDefinition`
  (`legal-pages.model.ts`). Backend-shaped counterpart: `StaticPageConfig`,
  `StaticPagesConfig`, `ResolvedStaticPage`, `LocalizedHtmlContent`, `LocalizedTextContent`
  (`src/app/shared/models/config/static-page.model.ts`).
- Consumers: `static-pages-editor.component.ts`, `page-editor.component.ts`,
  `static-page.component.ts` (`src/app/pages/static-page/`), resolved via
  `StaticPageResolverService`.

---

## 17. Domain: Project editor / builder

**LOCAL-ONLY** today — edits an in-memory `BootstrapConfig`, persists drafts to localStorage;
no publish/save-to-backend HTTP call exists. A builder API is declared only as
`BootstrapConfig.apiEndpoints.builder` (runtime-declared, FUTURE).

- **Facade**: `ProjectEditorFacade` (`src/app/features/project-editor/facade/project-editor.facade.ts`)
  — orchestrates undo/redo `History<BootstrapConfig>`, injects `ConfigService`,
  `ProjectEditorIoService` (JSON import/export of bootstrap), `ProjectEditorPreviewService`,
  `LocaleSyncService`, `PlatformRuntimeService`, `ProjectValidator`,
  `ProjectEditorDraftStorageService` (localStorage drafts), `EditorSchemaService`.
- Services (`src/app/features/project-editor/services/`): `project-editor-io.service.ts`
  (`exportBootstrap`/`importBootstrap` = JSON.stringify/parse), `project-editor-draft-storage.service.ts`,
  `project-editor-preview.service.ts`, `project-validator.service.ts`, `locale-sync.service.ts`.
  Schema: `schema/editor-schema.service.ts`, `schema/field-schema.model.ts`, `schema/validators/`.
- **Models**: `project-editor.model.ts` (`ProjectEditorState`, `ProjectEditorSectionId`,
  `ProjectEditorWidgetPreset`, `BuilderSectionStatus`), `builder/builder-groups.model.ts`.
- Consumers: `project-editor-page.component.ts`, `homepage-section.component.ts`,
  `project-editor-nav.component.ts`. Also drives admin products/categories/dashboard facades
  (which inject `ProjectEditorFacade`).

---

## 18. Domain: Search

**LOCAL-ONLY orchestration over the product/category providers** — no dedicated search backend;
`SearchFacade` composes `ProductFacade` + `CategoryFacade` results and manages history/trending/
autocomplete/cache client-side.

- **Facade**: `SearchFacade` (`src/app/features/search/facade/search.facade.ts`) injects
  `ProductFacade`, `CategoryFacade`, `SearchAutocompleteService`, `SearchHistoryService`,
  `SearchTrendingService`, `SearchCacheService`, `SearchStore`, `TranslateService`.
- Services (`src/app/features/search/services/`): `search-autocomplete.service.ts`,
  `search-history.service.ts` + `search-history.repository.ts` (interface
  `SearchHistoryRepository{load,save,clear}`, localStorage), `search-trending.service.ts`,
  `search-cache.service.ts`. Store: `store/search.store.ts`.
- **Models**: `src/app/features/search/models/search.model.ts` (`SearchQuery`, `SearchResult<T>`,
  `SearchSuggestion`, `SearchFilterType`, `FilterGroup`, `FilterOption`, `SortOption`,
  `SearchHistory`, `SearchAnalyticsEvent`, `SearchNavigationTarget`), `search-state.model.ts`
  (`SearchState`). Duplicated under `src/app/core/search/models/`.
- Underlying live traffic is `GET /searchitems` (§4) via `ProductFacade.searchProducts`.

---

## 19. Domain: User experience (wishlist/compare/etc.)

**LOCAL-ONLY** (guest-first). MOCK-SWAPPABLE token exists for a future authenticated backend.

- **Interface**: `UserExperienceRepository`
  (`src/app/core/user-experience/repositories/user-experience.repository.ts`).
- **DI token**: `USER_EXPERIENCE_REPOSITORY`
  (`src/app/core/user-experience/user-experience-repository.token.ts`) → currently always
  `LocalUserExperienceRepository` (localStorage). Comment notes it "can be switched to
  authenticated repository later."
- **Facade**: `UserExperienceFacade` (`src/app/facades/platform/user-experience.facade.ts`) —
  wishlist / compare / recently-viewed / saved-searches / continue-browsing, all signals.
- **Models** (`src/app/core/user-experience/models/user-experience.model.ts`): `FavoriteItem`,
  `ComparedProduct`, `RecentlyViewedItem`, `SavedSearch`, `ContinueBrowsingState`. Config shape:
  `user-experience-config.model.ts` (limits, from bootstrap).

---

## 20. Domain: Diagnostics

**LOCAL-ONLY** — inspects runtime/bootstrap/widget state; the one live-ish probe is API ping.

- **Facade**: `DiagnosticsFacade` (`src/app/features/diagnostics/facade/diagnostics.facade.ts`)
  injects `ConfigService`, `TenantResolverService`, `PlatformRuntimeStateService`,
  `RuntimeDiagnosticsService`, `WidgetManifestService`, `WidgetRegistryService`,
  `RuntimeProviderStrategyService`, `DiagnosticsLoggerService`, `TranslateService`, `Router`.
- Validators: `validators/runtime-diagnostics.validator.ts` (uses `HttpClient` for API health
  probe), `bootstrap-diagnostics.validator.ts`, `diagnostics-health-score.util.ts`.
- **Models** (`src/app/features/diagnostics/models/diagnostics.model.ts`): `DiagnosticEntry`,
  `DiagnosticSeverity`, `DiagnosticsHealthSummary`, `DiagnosticsReport`.

---

## 21. Facade catalog

| Facade | File | Depends on | Consumed by (examples) |
|---|---|---|---|
| `ProductFacade` | `facades/platform/product.facade.ts` | `ProductDataService` → `PRODUCT_DATA_PROVIDER` | catalog/product containers, `SearchFacade` |
| `CategoryFacade` | `facades/platform/category.facade.ts` | `CategoryService` → `CATEGORY_REPOSITORY` | catalog nav, `SearchFacade` |
| `SearchFacade` | `features/search/facade/search.facade.ts` | ProductFacade, CategoryFacade, search services | search bar/pages |
| `UserExperienceFacade` | `facades/platform/user-experience.facade.ts` | `USER_EXPERIENCE_REPOSITORY` | wishlist/compare UI |
| `UiRuntimeFacade` | `facades/runtime/ui-runtime.facade.ts` | `ConfigService` | header/branding |
| `WebsiteRuntimeFacade` | `facades/website/website-runtime.facade.ts` | config/page renderer | dynamic pages |
| `AuthFacade` | `core/auth/services/auth-facade.service.ts` | AuthService, SessionService, PermissionService | login/guarded UI |
| `MediaLibraryFacade` | `features/backoffice/media/facade/media-library.facade.ts` | `MediaRepository` | media page |
| `ContentManagementFacade` | `features/content-management/facade/...` | `ContentPageService` (bootstrap) | content dashboard/editor |
| `ProjectEditorFacade` | `features/project-editor/facade/...` | config + editor services (localStorage) | builder pages, admin facades |
| `DiagnosticsFacade` | `features/diagnostics/facade/...` | runtime/config/widget services | diagnostics page |
| `AdminCategoriesFacade` | `features/admin/categories/facade/...` | `ADMIN_CATEGORIES_GATEWAY`, ProjectEditorFacade | admin categories pages |
| `AdminProductsFacade` | `features/admin/products/facade/...` | `AdminProductsLocalGateway`, ProjectEditorFacade | admin products pages |
| `AdminOrdersFacade` | `features/admin/orders/facade/...` | `AdminOrdersLocalGateway` | admin orders pages |
| `AdminUsersFacade` | `features/admin/users/facade/...` | `AdminUsersLocalGateway` | admin users pages |
| `AdminTransactionsFacade` | `features/admin/transactions/facade/...` | `AdminTransactionsLocalGateway` | admin transactions pages |
| `AdminMonitoringFacade` | `features/admin/monitoring/facade/...` | `AdminMonitoringLocalGateway` | admin monitoring page |
| `AdminModerationFacade` | `features/admin/moderation/facade/...` | `AdminModerationLocalGateway` | moderation pages |
| `AdminCustomersFacade` | `features/admin/customers/facade/...` | `AdminOrdersLocalGateway` (derives customers from orders) | customers pages |
| `AdminAnalyticsFacade` | `features/admin/analytics/facade/...` | orders/products/moderation local + `ADMIN_CATEGORIES_GATEWAY` + `AdminDashboardFacade` | analytics page |
| `AdminDashboardFacade` | `features/admin/dashboard/facade/...` | `ADMIN_DASHBOARD_METRICS_GATEWAY`, ProjectEditorFacade, AdminAuthService | admin dashboard |

`ProductFacade` public API: `getProducts, getProduct, getCategories, searchProducts,
getFeaturedProducts, getLatestProducts, getProductsByCategory, getRelatedProducts, loadRating,
loadReviews, loadQuestions, submitReview, submitQuestion, search(criteria), filter, sort,
loadCatalog`. `CategoryFacade`: signals (`allCategories, categoryTree, rootCategories,
selectedCategory, breadcrumb, children, loading, error`) + `loadCategories, selectCategory,
getAllCategories, getCategoryTree, getRootCategories, getCategoryById, getBreadcrumb, getChildren`.
`UserExperienceFacade`: `isInWishlist, toggleWishlist, clearWishlist, isInCompare, addToCompare,
removeFromCompare, clearCompare, trackRecentlyViewed, saveSearch, removeSavedSearch,
saveContinueBrowsing, getContinueBrowsing` + wishlist/compare signals & counts.

---

## 22. Gateway / provider master table

| Gateway/provider | Interface path | Mock/local impl | Real/API impl | DI token | Consuming facade(s) | Status |
|---|---|---|---|---|---|---|
| ConfigProvider | `core/config/config-provider.interface.ts` | `core/bootstrap/providers/mock-bootstrap.provider.ts` | `core/bootstrap/providers/api-bootstrap.provider.ts` | `CONFIG_PROVIDER` | UiRuntime, WebsiteRuntime, ProjectEditor, ContentMgmt, Diagnostics (via ConfigService) | LIVE (`GET /bootstrap`) |
| ProductDataProvider | `core/products/providers/product-data-provider.interface.ts` | none bound | `core/products/providers/api-product-data.provider.ts` | `PRODUCT_DATA_PROVIDER` | ProductFacade | LIVE |
| CategoryRepository | `core/categories/repositories/category.repository.ts` | none bound | `core/categories/repositories/api-category.repository.ts` | `CATEGORY_REPOSITORY` | CategoryFacade | LIVE |
| BackofficeDataProvider | `core/backoffice/providers/backoffice-data-provider.interface.ts` | `mock-backoffice-data.provider.ts` | `api-backoffice-data.provider.ts` | `BACKOFFICE_DATA_PROVIDER` | storefront cards | LIVE (`/api/backoffice/*`) |
| UserExperienceRepository | `core/user-experience/repositories/user-experience.repository.ts` | `local-user-experience.repository.ts` | none | `USER_EXPERIENCE_REPOSITORY` | UserExperienceFacade | LOCAL-ONLY |
| MediaRepository | `core/media/media-repository.ts` (abstract class) | `core/media/mock-media-repository.service.ts` | none | `MediaRepository` class (app.config.ts) | MediaLibraryFacade | MOCK-SWAPPABLE |
| SearchHistoryRepository | `features/search/services/search-history.repository.ts` | (localStorage impl) | none | (injected concretely) | SearchFacade (via SearchHistoryService) | LOCAL-ONLY |
| AdminCategoriesGateway | `features/admin/categories/services/admin-categories-gateway.interface.ts` | `admin-categories-local.gateway.ts` | `admin-categories-api.gateway.ts` | `ADMIN_CATEGORIES_GATEWAY` | AdminCategoriesFacade, AdminAnalyticsFacade | MOCK-SWAPPABLE (real impl exists) |
| AdminDashboardMetricsGateway | `features/admin/dashboard/services/admin-dashboard-metrics.gateway.interface.ts` | `admin-dashboard-metrics.local.gateway.ts` | none | `ADMIN_DASHBOARD_METRICS_GATEWAY` | AdminDashboardFacade | MOCK-SWAPPABLE (token only) |
| AdminOrdersGateway | `features/admin/orders/services/admin-orders-gateway.interface.ts` | `admin-orders-local.gateway.ts` | none | **none** | AdminOrdersFacade, AdminCustomersFacade, AdminAnalyticsFacade | MOCK-ONLY (no seam) |
| AdminProductsGateway | `features/admin/products/services/admin-products-gateway.interface.ts` | `admin-products-local.gateway.ts` | none | **none** | AdminProductsFacade, AdminAnalyticsFacade | MOCK-ONLY (no seam) |
| AdminUsersGateway | `features/admin/users/services/admin-users-gateway.interface.ts` | `admin-users-local.gateway.ts` | none | **none** | AdminUsersFacade | MOCK-ONLY (no seam) |
| AdminTransactionsGateway | `features/admin/transactions/services/admin-transactions-gateway.interface.ts` | `admin-transactions-local.gateway.ts` | none | **none** | AdminTransactionsFacade | MOCK-ONLY (no seam) |
| AdminMonitoringGateway | `features/admin/monitoring/services/admin-monitoring-gateway.interface.ts` | `admin-monitoring-local.gateway.ts` | none | **none** | AdminMonitoringFacade | MOCK-ONLY (no seam) |
| AdminModerationGateway | `features/admin/moderation/services/admin-moderation-gateway.interface.ts` | `admin-moderation-local.gateway.ts` | none | **none** | AdminModerationFacade, AdminAnalyticsFacade | MOCK-ONLY (no seam) |
| (Auth session) | — (`TelegramSessionApiService`) | mock via `mockDataInterceptor` | `services/telegram-session-api.service.ts` | n/a (concrete) | AuthService, AdminAuthService, AuthFacade | LIVE |
| (Ed25519 admin auth) | — (`AuthApiService`) | none | `core/auth/services/auth-api.service.ts` | n/a (concrete) | AuthService (Ed25519 flow) | LIVE wiring, backend absent |

---

## 23. Model / DTO catalog

Grouped by boundary role. B = backend-shaped/wire DTO, V = frontend view model, C = bootstrap
config shape. Adapter column names the mapper if distinct.

### Core wire DTOs / domain (B)
- `Item` + supporting (`src/app/models/item.model.ts`) — **primary product wire shape**; adapter
  `ApiService.normalizeItem()`.
- `Category`, `Subcategory` (`src/app/models/category.model.ts`) — legacy category wire; adapter
  `ApiService.normalizeCategory()`.
- `CategoryDto`, `CategoryNameDto` (`src/app/core/categories/dto/category.dto.ts`) — clean-stack
  wire DTO; adapter `CategoryMapper`.
- `Region`, `GeoIpResponse` (`src/app/models/location.model.ts`).
- Payment/order DTOs inline in `src/app/services/api.service.ts`: `QrCreateRequest`,
  `QrCreateResponse`, `CartPaymentRequest`, `CreateOrderRequest`, `CreateOrderResponse`,
  `QrDynamicStatusResponse`.
- Auth: `AuthSession`, `WebSessionStart` (`src/app/models/auth.model.ts`); `AuthChallenge`,
  `VerifySignatureRequest`, `AuthTokenPair`, `RefreshTokenRequest`, `JwtClaims`
  (`src/app/core/auth/models/auth-api.model.ts`).

### Domain / view models (V)
- Products: `Product`(=Item alias), `ProductListQuery`, `ProductSearchQuery`, `ProductListResult`,
  `ProductFilters`, `RelatedProductsQuery`, `RelatedProductCollection`, `ProductVariantSelection`
  (`core/products/models/product-domain.model.ts`).
- Engagement: `Review`, `Answer`, `Question`, `RatingSummary`, `RatingDistributionEntry`,
  `EngagementListQuery`, `EngagementListResult<T>`, `SubmitReviewInput`, `SubmitQuestionInput`
  (`core/products/models/product-engagement.model.ts`).
- Catalog experience: `SearchCriteria`, `FilterDefinition`, `FilterOption`, `SortDefinition`,
  `CatalogView`, `SearchResult` (`core/products/models/catalog-experience.model.ts`);
  catalog state (`features/website/catalog/models/catalog-state.model.ts`).
- Category domain: `Category`, `CategoryTranslation` (`core/categories/models/category-domain.model.ts`).
- Media: `MediaAsset` + params/results (`core/media/models/media-asset.model.ts`).
- User experience: `FavoriteItem`, `ComparedProduct`, `RecentlyViewedItem`, `SavedSearch`,
  `ContinueBrowsingState` (`core/user-experience/models/user-experience.model.ts`).
- Search: `search.model.ts` + `search-state.model.ts` (`features/search/models/`, dup in `core/search/models/`).
- Content: `ContentPage`, `ContentPageTranslation`, `ContentPageSeoConfig`, `ContentPageStatus`,
  `ContentPageBootstrapInput`, `LegalPageKey`, `LegalPageDefinition`
  (`features/content-management/models/`); adapter `ContentPageService`.
- Project editor: `ProjectEditorState`, `ProjectEditorSectionId`, `ProjectEditorWidgetPreset`,
  `BuilderSectionStatus` (`features/project-editor/models/`), `builder-groups.model.ts`.
- Diagnostics: `DiagnosticEntry`, `DiagnosticsHealthSummary`, `DiagnosticsReport`
  (`features/diagnostics/models/diagnostics.model.ts`).
- Widgets: contracts in `src/app/widgets/contracts/*` and renderer `*.model.ts` (see §13).

### Admin models (V, all under `features/admin/<domain>/models/`)
- `admin-order.model.ts`: `AdminOrder`, `AdminOrderCustomer`, `AdminOrderPayment`,
  `AdminOrderShipping`, `AdminOrderItem`, `AdminOrderTimelineEntry`, `AdminOrderStatus`,
  `AdminOrderPaymentStatus`, `AdminOrderTimelineEventKey`, `AdminOrderListFilters`,
  `AdminOrdersListResult`.
- `admin-product.model.ts`: `AdminProduct` (+ `AdminProductMedia`, `AdminProductSpecification`,
  `AdminProductVariant(Price)`, `AdminProductVariantAttributeDef`, `AdminProductAttribute`,
  `AdminProductTranslation`, `AdminProductSeo`, `AdminProductReview`, `AdminProductQuestion`),
  `AdminProductListFilters`, `AdminProductsListResult`, `AdminProductCategoryOption`, status/sort/mode types.
- `admin-category.model.ts`: `AdminCategory`, `AdminCategoryTranslation`, `AdminCategorySeo`,
  `AdminCategoryAttribute`, `AdminCategoryListFilters`, status/mode types.
- `admin-user.model.ts`: `AdminUser`, `AdminRole`, `AdminInvitation`, `AdminSession`,
  `AdminUserAuditEntry`, scope/status/invitation-status types.
- `admin-transaction.model.ts`: `AdminTransaction`, `AdminTransactionAuditEntry`,
  `AdminTransactionListFilters`, `AdminTransactionsListResult`, type/status types.
- `admin-monitoring.model.ts`: `AdminMonitoringEvent`, `AdminMonitoringEventFilters`,
  `AdminQueue`, `AdminWebhookDelivery`, category/level/queue/webhook status types.
- `admin-review.model.ts`: `AdminReview`, `AdminReviewTimelineEntry`, `AdminReviewListFilters`,
  `AdminReviewsListResult`, status/timeline types.
- `admin-report.model.ts`: `AdminReport`, `AdminReportTargetType`, `AdminReportStatus`.
- `admin-customer.model.ts`: `AdminCustomer`.
- `admin-analytics.model.ts`: `AdminAnalyticsSummary`, `AdminAnalyticsSeriesPoint`,
  `AdminAnalyticsTopProduct`, `AdminLowStockProduct`, `AdminRecentActivityEntry`,
  `AdminMarketplaceHealthCheck`, `AdminProductAnalytics(Row)`, `AdminCustomerAnalytics`,
  `AdminRecommendationCard`, date-range/severity/health types.
- `admin-dashboard.model.ts`: `AdminDashboardMetrics`, `AdminDashboardCardState<T>`,
  `AdminDashboardQuickAction(Id)`, `AdminDashboardActivityEntry`, `AdminDashboardHealthCheck`,
  `AdminDashboardHomeHealthCheck`, `AdminDashboardDraftField`, `AdminDashboardShortcut`, status types.
- Shell: `features/admin/shell/admin-nav.model.ts`.

### Bootstrap config shapes (C)
All under `src/app/shared/models/config/` — see §6 for the full list (24 files + barrel).

---

## 24. Endpoint URL literals found in code

Marketplace API (relative to base): `/ping`, `/bootstrap`, `/category`, `/category/{id}`,
`/items/{id}`, `/items/randomitems`, `/searchitems`, `/cart`, `/orders`, `/purchase-email`,
`/regions`, `/websession/{sessionId}`, `/items/{id}/callback`, `/items/{id}/questiion`.

Backoffice storefront: `/api/backoffice/products`, `/api/backoffice/categories`.

Payment (`qrApiUrl` = `https://qr.vitanova.network/api`): `/qr`, `/qr/dynamic/{partnerId}/{qrId}`,
`/card/{partnerId}/{orderId}`. Const partner id `web-97ec-9c57-4dde-9037-3a68f7f83750`.

Session auth (`authApiUrl`): `/users/sessions`, `/users/sessions/{id}`.

Ed25519 admin auth (`authApiUrl`): `/api/admin/auth/challenge|verify|refresh|logout`
(not implemented server-side).

Static assets (not backend): `/assets/mock/bootstrap/bootstrap.json`,
`/assets/mock/bootstrap/widget-manifest.json`.

External (not this platform): `http://ip-api.com/json/...` (geo-IP),
`https://api.qrserver.com/v1/create-qr-code/...` (QR image), `https://t.me/{bot}`,
`tg://resolve?...`.

`mockDataInterceptor` URL matchers (mock mode only): `/ping`, `/users/sessions[/{id}]`,
`/category`, `/category/{id}`, `/items/{id}`, `/searchitems`, `/randomitems`, `/cart`,
`/websession/{id}[/qr]`, `/qr`, `/items/{id}/callback`, `/purchase-email`, `/qr/payment/{id}`.

**No literal `/admin/*`, `/builder/*`, or per-admin-domain backoffice CRUD paths exist in code.**
Those live only as `apiEndpoints.{builder,backoffice}` records inside the runtime bootstrap
document, and admin gateways are in-memory (they never construct a URL). Any concrete admin CRUD
path is therefore a proposal, not a verified literal — consistent with `docs/BACKEND_API.md`
Assumption #2.

The admin-auth-headers interceptor gates these path **segments** (anticipatory, not called yet):
`/admin/`, `/backoffice/`, `/builder/`, `/media/`.

---

## 25. Cross-check against existing docs

Skimmed: `docs/BACKEND_API.md` (canonical master spec, CURRENT/PLANNED/FUTURE tagging),
`docs/AUTH.md`, `docs/ADMIN.md`, `docs/BACKEND_API_REMAINING_WORK.md`,
`docs/architecture/foundation/**`, `docs/backend/BACKEND-INTEGRATION.md`.

Agreements (preserve these conventions downstream):
- `docs/BACKEND_API.md` already uses `GET /bootstrap`, the `*LocalGateway` → `*ApiGateway`
  rebind pattern, and frozen auth/payment (ADR-010). Its CURRENT/PLANNED/FUTURE tagging maps
  cleanly onto LIVE / MOCK-SWAPPABLE / MOCK-ONLY here.
- Assumption #2 (builder/backoffice paths are proposals, not literals) is confirmed by code.
- `submitQuestion` typo `questiion` and `callback` review path confirmed against code.

Discrepancies / things to flag for a human:
1. **`docs/BACKEND_API.md` PLANNED framing implies every admin domain is a token rebind.**
   In code, only `ADMIN_CATEGORIES_GATEWAY` and `ADMIN_DASHBOARD_METRICS_GATEWAY` are
   token-bound. Orders, products, users, transactions, monitoring, moderation (and derived
   customers/analytics) inject the concrete `*LocalGateway` directly — no seam. A backend
   integration for those requires adding a token first. This should be reconciled in the docs.
2. **Only one real admin API impl exists** (`AdminCategoriesApiGateway`). Everything else admin
   is mock. Docs that describe admin endpoints as "PLANNED, served by local gateway" are
   accurate in spirit but the swap ergonomics differ per domain (see #1).
3. **Duplicate `Category` types** (`src/app/models/category.model.ts` vs
   `core/categories/models/category-domain.model.ts`) and **duplicate `AdminRole`**
   (auth `permission.model.ts` string-union vs users `admin-user.model.ts` interface) — naming
   collisions a backend/contract author should be warned about.
4. **Duplicate search models** under `features/search/models/` and `core/search/models/`.
5. **Content-management & project-editor "save/publish" has no client HTTP call.** Docs that
   imply a builder publish endpoint should tag it FUTURE — there is no `PUT /bootstrap` or
   builder-write call anywhere in code today; changes live in localStorage drafts + in-memory
   bootstrap only.
6. `PRODUCT_DATA_PROVIDER` / `CATEGORY_REPOSITORY` token factories return the Api provider even
   in `mock` mode (no mock class bound) — so `useMockData` does NOT mock products/categories at
   the provider layer; mocking there relies entirely on `mockDataInterceptor`. Worth noting if a
   doc claims a mock product provider exists.

---

_Generated from source on branch `B2B`. Every path above is repo-relative to
`F:\dx\remote\marketplaces\`._
