docs: add backend integration guide + implementation prompt for B2B
Some checks failed
Architecture Governance / architecture (push) Has been cancelled

Document how the B2B storefront sends/gets data vs main (base-URL
resolution, bootstrap fetch, interceptor chain, headers) and the new
builder/backoffice surface awaiting a real API. Add a self-contained
hand-off prompt. Login and payments left untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-07-17 00:28:32 +04:00
parent 3474581122
commit 54725c624e
2 changed files with 174 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
# Backend Implementation Prompt — B2B branch
Copy-paste this to a backend developer or an AI agent. It is self-contained; pair it with [`BACKEND-INTEGRATION.md`](BACKEND-INTEGRATION.md) (contract detail) and [`BACKEND.md`](BACKEND.md) (per-domain models).
---
## Prompt
You are implementing the backend for the **`B2B` branch** of an Angular marketplace/storefront + admin builder. The frontend is already built and runs offline against mocks. Your job is to expose real HTTP endpoints the frontend already calls. **Do not touch authentication (Telegram QR session) or payments — those contracts are frozen and out of scope.**
### Context you must honor
- **Single build, multi-tenant.** Base URL is resolved per-tenant at runtime. Serve each tenant at `https://<tenant>.api.dexarmarket.ru:445` (template) or get it registered in `environment.tenantApiBaseUrls`. Default tenant → `https://api.dexarmarket.ru:445`.
- Every storefront request carries headers: `X-Region` (`Moscow`/`ST. Petersburg`/`Yerevan`), `X-Language` (`RU`/`EN`/`AM`), `Currency` (`RUB`/`USD`/`AMD`), `WebSessionID` (32-char hex). Localize and session-scope responses off these.
- The frontend normalizes both legacy and "backOffice" field variants, but you should match the documented models to avoid surprises.
### Part A — Keep existing storefront endpoints working (already in `main`, do not change shapes)
- `GET /ping`
- `GET /category`
- `GET /category/:id?count=&skip=`
- `GET /items/:id`
- `GET /searchitems?search=&count=&skip=&categoryIDs=&minPrice=&maxPrice=&tag=&sort=``{ items, total }`
- `GET /items/randomitems?count=&category=`
- `POST /websession/:sessionId` (cart lines)
- `POST /items/:id/callback` (review), `POST /items/:id/questiion` (question — keep the typo), `POST /purchase-email`
### Part B — New: `GET /bootstrap` (blocking dependency for prod)
Return one JSON document of type `BootstrapConfig` per tenant: `tenant, branding, theme, company, featureFlags, apiEndpoints, localization, seo, permissions, navigation, footer, pages, staticPages, widgetRegistry`.
- Schema: `src/app/shared/models/config/bootstrap-config.model.ts`
- Reference payload to match field-for-field: `src/assets/mock/bootstrap/bootstrap.json`
- Must be cacheable; frontend loads it once at startup.
### Part C — New: Builder (Project Editor persistence) — highest priority
The editor edits the same `BootstrapConfig` the storefront reads. Implement:
- `GET /builder/bootstrap/draft` → current draft
- `PUT /builder/bootstrap/draft` ← save draft (whole document)
- `POST /builder/bootstrap/publish` → promote draft to the live `GET /bootstrap`
- `POST /builder/bootstrap/validate` (optional endpoint) — **but server-side validation on publish is mandatory**; treat the client validator as untrusted.
### Part D — New: Backoffice (admin) CRUD, per domain
For each domain — categories, products, orders, transactions, users/roles, dashboard metrics, monitoring, media — expose REST endpoints under `/backoffice/<domain>` matching the interfaces the frontend mock gateways implement. Model shapes and required operations per domain: `BACKEND.md` §5§16 and `features/admin/<domain>/models/*.model.ts` / `*-gateway.interface.ts`. The frontend swaps mock→api by rebinding one DI token per domain; your endpoints must satisfy the same interface (list/get/create/update/soft-delete/restore/draft-publish where the interface declares them).
### Constraints
- No changes to auth or payment endpoints.
- Preserve existing storefront request/response shapes exactly.
- Populate `apiEndpoints.website / builder / backoffice` in the bootstrap document as you add endpoints, so the frontend can discover them.
- Add server-side authorization: admin/builder sessions must be distinguishable from customer sessions server-side (the frontend cannot enforce this).
### Deliverables
1. `GET /bootstrap` per tenant.
2. Builder draft/publish/validate with server-side re-validation.
3. Backoffice CRUD per domain against the documented interfaces.
4. OpenAPI/spec for B, C, D. Storefront (A) is already specified by the client normalizers — do not deviate.
Ask before assuming any field you cannot find in the referenced models or `bootstrap.json`.

