feat(feature-control): add standalone BFF with bootstrap, exposure telemetry and tests
This commit is contained in:
89
feature-control-bff/README.md
Normal file
89
feature-control-bff/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 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 <JWT>`, 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
|
||||
```
|
||||
Reference in New Issue
Block a user