# Redis

Configuracao e uso do Redis 7 no Monetarie PIX para rate limiting, blacklist de tokens, idempotencia e cache.

## Pre-requisitos

- Redis 7.x instalado e acessivel na rede
- Conectividade entre os pods PIX e o servidor Redis
- Variaveis de ambiente `REDIS_HOST` e `REDIS_PORT` configuradas
- Memoria disponivel de pelo menos 1GB para carga PIX

## Casos de Uso no Monetarie PIX

O Redis e utilizado para 4 funcionalidades distintas no Monetarie PIX:

```mermaid
flowchart TB
    subgraph Redis["Redis 7"]
        RL["Rate Limiting<br/>Token Bucket"]
        TB["Token Blacklist<br/>JWT Revogacao"]
        IK["Idempotency Keys<br/>24h TTL"]
    end

    subgraph PIX["Monetarie PIX"]
        AUTH["Login / MFA<br/>Endpoints"]
        LOGOUT["Logout<br/>Endpoints"]
        PAY["POST /payments<br/>POST /transactions"]
    end

    subgraph ETS["ETS (in-memory)"]
        CB["Circuit Breaker<br/>Estado atomico"]
        RBAC["RBAC Cache<br/>5-min TTL"]
    end

    AUTH --> RL
    LOGOUT --> TB
    PAY --> IK

    style Redis fill:#dc382c,stroke:#333,color:#fff
    style ETS fill:#4b8bbe,stroke:#333,color:#fff
```

::: info CIRCUIT BREAKER NAO USA REDIS
O circuit breaker (`SettlementService.CircuitBreaker`) usa **ETS** (memoria local), nao Redis. Isso garante acesso atomico via `:ets.update_counter/4` sem latencia de rede. O cache RBAC (`RequirePermission`) tambem usa ETS com TTL de 5 minutos.
:::

## Configuracao

### Servidor Unico (Desenvolvimento)

```bash
# Docker Compose
redis:
  image: redis:7-alpine
  ports:
    - "6379:6379"
  command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
```

### Redis Sentinel (Producao)

Para alta disponibilidade, configure Redis Sentinel com 3 nos:

```
# Topologia Sentinel
Master:   10.140.240.4:6379
Replica:  10.140.240.5:6379
Replica:  10.140.240.6:6379
Sentinel: 10.140.240.4:26379
Sentinel: 10.140.240.5:26379
Sentinel: 10.140.240.6:26379
```

```ini
# sentinel.conf
sentinel monitor fluxiq-redis 10.140.240.4 6379 2
sentinel down-after-milliseconds fluxiq-redis 5000
sentinel failover-timeout fluxiq-redis 10000
sentinel parallel-syncs fluxiq-redis 1
```

### GCP Memorystore

Para ambientes GCP, use Memorystore for Redis:

```bash
gcloud redis instances create monetarie-pix \
  --size=2 \
  --region=southamerica-east1 \
  --redis-version=redis_7_0 \
  --tier=standard-ha \
  --connect-mode=private-service-access
```

## Pool de Conexoes

O Monetarie PIX usa `Shared.Redis.Connection` com um pool de 10 conexoes:

```elixir
# Shared.Redis.Connection (iniciado pelo Shared.Application)
# Pool de 10 conexoes persistentes
defmodule Shared.Redis.Connection do
  use GenServer

  def start_link(_opts) do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end
end
```

| Parametro | Valor | Descricao |
|-----------|-------|-----------|
| Conexoes | 10 | Pool fixo de conexoes persistentes |
| Timeout | 5.000ms | Timeout por operacao Redis |
| Reconexao | Automatica | Reconecta em caso de perda de conexao |

## Rate Limiting (Token Bucket)

### Funcionamento

O rate limiting protege os endpoints de login e MFA contra ataques de forca bruta:

```mermaid
sequenceDiagram
    participant C as Cliente
    participant A as AuthController
    participant R as Redis

    C->>A: POST /api/v1/auth/login
    A->>R: INCR rate_limit:{ip}
    R-->>A: count = 3
    A->>R: EXPIRE rate_limit:{ip} 900
    Note over A: count <= 10: Permitir
    A-->>C: 200 OK (login processado)

    C->>A: POST /api/v1/auth/login (11a tentativa)
    A->>R: INCR rate_limit:{ip}
    R-->>A: count = 11
    Note over A: count > 10: Bloquear
    A-->>C: 429 Too Many Requests
```

### Configuracao

| Parametro | Valor | Descricao |
|-----------|-------|-----------|
| Limite | 10 tentativas | Por IP |
| Janela | 15 minutos (900s) | Tempo de expiracao do contador |
| Endpoints | `/api/v1/auth/login`, `/api/v1/auth/mfa/*` | Endpoints protegidos |
| Bypass | Desabilitado por padrao | `bypass_auth: false` |

### Chaves Redis

```
rate_limit:{ip_address}   ->  INTEGER (contador)  TTL: 900s
```

### Comandos Redis Utilizados

```redis
INCR rate_limit:192.168.1.100
EXPIRE rate_limit:192.168.1.100 900
GET rate_limit:192.168.1.100
```

## Token Blacklist (JWT Revogacao)

### Funcionamento

Quando um usuario faz logout, o token JWT e adicionado a uma blacklist no Redis. O TTL da chave e igual ao tempo restante de vida do token.

