Files
marketplaces/docs/context/BACKEND-AUDIT.md
sdarbinyan fd7ffc8668 docs: full frontend backend-surface audit (BACKEND-AUDIT.md)
Exhaustive inventory of every HTTP call, gateway (interface + mock +
real impl), facade, and model/DTO the frontend defines or expects,
grouped by domain. Primary input for the remaining Backend
Finalization Sprint docs.

Key findings:
- Only AdminCategoriesGateway and AdminDashboardMetricsGateway are
  DI-token-bound; every other admin domain (orders, products, users,
  transactions, monitoring, moderation) injects its *LocalGateway
  class directly - a real backend swap needs a token added first, not
  just a rebind.
- Only one real admin API impl exists (AdminCategoriesApiGateway);
  everything else admin is in-memory/localStorage mock.
- Content-management/project-editor have no save/publish HTTP call at
  all - builder writes are in-memory + localStorage draft only.
- No literal /admin|/builder|/backoffice CRUD paths exist in source;
  concrete admin paths are proposals, not verified literals.
2026-07-26 01:05:26 +04:00

824 lines
55 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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\`._