Exact wire contract for every screen → endpoint. Base /api/v1; envelope per
00-shared/07 and response-envelope.interceptor.ts / http-exception.filter.ts.
All endpoints from src/modules/settings/settings.controller.ts; business rules from
settings.service.ts + setting.repository.ts. Global guard chain: RateLimitGuard →
JwtAuthGuard → RbacGuard (app.module.ts:129-131); the controller additionally
declares @UseGuards(JwtAuthGuard) (settings.controller.ts:19) and carries no
@Permissions metadata (OQ-2 — the global RbacGuard passes because no permission is
required, rbac.guard.ts:29).
{success:false, message, error:{code, details?}, timestamp, requestId} — codes per http-exception.filter.ts:27-35
Pagination
NOT paginated.findAll returns a bare array (settings.service.ts:10-12); the interceptor only emits meta when the payload is {data, meta} (response-envelope.interceptor.ts:25-32) → meta is omitted for every settings endpoint. Client renders the full array (no infinite scroll).
Tenancy
tenantId from JWT claim via TenantContextService (setting.repository.ts:16,34); never in body. Platform admin bypasses the tenant scope (base.repository.ts:21-23).
Caching
none server-side in the settings path; client stale-while-revalidate
Offline
reads from last-good cache + banner; writes blocked (no offline queue)
400 invalid group (details per field); 500 for missing key/value (no DTO decorators → Mongoose required error, OQ-3); 500 E11000 on recreate-after-delete (OQ-5); 401; 429
GET /feature-flags[?module=], GET /feature-flags/enabled, GET /feature-flags/:key,
PUT /feature-flags, PUT /feature-flags/bulk, DELETE /feature-flags/:key
(feature-flags.controller.ts:23-58); flag doc {key, enabled, label?, description?, module?}
(feature-flag.schema.ts:9-23).