```mermaid
sequenceDiagram
    participant C as Cliente
    participant A as AuthController
    participant R as Redis
    participant J as JWTAuth/Authenticate

    C->>A: POST /api/v1/auth/logout
    A->>A: Extrair JTI + exp do token
    A->>R: SET blacklist:{jti} "revoked" EX {ttl_restante}
    R-->>A: OK
    A-->>C: 200 OK (logout)

    Note over C,J: Proxima requisicao com mesmo token

    C->>J: GET /api/v1/... (Authorization: Bearer {token})
    J->>R: GET blacklist:{jti}
    R-->>J: "revoked"
    J-->>C: 401 Unauthorized (token revogado)
```

### Chaves Redis

```
blacklist:{jti}   ->  "revoked"   TTL: tempo restante do token
```

### Verificacao

A verificacao de blacklist e feita em 3 pontos:

1. **Settlement**: `Shared.Auth.JWTAuth` plug
2. **DICT**: `DictServiceWeb.Plugs.Authenticate` plug
3. **SSO**: `Shared.Auth.SsoAuth` plug

## Idempotencia

### Funcionamento

O plug `Shared.Plugs.Idempotency` garante que requisicoes duplicadas retornem o mesmo resultado, usando `SET NX` atomico (TOCTOU-safe):

```mermaid
sequenceDiagram
    participant C as Cliente
    participant I as Idempotency Plug
    participant R as Redis
    participant H as Handler

    C->>I: POST /payments (Idempotency-Key: abc123)
    I->>R: SET idempotency:{user}:{key}:{fingerprint} NX EX 86400
    R-->>I: OK (chave nova)
    I->>H: Processar pagamento
    H-->>I: 201 Created {response}
    I->>R: SET idempotency:{user}:{key}:response {body} EX 86400
    I-->>C: 201 Created {response}

    Note over C,R: Requisicao duplicada

    C->>I: POST /payments (Idempotency-Key: abc123)
    I->>R: SET idempotency:{user}:{key}:{fingerprint} NX EX 86400
    R-->>I: nil (chave ja existe)
    I->>R: GET idempotency:{user}:{key}:response
    R-->>I: {cached response}
    I-->>C: 201 Created {cached response}
```

### Configuracao

| Parametro | Valor | Descricao |
|-----------|-------|-----------|
| TTL | 24 horas (86.400s) | Tempo de vida da chave de idempotencia |
| Header | `Idempotency-Key` | Header HTTP obrigatorio para endpoints protegidos |
| Fingerprint | SHA-256 do body | Garante que o mesmo Key com body diferente e rejeitado |
| Escopo | Por usuario | Chaves sao vinculadas ao usuario autenticado |
| Limite body | 64KB | Requisicoes maiores sao rejeitadas |
| Lock | `SET NX` atomico | Previne race conditions (TOCTOU) |

### Chaves Redis

```
idempotency:{user_id}:{idempotency_key}:{body_sha256}   ->  "locked"    TTL: 86400s
idempotency:{user_id}:{idempotency_key}:response         ->  {JSON body} TTL: 86400s
```

### Endpoints Protegidos

| Endpoint | Pipeline |
|----------|----------|
| `POST /api/v1/payments` | `idempotent` |
| `POST /api/v1/transactions` | `idempotent` |

## Comandos Redis Utilizados pelo PIX

| Comando | Caso de Uso | Descricao |
|---------|-------------|-----------|
| `SET key value EX ttl` | Blacklist, Idempotencia | Definir valor com expiracao |
| `SET key value NX EX ttl` | Idempotencia (lock) | Definir apenas se nao existe (atomico) |
| `GET key` | Blacklist, Idempotencia | Obter valor |
| `DEL key` | Limpeza | Remover chave |
| `INCR key` | Rate limiting | Incrementar contador |
| `EXPIRE key ttl` | Rate limiting | Definir expiracao |

## Monitoramento Redis

### Metricas Importantes

```bash
# Verificar uso de memoria
redis-cli -h $REDIS_HOST INFO memory

# Verificar clientes conectados
redis-cli -h $REDIS_HOST INFO clients

# Verificar comandos por segundo
redis-cli -h $REDIS_HOST INFO stats | grep instantaneous_ops_per_sec

# Verificar chaves por padrao
redis-cli -h $REDIS_HOST --scan --pattern "rate_limit:*" | wc -l
redis-cli -h $REDIS_HOST --scan --pattern "blacklist:*" | wc -l
redis-cli -h $REDIS_HOST --scan --pattern "idempotency:*" | wc -l
```

### Alertas Recomendados

| Metrica | Limiar | Acao |
|---------|--------|------|
| `used_memory` | > 80% maxmemory | Investigar chaves, aumentar memoria |
| `connected_clients` | > 100 | Verificar leak de conexoes |
| `instantaneous_ops_per_sec` | > 50.000 | Considerar cluster |
| `rejected_connections` | > 0 | Aumentar `maxclients` |
| `evicted_keys` | > 0 | Aumentar memoria ou revisar TTLs |

## Tuning Redis para PIX

### Parametros Recomendados

```ini
# redis.conf para carga PIX
maxmemory 2gb
maxmemory-policy allkeys-lru
maxclients 10000

# Persistencia (RDB + AOF para durabilidade)
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec

# Rede
tcp-backlog 511
timeout 300
tcp-keepalive 300

# Performance
hz 10
```

## Resultado Esperado

Apos a configuracao do Redis:

- O `Shared.Redis.Connection` inicia com 10 conexoes no pool
- Rate limiting bloqueia IPs apos 10 tentativas de login em 15 minutos
- Tokens JWT revogados sao rejeitados imediatamente apos logout
- Requisicoes duplicadas com `Idempotency-Key` retornam a resposta original
- `redis-cli -h $REDIS_HOST ping` retorna `PONG`
- O consumo de memoria permanece estavel com a politica `allkeys-lru`
