# 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` ## Notificações No momento este BFF cobre apenas Feature Control (`bootstrap` + `exposure`). Para notificações segmentadas por audiência (`todos`, `feature:fc.ios`), precisamos adicionar o contrato de endpoint de notificações do Atomenta para integrar no app. ## 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 { "at.ios.only": { "enabled": true, "variant": "on" }, "at.android.only": { "enabled": true, "variant": "on" }, "at.promo": { "enabled": true, "variant": "on" }, "at.city.aguai": { "enabled": true, "variant": "on" } } ``` ## Request (App -> BFF) ```json { "environment": "production", "keys": ["at.ios.only", "at.android.only", "at.promo", "at.city.aguai"], "context": { "subjectType": "customer", "subjectId": "cust_123", "storeId": "store_001", "platform": "ios", "appVersion": "2.3.1", "attributes": { "city": "Aguaí" } } } ``` 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": { "atiosonly": true, "atandroidonly": false, "atpromo": true, "atcityaguai": true }, "raw": { "at.ios.only": { "enabled": true, "variant": "on", "payload": null, "reason": "rollout" }, "at.promo": { "enabled": true, "variant": "on", "payload": null, "reason": "rollout" } } } ``` > O app Swift usa o campo **`raw`** indexado pela chave original (ex: `raw["at.promo"]`). O campo `flags` é uma versão simplificada gerada mecanicamente (pontos removidos). ``` 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 ``` Autor: Daniel Arantes Loverde