docs: add backend integration guide + implementation prompt for B2B
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
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:
120
docs/BACKEND-INTEGRATION.md
Normal file
120
docs/BACKEND-INTEGRATION.md
Normal 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.
|
||||
Reference in New Issue
Block a user