# Feature Control BFF BFF mínimo para expor flags ao app sem expor `Atomenta-Token` no cliente. ## Endpoint - `POST /feature-control/bootstrap` - `POST /feature-control/telemetry/exposure` - `GET /health` ## Variáveis de ambiente - `PORT` (default: `8787`) - `ATOMENTA_ORIGIN` (default: `https://atomenta.com.br`) - `FEATURE_CONTROL_MODULE_TOKEN` (ou `ATOMENTA_FEATURE_CONTROL_MODULE_ID`) **obrigatório** - `FEATURE_CONTROL_ENVIRONMENT` (default: `production`) - `FEATURE_CONTROL_CACHE_TTL_MS` (default: `60000`) - `FEATURE_CONTROL_TIMEOUT_MS` (default: `2000`) - `FEATURE_CONTROL_DEFAULTS_JSON` (opcional, JSON com defaults de fallback) Exemplo de `FEATURE_CONTROL_DEFAULTS_JSON`: ```json { "fc.checkout_v2": { "enabled": false, "variant": "off" }, "fc.search_ranking_v3": { "enabled": true, "variant": "on", "payload": { "model": "v3" } } } ``` ## Request (App -> BFF) ```json { "environment": "production", "keys": ["fc.checkout_v2", "fc.search_ranking_v3"], "context": { "subjectType": "customer", "subjectId": "cust_123", "storeId": "store_001", "platform": "ios", "appVersion": "2.3.1", "attributes": { "city": "Belo Horizonte", "tier": "gold" } } } ``` Se o app enviar `Authorization: Bearer `, o BFF tenta extrair `subjectId` do JWT (`sub`/`customerId`/`id`) quando `context.subjectId` não vier. ## Response (BFF -> App) ```json { "ok": true, "source": "live", "configVersion": 7, "evaluatedAt": "2026-04-16T12:00:00.000Z", "flags": { "checkoutV2": true, "searchRankingV3": "off" }, "raw": { "fc.checkout_v2": { "enabled": true, "variant": "on", "payload": null, "reason": "rollout" } } } ``` Quando o upstream falha (ex.: `429`, `500`, timeout), o BFF devolve `fallback` com defaults estáticos. ## Execução local ```bash cd feature-control-bff FEATURE_CONTROL_MODULE_TOKEN="550e8400-e29b-41d4-a716-44665544000b" npm start ``` ## Testes ```bash cd feature-control-bff npm test ```