Files
marketplaces/docs/BACKEND-INTEGRATION.md
sdarbinyan 41a9315b6e
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
@
docs: add backend integration guide + implementation prompt for B2B

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>
@
2026-07-17 00:28:32 +04:00

121 lines
8.3 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 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.