Files
marketplaces/docs/BACKEND-INTEGRATION.md
sdarbinyan 54725c624e
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:29:26 +04:00

8.3 KiB
Raw Blame History

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 /bootstrapBootstrapConfig
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-RegionMoscow / ST. Petersburg / Yerevan (from region id)
    • X-LanguageRU / EN / AM
    • CurrencyRUB (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/dexarmarkethttps://api.dexarmarket.ru:445)
  3. environment.tenantApiTemplatehttps://{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 /bootstrapnew, 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.stringifys 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 §5§16. Handoff framing: 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.