120
docs/BACKEND-INTEGRATION.md Normal file
View File

@@ -0,0 +1,120 @@
# Backend Integration — B2B branch
How the `B2B` frontend **sends** and **gets** data, and how that differs from `main`.
Scope excludes **login/auth** and **payments** — those contracts are frozen and untouched here.
Source of truth in code:
- `src/app/services/api.service.ts` — storefront reads/writes
- `src/app/core/config/api-config.service.ts` — base-URL resolution
- `src/app/interceptors/api-base-url.interceptor.ts` + `api-headers.interceptor.ts` — request rewriting + headers
- `src/app/core/config/config.service.ts` + `core/bootstrap/providers/*` — bootstrap load
- `src/app/shared/models/config/*` — bootstrap/endpoint models
---
## 1. What changed vs `main` (one screen)
| Concern | `main` | `B2B` |
|---|---|---|
| API base URL | Hardcoded `environment.apiUrl` (`/api`) | Resolved per-tenant at runtime by `ApiConfigService` |
| Multi-tenant | One build per brand (`environment.lavero.ts`, `index.novo.html`, …) | **Single build**, tenant resolved from host; per-brand env/html files deleted |
| Config source | Compiled into `environment.ts` (brand, theme, logo, phones) | Fetched at runtime via **`GET /bootstrap`** → `BootstrapConfig` |
| Data providers | `ApiService` called directly everywhere | Same endpoints, now behind **repository/provider interfaces + DI tokens** (swap mock↔api without touching UI) |
| Mock strategy | `mockDataInterceptor` intercepts HTTP | Provider/gateway pattern picks mock vs api per domain (`RuntimeProviderStrategyService`) |
| Interceptor chain | `[mockData, apiHeaders, cache]` | `[mockData, **apiBaseUrl**, apiHeaders, adminAuth, cache]` |
| Storefront read/write endpoints | see §3 | **unchanged in shape** |
**Bottom line for backend:** the storefront read/write contract (categories, items, search, cart, reviews) is the **same as `main`**. What is *new* is (a) a `GET /bootstrap` document the frontend now depends on, and (b) two whole endpoint namespaces (`builder`, `backoffice`) that are declared but **empty** and served by client-side mocks today.
---
## 2. How a request is built (B2B pipeline)
Every storefront call goes through this chain:
1. Code calls `this.http.get('/api/category')` (or `${apiConfig.getBaseUrl()}/category`).
2. **`apiBaseUrlInterceptor`** — if the URL starts with `/api`, rewrites it to the resolved tenant base via `ApiConfigService.toApiUrl()`.
3. **`apiHeadersInterceptor`** — on any API request, attaches:
- `X-Region``Moscow` / `ST. Petersburg` / `Yerevan` (from region id)
- `X-Language``RU` / `EN` / `AM`
- `Currency``RUB` (default) / `USD` / `AMD`
- `WebSessionID` — 32-char hex; from auth session if present, else a persisted anonymous id (`localStorage: web_session_id`)
4. Request goes out to the resolved absolute base.
### Base-URL resolution (`ApiConfigService.getBaseUrl`)
Priority order:
1. localhost → `environment.localhostApiUrl` (`/api`, proxied by dev server)
2. `environment.tenantApiBaseUrls[tenantKey]` (e.g. `default`/`dexarmarket``https://api.dexarmarket.ru:445`)
3. `environment.tenantApiTemplate``https://{tenant}.api.dexarmarket.ru:445`
4. (opt-in) `bootstrap.apiEndpoints.website.baseUrl` / `bootstrap.tenant.apiBaseUrl` — only if `allowBootstrapApiOverride: true` **and** absolute
5. fallback `environment.apiUrl`
> Backend impact: for a **new tenant**, either add it to `tenantApiBaseUrls`, or serve it at `https://<tenant>.api.dexarmarket.ru:445` so the template matches. No frontend rebuild needed if the template host pattern holds.
---
## 3. GET — reads (storefront, real HTTP today)
Identical shapes to `main`. `ApiService` normalizes legacy **and** backOffice response formats (see `normalizeItem`/`normalizeCategory` — dual field names, `0x`-hex colours, `names[]`→translations, `imgs[]`→photos, Go-typo tolerance like `valuue`).
| Method | Endpoint | Notes |
|---|---|---|
| `getCategories()` | `GET /category` | retry ×2 backoff |
| `getCategoryItems(id,count,skip)` | `GET /category/:id?count=&skip=` | |
| `getItem(id)` | `GET /items/:id` | rating/reviews/questions derived from item |
| `searchItems(q,count,skip,opts)` | `GET /searchitems?search=&count=&skip=&categoryIDs=&minPrice=&maxPrice=&tag=&sort=` | returns `{items,total}` |
| `getRandomItems(count,category?)` | `GET /items/randomitems?count=&category=` | featured/related |
| `ping()` | `GET /ping` | health |
`GET /bootstrap`**new, required in prod.** Returns the full `BootstrapConfig` (tenant, branding, theme, company, featureFlags, `apiEndpoints`, localization, seo, permissions, navigation, footer, pages, staticPages, widgetRegistry). Loaded once, cached (`ConfigService.loadBootstrap`, `shareReplay(1)`). Shape: `src/app/shared/models/config/bootstrap-config.model.ts`; canonical example: `src/assets/mock/bootstrap/bootstrap.json`.
On **localhost** (or `useMockData:true`) the `MockBootstrapProvider` serves `bootstrap.json` instead of hitting `/bootstrap`, so the app runs fully offline (`npm run dexar`).
---
## 4. POST — writes (storefront, real HTTP today)
Unchanged from `main` (payment writes omitted per scope):
| Method | Endpoint | Body |
|---|---|---|
| `addToCart(sessionId, items)` | `POST /websession/:sessionId` | `[{itemID,quantity,colour?,size?,price?}]` |
| `submitReview({...})` | `POST /items/:id/callback` | `{rating,comment,sessionID,timestamp}` |
| `submitQuestion({...})` | `POST /items/:id/questiion` | `{question,sessionID,timestamp}`**note existing path typo, keep it** |
| `submitPurchaseEmail({...})` | `POST /purchase-email` | `{email,phone?,telegramUserId,items[]}` |
---
## 5. New backend surface the frontend is waiting on
Declared in the bootstrap model (`apiEndpoints.builder`, `apiEndpoints.backoffice`) but currently `{}` empty and served by **localStorage / in-memory gateways**. UI is done; wiring a real API = implement one gateway/provider against the existing interface and rebind its DI token — no page/component changes.
### 5a. Builder (Project Editor) — **highest priority**
The editor edits the same `BootstrapConfig` the storefront consumes. Today `ProjectEditorIoService` only `JSON.stringify`s it (export) — **no HTTP, no persistence**. Needed:
- `GET /builder/bootstrap/draft` → current draft `BootstrapConfig`
- `PUT /builder/bootstrap/draft` ← save draft
- `POST /builder/bootstrap/publish` → promote draft to the live `GET /bootstrap` document
- `POST /builder/bootstrap/validate` (optional) → **server-side re-validation is mandatory**; the client validator is not a trust boundary
### 5b. Backoffice (admin) — mock gateways awaiting real API
Each domain has a `*Gateway`/`*Provider` interface + a `*LocalGateway` mock bound via token. Implement `*ApiGateway` against the same interface, endpoints under `/backoffice/...`, models in `features/admin/<area>/models/*.model.ts`:
categories, products, orders, transactions, users/roles, dashboard metrics, monitoring feeds, media.
Provider selection is centralized in `RuntimeProviderStrategyService` (`getBackofficeProviderMode`, `getProductProviderMode`, `getCategoryProviderMode`): returns `mock` only when `environment.useMockData`, else `api`.
> Full per-domain punch list and model shapes: [`BACKEND.md`](BACKEND.md) §5§16. Handoff framing: [`BACKEND-DIFF-VS-MAIN.md`](BACKEND-DIFF-VS-MAIN.md).
---
## 6. Contract rules for the backend
- **Do not change** existing storefront read/write shapes (categories, items, search, cart, reviews, questions) — frontend `main` and `B2B` both depend on them.
- **Serve `GET /bootstrap`** matching `bootstrap-config.model.ts`. Field-name tolerance exists on the client, but match the model to avoid normalization surprises.
- Respect request headers `X-Region`, `X-Language`, `Currency`, `WebSessionID` for localization/session-scoped responses.
- New namespaces `builder/*` and `backoffice/*` are yours to define; keep them consistent with the declared `apiEndpoints` block so they can be published via bootstrap.
- **Out of scope here:** auth (Telegram QR session) and payments (`/qr`, `/card`, `/cart` payment) — unchanged, see existing docs.
---
## 7. Known reliability issue (not fixable in frontend)
Intermittent `502`/`504` on refresh/back-nav in prod originate from the upstream reverse proxy at `api.dexarmarket.ru:445` / `users.vitanova.network:456` — the frontend calls those absolute URLs directly. Needs DevOps/backend investigation of upstream health/timeouts around bootstrap + session-check.