docs: assemble BACKEND_INTEGRATION.md, single canonical backend spec
4349 lines, 9 numbered sections per the Backend Finalization Sprint spec: Bootstrap, Endpoint Framework, CRUD Contracts (~102 endpoints across 20 domains), Authentication (spliced from AUTHENTICATION.md), Security, Error Model (spliced from ERROR_CONTRACT.md), Uploads, Real Backend Implementation Guide, Backend Checklist (34 items). Everything traced to docs/context/BACKEND-AUDIT.md and actual current source - proposed (unverified) paths explicitly marked as such, everything the frontend has no opinion on marked "Requires backend decision" rather than invented. Archived the three docs this supersedes (BACKEND_API.md, AUTH.md, BACKEND_API_REMAINING_WORK.md) to docs/archive/ with pointers back to this file. AUTHENTICATION.md, ERROR_CONTRACT.md, MAINTENANCE_MODE.md kept in place as standalone companion references (their content is also inlined/cross-referenced here). ADMIN.md left untouched - it's a frontend admin-UI sprint doc, not a backend spec, no overlap. Verified via repo-wide search: no other backend/API spec docs remain outside archive/ and this canonical file.
This commit is contained in:
274
docs/archive/AUTH.md
Normal file
274
docs/archive/AUTH.md
Normal file
@@ -0,0 +1,274 @@
|
||||
> **ARCHIVED 2026-07-26.** Superseded by [`docs/BACKEND_INTEGRATION.md`](../BACKEND_INTEGRATION.md), the single canonical backend integration document. Kept for history only — do not implement against this file.
|
||||
|
||||
# Admin Authentication — Ed25519 Foundation
|
||||
|
||||
Status: **FRONTEND PREPARED, NOT LIVE.** Everything in this document describes
|
||||
code that exists in `src/app/core/auth/` today, wired to endpoints that do
|
||||
not exist on the backend yet. No route currently requires this flow — the
|
||||
live admin gate remains the Telegram-QR-based `AdminAuthService` /
|
||||
`adminAuthGuard` (`src/app/core/admin-auth/`, documented in
|
||||
`docs/BACKEND_API.md` §2.4–2.5). This module is the
|
||||
integration target once the backend ships the endpoints below.
|
||||
|
||||
Do not point any live route's `canActivate` at `ed25519AuthGuard` until the
|
||||
backend endpoints in §API Contracts exist and have been verified — doing so
|
||||
before then would lock every admin out.
|
||||
|
||||
## 1. Why this exists
|
||||
|
||||
`docs/BACKEND_API.md` §2.5 documents the current system's
|
||||
biggest security gap: admin and customer login hit the *same* Telegram
|
||||
session endpoint, so the backend has no way to distinguish an admin login
|
||||
attempt from a customer one at the moment of login — authorization is
|
||||
effectively unenforced. Ed25519 challenge/response auth closes this by
|
||||
requiring proof of possession of a specific, pre-registered private key
|
||||
before a session is ever issued, instead of "any Telegram account that
|
||||
happened to scan the right QR code."
|
||||
|
||||
## 2. Sequence diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as Admin (browser)
|
||||
participant FE as Frontend (AuthService)
|
||||
participant BE as Backend
|
||||
|
||||
Admin->>FE: Click "Sign in"
|
||||
FE->>BE: GET /api/admin/auth/challenge
|
||||
BE-->>FE: { nonce, issuedAt, expiresAt }
|
||||
FE->>FE: Ed25519KeypairService.sign(nonce)<br/>(WebCrypto, non-extractable private key)
|
||||
FE->>BE: POST /api/admin/auth/verify<br/>{ publicKey, signature, nonce }
|
||||
alt signature valid & publicKey is a provisioned admin key
|
||||
BE-->>FE: 200 { token, refreshToken }
|
||||
FE->>FE: SessionService.activate(tokens)<br/>decode JWT claims, schedule refresh
|
||||
FE-->>Admin: Redirect to /backoffice
|
||||
else invalid signature / unknown key / expired nonce
|
||||
BE-->>FE: 401/403
|
||||
FE-->>Admin: Redirect to /admin-login/error/invalid-signature
|
||||
end
|
||||
```
|
||||
|
||||
### Refresh sequence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant FE as Frontend (SessionService)
|
||||
participant IC as authInterceptor
|
||||
participant BE as Backend
|
||||
|
||||
Note over FE: Timer fires ~60s before JWT exp
|
||||
FE->>BE: POST /api/admin/auth/refresh { refreshToken }
|
||||
alt refresh token still valid
|
||||
BE-->>FE: 200 { token, refreshToken }
|
||||
FE->>FE: activate(tokens) - reschedules next refresh
|
||||
else refresh token expired/revoked
|
||||
BE-->>FE: 401
|
||||
FE->>FE: SessionService.markExpired()
|
||||
FE-->>FE: Route to /admin-login/error/session-expired
|
||||
end
|
||||
|
||||
Note over IC: Reactive path - any 401 on an admin request
|
||||
IC->>BE: Admin API request (expired token)
|
||||
BE-->>IC: 401
|
||||
IC->>BE: POST /api/admin/auth/refresh (single retry)
|
||||
alt refresh succeeds
|
||||
BE-->>IC: 200 tokens
|
||||
IC->>BE: Retry original request with new token
|
||||
else refresh fails
|
||||
IC-->>FE: Propagate error, route to session-expired
|
||||
end
|
||||
```
|
||||
|
||||
## 3. Ed25519 flow, step by step
|
||||
|
||||
1. **Key generation (once per device):** `Ed25519KeypairService.getOrCreateKeyPair()`
|
||||
generates a non-extractable Ed25519 keypair via `crypto.subtle.generateKey`
|
||||
and persists the `CryptoKey` handles in IndexedDB (`admin-auth-ed25519` DB).
|
||||
The private key is never exported, serialized, or transmitted — by
|
||||
construction, not by convention.
|
||||
2. **Registering the public key with the backend is out of scope for this
|
||||
frontend.** An Owner/Administrator must associate a new device's
|
||||
`publicKeyBase64` with an admin account through some out-of-band
|
||||
mechanism (e.g. a backend admin tool, a one-time enrollment link) before
|
||||
that device can complete step 4. This document does not prescribe that
|
||||
mechanism — it is a backend/ops concern.
|
||||
3. **Challenge:** `GET /api/admin/auth/challenge` returns a fresh `nonce` the
|
||||
client must sign before `expiresAt`.
|
||||
4. **Sign:** the raw `nonce` string is signed with the device's private key
|
||||
(`Ed25519KeypairService.sign`), producing a base64 signature.
|
||||
5. **Verify:** `POST /api/admin/auth/verify` sends `{ publicKey, signature,
|
||||
nonce }`. The backend re-derives the signed message from the nonce it
|
||||
issued, verifies the signature against its own record of that
|
||||
`publicKey → admin account` mapping, and only then issues tokens.
|
||||
6. **Session:** the returned `{ token, refreshToken }` pair is stored
|
||||
(`SessionService`, `localStorage: ed25519AdminToken` /
|
||||
`ed25519AdminRefreshToken`) and the JWT is decoded client-side for
|
||||
`role`/`exp` — decoding only, never signature verification (the frontend
|
||||
has no trusted key to check it against).
|
||||
|
||||
## 4. API contracts
|
||||
|
||||
All under `{environment.authApiUrl}/api/admin/auth` (see
|
||||
`src/environments/environment.ts`). None of these exist on the backend
|
||||
today — this is the contract the frontend was built against, not a
|
||||
confirmed backend spec.
|
||||
|
||||
| Method | Path | Request body | Response | Notes |
|
||||
|---|---|---|---|---|
|
||||
| GET | `/challenge` | — | `200 AuthChallenge` | `{ nonce, issuedAt, expiresAt }`, all ISO 8601 except `nonce` |
|
||||
| POST | `/verify` | `VerifySignatureRequest` | `200 AuthTokenPair` \| `401` \| `403` | `{ publicKey, signature, nonce }` → `{ token, refreshToken }` |
|
||||
| POST | `/refresh` | `RefreshTokenRequest` | `200 AuthTokenPair` \| `401` | `{ refreshToken }` → new pair (rotation expected — old refresh token should be invalidated server-side) |
|
||||
| POST | `/logout` | `{ refreshToken }` | `204` | Should revoke the refresh token server-side; frontend clears local state regardless of response |
|
||||
|
||||
Types: `src/app/core/auth/models/auth-api.model.ts`.
|
||||
|
||||
## 5. JWT claims
|
||||
|
||||
```ts
|
||||
interface JwtClaims {
|
||||
sub: string; // admin account id
|
||||
role: AdminRole; // 'Owner' | 'Administrator' | 'Editor' | 'Support' | 'ReadOnly'
|
||||
iat: number; // seconds since epoch
|
||||
exp: number; // seconds since epoch
|
||||
publicKey: string; // the Ed25519 public key this token was issued for
|
||||
}
|
||||
```
|
||||
|
||||
The frontend decodes these (`JwtService.decode`) for UX only — role-based UI
|
||||
gating, expiry countdowns, refresh scheduling. **Every admin API request
|
||||
must be independently authorized server-side**; a decoded-but-unverified
|
||||
claim is not proof of anything to the backend.
|
||||
|
||||
## 6. Permission model
|
||||
|
||||
Five roles, coarse-grained permission keys (`src/app/core/auth/models/permission.model.ts`):
|
||||
|
||||
| Role | Permissions |
|
||||
|---|---|
|
||||
| Owner | `backoffice.read`, `backoffice.write`, `builder.read`, `builder.write`, `users.manage`, `settings.manage` |
|
||||
| Administrator | `backoffice.read`, `backoffice.write`, `builder.read`, `builder.write`, `users.manage` |
|
||||
| Editor | `backoffice.read`, `backoffice.write`, `builder.read`, `builder.write` |
|
||||
| Support | `backoffice.read` |
|
||||
| ReadOnly | `backoffice.read`, `builder.read` |
|
||||
|
||||
This is deliberately coarse and mirrors the existing bootstrap-level
|
||||
`PermissionsConfig` shape (`src/app/shared/models/config/permissions.model.ts`).
|
||||
Finer-grained, per-domain permissions (e.g. "can edit prices but not delete
|
||||
products") stay server-side until a real permission model exists there —
|
||||
see `docs/BACKEND_API.md` §"Admin-role-required". Use
|
||||
`PermissionService.has(permission)` / `permissionGuard(permission)` to gate
|
||||
UI and routes; never treat a passing client-side check as authorization by
|
||||
itself.
|
||||
|
||||
## 7. Error screens
|
||||
|
||||
Single component (`AuthErrorPageComponent`, `/admin-login/error/:code`)
|
||||
renders all five, keyed by route param:
|
||||
|
||||
| Code | Trigger | User action offered |
|
||||
|---|---|---|
|
||||
| `session-expired` | Refresh token rejected/expired | Sign in again |
|
||||
| `invalid-signature` | `verify` returns 401/403 during login | Try again |
|
||||
| `unauthorized` | Route guard sees no active session | Sign in |
|
||||
| `forbidden` | `permissionGuard` denies (authenticated but insufficient role) | Back to dashboard |
|
||||
| `backend-unavailable` | Network error / 5xx / status 0 | Retry |
|
||||
|
||||
`authErrorCodeFromStatus` (`models/auth-error.model.ts`) maps HTTP status →
|
||||
code: `401→unauthorized`, `403→forbidden`, `0→backend-unavailable`,
|
||||
`5xx→backend-unavailable`, else `unauthorized`. `AuthService.login()`
|
||||
additionally maps any failure during the challenge/sign/verify sequence to
|
||||
`invalid-signature` when it isn't a clearer HTTP-status-derived code.
|
||||
|
||||
## 8. Refresh lifecycle
|
||||
|
||||
- On `SessionService.activate(tokens)`, a timer is scheduled for
|
||||
`max(exp - now - 60s, 5s)` — refresh fires ~60 seconds before expiry so a
|
||||
concurrent request never races an expiring token.
|
||||
- **Proactive path:** the timer fires `AuthService.refresh()` directly.
|
||||
- **Reactive path:** `authInterceptor` catches a 401 on any admin-gated
|
||||
request, attempts one `refresh()`, retries the original request once on
|
||||
success, and routes to `session-expired` on failure. It does not retry
|
||||
more than once — a second 401 after a successful-looking refresh means
|
||||
something is wrong server-side, not a transient race.
|
||||
- `SessionService.restore()` runs on app bootstrap (call
|
||||
`AuthFacade.restoreSession()` from an app initializer once this flow goes
|
||||
live) — reads persisted tokens, decodes claims, and either resumes with a
|
||||
scheduled refresh or marks `expired` without any network call, so a stale
|
||||
session is caught before it reaches any component.
|
||||
|
||||
## 9. Module map
|
||||
|
||||
```
|
||||
src/app/core/auth/
|
||||
├── auth.routes.ts # /admin-login, /admin-login/error/:code
|
||||
├── models/
|
||||
│ ├── auth-api.model.ts # AuthChallenge, VerifySignatureRequest, AuthTokenPair, JwtClaims
|
||||
│ ├── auth-error.model.ts # AuthErrorCode, authErrorCodeFromStatus()
|
||||
│ └── permission.model.ts # AdminRole, Permission, ROLE_PERMISSIONS
|
||||
├── services/
|
||||
│ ├── ed25519-keypair.service.ts # WebCrypto keygen/sign, IndexedDB persistence
|
||||
│ ├── auth-api.service.ts # HttpClient calls to the 4 endpoints in §4
|
||||
│ ├── jwt.service.ts # decode-only JWT parsing
|
||||
│ ├── session.service.ts # token/claims state, persistence, refresh scheduling
|
||||
│ ├── permission.service.ts # role -> permission set
|
||||
│ ├── auth.service.ts # orchestrates challenge -> sign -> verify -> refresh -> logout
|
||||
│ └── auth-facade.service.ts # public surface for components
|
||||
├── interceptors/
|
||||
│ └── auth.interceptor.ts # Authorization: Bearer + 401 refresh-and-retry
|
||||
├── guards/
|
||||
│ ├── ed25519-auth.guard.ts # requires SessionService.isAuthenticated()
|
||||
│ └── permission.guard.ts # permissionGuard(permission) factory
|
||||
└── pages/
|
||||
├── admin-login-page.component.* # sign-in UI
|
||||
└── auth-error-page.component.* # parameterized error screen (§7)
|
||||
```
|
||||
|
||||
`AuthFacade` is the only thing components/pages should depend on;
|
||||
`AuthService`/`SessionService`/`PermissionService` are internal
|
||||
collaborators reachable through it.
|
||||
|
||||
## 10. Cutover plan (when the backend ships)
|
||||
|
||||
1. Verify the four endpoints in §4 against a real backend, including error
|
||||
shapes.
|
||||
2. Register `authInterceptor` in `app.config.ts`'s `withInterceptors([...])`
|
||||
list (currently not registered).
|
||||
3. Decide the relationship to the existing Telegram flow: replace
|
||||
`adminAuthGuard` with `ed25519AuthGuard` outright, or run both and let
|
||||
role/tenant config pick — this is a product decision, not made here.
|
||||
4. Wire `AuthFacade.restoreSession()` into an `APP_INITIALIZER` (or root
|
||||
component `ngOnInit`) so a page refresh restores state before any guard
|
||||
runs.
|
||||
5. Only after 1–4: point `/backoffice` and `/edit`'s `canActivate` at
|
||||
`ed25519AuthGuard` (and `permissionGuard(...)` where a route needs a
|
||||
specific role).
|
||||
|
||||
## 11. Security considerations
|
||||
|
||||
- **Private key never leaves the device.** Generated non-extractable via
|
||||
WebCrypto; `Ed25519KeypairService` has no export path. Losing the device
|
||||
means losing the key — key rotation/recovery (revoking a lost device's
|
||||
public key, provisioning a new one) is a backend/ops process, not
|
||||
implemented here.
|
||||
- **The frontend is not the authorization boundary.** Every admin
|
||||
request must be independently checked server-side against the caller's
|
||||
actual role, exactly as `docs/BACKEND_API.md` §2.5
|
||||
already states for the Telegram flow. A decoded JWT claim or a passing
|
||||
`PermissionService.has()` check is UX, not proof.
|
||||
- **Refresh tokens should rotate.** Every `POST /refresh` response is
|
||||
expected to include a *new* refresh token; the backend should invalidate
|
||||
the one just used. The frontend always stores whatever pair it receives
|
||||
and never reuses an old refresh token after a successful rotation.
|
||||
- **CSRF/replay:** the nonce from `/challenge` must be single-use and
|
||||
time-boxed server-side (`expiresAt`) — the frontend enforces nothing here
|
||||
beyond passing the nonce back unmodified; replay protection is the
|
||||
backend's responsibility.
|
||||
- **No fallback to unsigned auth.** There is no code path in this module
|
||||
that issues a session without a valid signature. If the backend is
|
||||
unreachable, the user sees `backend-unavailable`, never a degraded or
|
||||
bypassed login.
|
||||
- **Dev bypass exclusion:** unlike `AdminAuthService.devBypassLogin()` in
|
||||
the Telegram flow, this module intentionally has no dev bypass — an
|
||||
Ed25519 keypair is cheap to generate locally, so local testing should
|
||||
point at a real (even if mocked-in-dev) `/challenge`/`/verify` pair
|
||||
rather than fabricating a session.
|
||||
1746
docs/archive/BACKEND_API.md
Normal file
1746
docs/archive/BACKEND_API.md
Normal file
File diff suppressed because it is too large
Load Diff
92
docs/archive/BACKEND_API_REMAINING_WORK.md
Normal file
92
docs/archive/BACKEND_API_REMAINING_WORK.md
Normal file
@@ -0,0 +1,92 @@
|
||||
> **ARCHIVED 2026-07-26.** Superseded by [`docs/BACKEND_INTEGRATION.md`](../BACKEND_INTEGRATION.md), the single canonical backend integration document. Kept for history only — do not implement against this file.
|
||||
|
||||
# Remaining backend work (everything except auth/session)
|
||||
|
||||
Companion to the `API-CONTRACT.md` backend delivered separately (covers `GET /bootstrap`
|
||||
transport + `/users/sessions/*` — done, see prior conversation). This file lists what's
|
||||
still outstanding. Full request/response shapes, TypeScript
|
||||
interfaces, and validation rules for every item below already exist in
|
||||
[`docs/BACKEND_API.md`](BACKEND_API.md) — this is a prioritized
|
||||
punch list with links into that spec, not a duplicate of it. **Do not re-document
|
||||
endpoint shapes here** — edit the master spec if a shape needs to change.
|
||||
|
||||
Status legend (same as master spec): **PLANNED** = shape fully specified client-side,
|
||||
served by a mock gateway today, nothing built server-side yet. **FUTURE** = reserved
|
||||
contract only, no urgency. Bootstrap's *content* (branding/theme/nav values, not the
|
||||
`GET /bootstrap` transport itself) is also still outstanding — see P0 below.
|
||||
|
||||
---
|
||||
|
||||
## Status legend for this list
|
||||
|
||||
**DONE** = wired end-to-end on the frontend (real HTTP gateway or real call site, no mock
|
||||
left in the path). **PLANNED** = shape fully specified client-side, still served by a mock
|
||||
gateway, nothing wired yet. Everything below that isn't marked DONE is still open.
|
||||
|
||||
## P0 — blocks going live at all
|
||||
|
||||
| # | Item | Status | Spec section |
|
||||
|---|---|---|---|
|
||||
| 1 | `bootstrap.json` real content (branding, theme, navigation, seo) — currently default stubs per backend's own note in API-CONTRACT.md | open | [§4](BACKEND_API.md#4-bootstrap) |
|
||||
| 2 | Builder — bootstrap draft/publish/validate (`GET/PUT /builder/bootstrap/draft`, `POST /builder/bootstrap/publish`, `POST /builder/bootstrap/validate`) — this is how the Marketplace Builder actually saves anything | open | [§6.7](BACKEND_API.md#67-builder--bootstrap-draftpublishvalidate-planned-highest-priority) |
|
||||
| 3 | Backoffice — Products CRUD + variants | open | [§6.10](BACKEND_API.md#610-backoffice--products-planned), DTOs [§7.2](BACKEND_API.md#72-products--srcappfeaturesadminproductsmodelsadmin-productmodelts) |
|
||||
| 4 | Backoffice — Categories CRUD (tree) | **DONE** — `admin-categories-api.gateway.ts` + `admin-categories-gateway.token.ts` wired, swaps on `RuntimeProviderStrategyService` | [§6.9](BACKEND_API.md#69-backoffice--categories-planned), DTOs [§7.1](BACKEND_API.md#71-categories--srcappfeaturesadmincategoriesmodelsadmin-categorymodelts) |
|
||||
| 5 | Media upload/delete/replace pipeline | open | [§6.18](BACKEND_API.md#618-media-planned--adr-0002), [§10](BACKEND_API.md#10-media) |
|
||||
|
||||
## P1 — needed for real order/commerce flow
|
||||
|
||||
| # | Item | Status | Spec section |
|
||||
|---|---|---|---|
|
||||
| 6 | Backoffice — Orders CRUD + status transitions | open | [§6.11](BACKEND_API.md#611-backoffice--orders-planned), state machine [§8.1](BACKEND_API.md#81-orders--adminorderstatus) |
|
||||
| 7 | Backoffice — Transactions (list/detail, tied to orders) | open | [§6.12](BACKEND_API.md#612-backoffice--transactions-planned) |
|
||||
| 8 | Order creation — checkout calls `POST /orders` on payment success | **DONE** — `ApiService.createOrder()` + `CartComponent.recordOrder()`, fire-and-forget alongside `clearCart()`, doesn't touch the frozen payment call chain | [§16.9](BACKEND_API.md#169-order-creation-future--no-order-creation-endpoint-exists-anywhere-yet) |
|
||||
| 9 | Backoffice — Users/roles/invitations | open | [§6.13](BACKEND_API.md#613-backoffice--users-roles-invitations-planned) |
|
||||
| 10 | Backoffice — Moderation (review + report status transitions) | open | [§6.14](BACKEND_API.md#614-backoffice--moderation-reviews--reports-planned), state machines [§8.4](BACKEND_API.md#84-reviews--adminreviewstatus)/[§8.5](BACKEND_API.md#85-reports--adminreportstatus) |
|
||||
|
||||
## P2 — dashboards / operational visibility
|
||||
|
||||
| # | Item | Status | Spec section |
|
||||
|---|---|---|---|
|
||||
| 11 | Backoffice — Dashboard metrics & recent activity | open | [§6.15](BACKEND_API.md#615-backoffice--dashboard-metrics--recent-activity-planned) |
|
||||
| 12 | Backoffice — Monitoring (all but Health) | open | [§6.16](BACKEND_API.md#616-backoffice--monitoring-planned-except-health) |
|
||||
| 13 | Backoffice — Analytics summary (real once orders are real) | open | [§6.17](BACKEND_API.md#617-backoffice--analytics-mostly-future--no-data-source) |
|
||||
| 14 | Builder — Content pages / CMS | open | [§6.8](BACKEND_API.md#68-builder--content-pages--cms-planned) |
|
||||
|
||||
## P3 — nice-to-have, no urgency
|
||||
|
||||
| # | Item | Status | Spec section |
|
||||
|---|---|---|---|
|
||||
| 15 | Search suggestions / catalog filters | open | [§6.6](BACKEND_API.md#66-search--autocomplete--trending-planned) |
|
||||
| 16 | Cross-device wishlist/compare/saved-searches sync — backend confirmed id-only stays, added `GET /items/batch?ids=` for hydration. Frontend needs `UserExperienceRepository` redesign: id-array + local product cache hydrated via the batch endpoint, replacing today's fully-synchronous denormalized-object storage | open (unblocked, not started) | [§6.6](BACKEND_API.md#66-search--autocomplete--trending-planned) |
|
||||
| 17 | Analytics traffic/funnels/heatmaps — needs a tracking pipeline that doesn't exist yet, not just an endpoint | open | [§6.17](BACKEND_API.md#617-backoffice--analytics-mostly-future--no-data-source) |
|
||||
| 18 | Sitemap — dynamic generation (static baseline today) | open (server-side, no frontend action) | [§6.19](BACKEND_API.md#619-sitemap-future--static-baseline-only-today) |
|
||||
|
||||
---
|
||||
|
||||
## Explicitly not in this list
|
||||
|
||||
- Auth / Telegram session (`GET /bootstrap` transport, `/users/sessions/*`) — covered by
|
||||
backend's `API-CONTRACT.md`, frontend wiring matches it exactly.
|
||||
- `authApiUrl` env value — **fixed**, now points at the same host as `apiUrl`
|
||||
(`https://api.dexarmarket.ru:445`) in both `environment.ts` and `environment.production.ts`.
|
||||
- `AdminWebSessionID` header — **fixed a real bug**: the interceptor only attached it to
|
||||
URLs containing `/admin/`, but every real backend path is `/backoffice/*`, `/builder/*`,
|
||||
`/media/*` — none of those matched, so every new admin call would have silently gone out
|
||||
with no admin auth header at all. Broadened the guard in `admin-auth-headers.interceptor.ts`.
|
||||
- `telegramBot` username — still unverified against `bot.go`'s `startbot()`.
|
||||
- Frontend deploy domain vs. CORS allow-list — **decided**: frontend and API stay on the
|
||||
same domain, so this is a non-issue by design rather than something to reconcile against
|
||||
an allow-list.
|
||||
- Payments — frozen, unchanged, out of scope per [§2.8](BACKEND_API.md#28-payments-frozen-documented-for-completeness).
|
||||
- Storefront reads/writes (categories, items, search, cart, reviews) — already real HTTP,
|
||||
already working, no backend work needed. See [§6.1](BACKEND_API.md#61-storefront-reads-current--frozen-shapes-srcappservicesapiservicets)–[§6.2](BACKEND_API.md#62-storefront-writes-current--frozen-shapes).
|
||||
|
||||
## For every open item above, when implementing
|
||||
|
||||
Read the interface + model file cited in the linked spec section before writing the
|
||||
endpoint — the shape is already fixed by the frontend gateway interface, not up for
|
||||
renegotiation without a frontend change. Follow the pattern now established for Categories
|
||||
(`admin-categories-api.gateway.ts` + `admin-categories-gateway.token.ts`): one `*ApiGateway`
|
||||
class implementing the existing `*Gateway` interface, plus one `InjectionToken` factory that
|
||||
picks mock vs. real off `RuntimeProviderStrategyService`, then switch the facade(s) to inject
|
||||
the token instead of the concrete mock class. See [§14](BACKEND_API.md#14-backend-replacement-pattern) for the general pattern.
|
||||
Reference in New Issue
Block a user