# Backup e Recuperacao de Desastres

Estrategia completa de backup para todos os componentes da plataforma Monetarie PIX, incluindo procedimentos de restauracao e recuperacao de desastres.

## Pre-requisitos

- Acesso SSH aos servidores de banco de dados e infraestrutura
- Ferramentas instaladas: `pg_dump`, `pg_restore`, `redis-cli`, `nats` CLI, `gpg`
- Permissoes de leitura em todos os bancos de dados e servicos
- Storage externo configurado (GCS bucket, S3, ou NFS) para armazenamento de backups
- Cron ou systemd timer para agendamento de backups automaticos

## Visao Geral da Estrategia

```mermaid
graph TB
    subgraph Dados Criticos
        PG[(PostgreSQL<br/>8 schemas)]
        REDIS[(Redis 7<br/>Cache + Sessions)]
        NATS[NATS JetStream<br/>7 streams]
        CERTS[Certificados<br/>ICP-Brasil]
        CONFIG[Configuracao<br/>.env + secrets]
    end

    subgraph Backup Local
        PG_DUMP[pg_dump diario<br/>+ WAL continuo]
        REDIS_RDB[RDB snapshot<br/>a cada 15 min]
        NATS_SNAP[Stream snapshot<br/>diario]
        CERT_ENC[Backup criptografado<br/>GPG]
        CONFIG_BAK[Backup versionado<br/>Git-crypt]
    end

    subgraph Storage Externo
        GCS[Google Cloud Storage<br/>Lifecycle 90 dias]
        COLD[Cold Storage<br/>Retencao 5 anos]
    end

    PG --> PG_DUMP
    REDIS --> REDIS_RDB
    NATS --> NATS_SNAP
    CERTS --> CERT_ENC
    CONFIG --> CONFIG_BAK

    PG_DUMP --> GCS
    REDIS_RDB --> GCS
    NATS_SNAP --> GCS
    CERT_ENC --> GCS
    CONFIG_BAK --> GCS

    GCS -->|Auditoria BACEN| COLD
```

| Componente | Tipo de Backup | Frequencia | Retencao | RPO |
|------------|---------------|------------|----------|-----|
| PostgreSQL (logico) | `pg_dump -Fc` | Diario 02:00 UTC | 30 dias | 24h |
| PostgreSQL (WAL) | WAL archiving | Continuo | 7 dias | ~5 min |
| Redis | RDB snapshot | A cada 15 min | 7 dias | 15 min |
| NATS JetStream | Stream snapshot | Diario 03:00 UTC | 7 dias | 24h |
| Certificados | GPG encrypted | Sob demanda | Permanente | N/A |
| Configuracao | Git-crypt | Sob demanda | Permanente | N/A |

## Backup PostgreSQL

### Backup Logico (pg_dump)

Backup completo do banco `monetarie` no formato custom (comprimido):

```bash
# Backup completo — formato custom (comprimido, paralelizavel)
pg_dump -Fc \
  -h 10.140.241.2 \
  -U postgres \
  -d monetarie \
  -f pix_backup_$(date +%Y%m%d_%H%M%S).dump

# Saida esperada: (nenhuma — arquivo criado no diretorio atual)
# Verificacao:
ls -lh pix_backup_*.dump
# -rw-r--r-- 1 postgres postgres 245M Feb 13 02:00 pix_backup_20260213_020000.dump
```

Backup por schema individual (util para restauracao parcial):

```bash
# Backup somente do schema monetarie_spi (transacoes)
pg_dump -Fc \
  -h 10.140.241.2 \
  -U postgres \
  -d monetarie \
  --schema=monetarie_spi \
  -f pix_spi_$(date +%Y%m%d).dump

# Backup somente do schema monetarie_dict (chaves PIX)
pg_dump -Fc \
  -h 10.140.241.2 \
  -U postgres \
  -d monetarie \
  --schema=monetarie_dict \
  -f pix_dict_$(date +%Y%m%d).dump

# Backup somente do schema monetarie_auth (usuarios)
pg_dump -Fc \
  -h 10.140.241.2 \
  -U postgres \
  -d monetarie \
  --schema=monetarie_auth \
  -f pix_auth_$(date +%Y%m%d).dump
```

Script de backup automatizado com rotacao:

```bash
#!/bin/bash
# /opt/monetarie/scripts/backup-postgres.sh

set -euo pipefail

DB_HOST="${DB_HOST:-10.140.241.2}"
DB_USER="${DB_USER:-postgres}"
DB_NAME="${DB_NAME:-monetarie}"
BACKUP_DIR="/opt/monetarie/backups/postgres"
RETENTION_DAYS=30
GCS_BUCKET="gs://fluxiq-backups/pix/postgres"

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/pix_backup_${TIMESTAMP}.dump"

mkdir -p "${BACKUP_DIR}"

echo "[$(date)] Iniciando backup PostgreSQL..."

pg_dump -Fc \
  -h "${DB_HOST}" \
  -U "${DB_USER}" \
  -d "${DB_NAME}" \
  -f "${BACKUP_FILE}"

BACKUP_SIZE=$(du -h "${BACKUP_FILE}" | cut -f1)
echo "[$(date)] Backup concluido: ${BACKUP_FILE} (${BACKUP_SIZE})"

# Upload para GCS
gsutil cp "${BACKUP_FILE}" "${GCS_BUCKET}/"
echo "[$(date)] Upload para GCS concluido"

# Rotacao local — remover backups com mais de 30 dias
find "${BACKUP_DIR}" -name "pix_backup_*.dump" -mtime +${RETENTION_DAYS} -delete
echo "[$(date)] Rotacao concluida (retencao: ${RETENTION_DAYS} dias)"
```

Agendamento via cron:

```bash
# Executar diariamente as 02:00 UTC (23:00 BRT)
0 2 * * * /opt/monetarie/scripts/backup-postgres.sh >> /var/log/monetarie/backup-postgres.log 2>&1
```

### Restauracao PostgreSQL

Restauracao completa:

```bash
# Restaurar backup completo
pg_restore \
  -h 10.140.241.2 \
  -U postgres \
  -d monetarie \
  --clean \
  --if-exists \
  pix_backup_20260213.dump

# Saida esperada:
# pg_restore: dropping table monetarie_spi.messages
# pg_restore: creating table "monetarie_spi.messages"
# ...
# pg_restore: processing data for table "monetarie_spi.messages"
# pg_restore: 1000 rows restored
```

Restauracao parcial (schema unico):

```bash
# Restaurar somente schema monetarie_spi
pg_restore \
  -h 10.140.241.2 \
  -U postgres \
  -d monetarie \
  --schema=monetarie_spi \
  --clean \
  --if-exists \
  pix_spi_20260213.dump
```

Restauracao em banco separado (para verificacao):

```bash
# Criar banco temporario
psql -h 10.140.241.2 -U postgres -c "CREATE DATABASE monetarie_restore;"

# Restaurar no banco temporario
pg_restore \
  -h 10.140.241.2 \
  -U postgres \
  -d monetarie_restore \
  pix_backup_20260213.dump

# Verificar contagem de registros
psql -h 10.140.241.2 -U postgres -d monetarie_restore -c "
  SELECT schemaname, relname, n_live_tup
  FROM pg_stat_user_tables
  WHERE schemaname LIKE 'monetarie_%'
  ORDER BY n_live_tup DESC
  LIMIT 20;
"

# Limpar banco temporario
psql -h 10.140.241.2 -U postgres -c "DROP DATABASE monetarie_restore;"
```

### WAL Archiving (Point-in-Time Recovery)

Configuracao do PostgreSQL para arquivamento continuo de WAL:

```ini
# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'gsutil cp %p gs://fluxiq-backups/pix/wal/%f'
archive_timeout = 300
```

Restauracao PITR (Point-in-Time Recovery):

```bash
# 1. Parar o PostgreSQL
systemctl stop postgresql

# 2. Mover diretorio de dados atual
mv /var/lib/postgresql/16/main /var/lib/postgresql/16/main.old

# 3. Restaurar base backup
pg_basebackup -D /var/lib/postgresql/16/main \
  -h 10.140.241.2 -U postgres

# 4. Criar recovery.conf (PostgreSQL 16 usa postgresql.auto.conf)
cat > /var/lib/postgresql/16/main/postgresql.auto.conf << 'EOF'
restore_command = 'gsutil cp gs://fluxiq-backups/pix/wal/%f %p'
recovery_target_time = '2026-02-13 14:30:00 UTC'
recovery_target_action = 'promote'
EOF

# 5. Criar signal de recovery
touch /var/lib/postgresql/16/main/recovery.signal

# 6. Iniciar PostgreSQL
systemctl start postgresql

# 7. Verificar recovery
psql -h localhost -U postgres -d monetarie -c "SELECT pg_is_in_recovery();"
# Saida: f (false = recovery concluida)
```

## Backup Redis

### RDB Snapshots

Configuracao do Redis para snapshots automaticos:

```ini
# redis.conf
save 900 1       # Snapshot se pelo menos 1 chave alterada em 15 min
save 300 10      # Snapshot se pelo menos 10 chaves alteradas em 5 min
save 60 10000    # Snapshot se pelo menos 10000 chaves alteradas em 1 min

dbfilename dump.rdb
dir /var/lib/redis
```

Backup manual:

```bash
# Forcar snapshot RDB
redis-cli -h 10.140.240.4 -p 6379 BGSAVE

# Saida esperada:
# Background saving started

# Verificar status do snapshot
redis-cli -h 10.140.240.4 -p 6379 LASTSAVE

# Copiar arquivo RDB para storage externo
scp redis-server:/var/lib/redis/dump.rdb \
  /opt/monetarie/backups/redis/dump_$(date +%Y%m%d_%H%M%S).rdb

# Upload para GCS
gsutil cp /opt/monetarie/backups/redis/dump_$(date +%Y%m%d_%H%M%S).rdb \
  gs://fluxiq-backups/pix/redis/
```

### AOF Persistence

Configuracao para append-only file (maior durabilidade):

```ini
# redis.conf
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
```

### Restauracao Redis

```bash
# 1. Parar Redis
systemctl stop redis

# 2. Copiar arquivo RDB para diretorio de dados
cp /opt/monetarie/backups/redis/dump_20260213.rdb /var/lib/redis/dump.rdb
chown redis:redis /var/lib/redis/dump.rdb

# 3. Iniciar Redis
systemctl start redis

# 4. Verificar restauracao
redis-cli -h 10.140.240.4 -p 6379 INFO keyspace
# Saida esperada:
# db0:keys=1523,expires=890,avg_ttl=3600000
```

::: warning Dados de sessao
O Redis armazena dados de sessao (tokens JWT blacklist, rate limiting, idempotency keys) e cache. A perda destes dados causa logout de todos os usuarios, mas nao resulta em perda de dados de negocio.
:::

## Backup NATS JetStream

### Snapshot de Streams

```bash
# Listar streams atuais
nats stream list --server=nats://10.10.40.5:4222

# Saida esperada:
# +-----------------------+----------+----------+-----------+
# | Name                  | Messages | Size     | Consumers |
# +-----------------------+----------+----------+-----------+
# | MONETARIE_SPI            | 45,231   | 1.2 GiB  | 4         |
# | MONETARIE_DICT           | 12,450   | 340 MiB  | 2         |
# | MONETARIE_SETTLEMENT     | 8,102    | 215 MiB  | 3         |
# | MONETARIE_AUDIT          | 156,890  | 4.5 GiB  | 1         |
# | MONETARIE_DLQ            | 23       | 1.2 MiB  | 1         |
# | MONETARIE_CORE           | 5,670    | 145 MiB  | 1         |
# +-----------------------+----------+----------+-----------+

# Backup de stream individual
nats stream backup MONETARIE_SPI /opt/monetarie/backups/nats/MONETARIE_SPI_$(date +%Y%m%d) \
  --server=nats://10.10.40.5:4222

# Saida esperada:
# Starting backup of Stream "MONETARIE_SPI" with 45231 data blocks
# 45231 / 45231 [====================] 100%
# Backup complete

# Backup de todas as streams
for STREAM in MONETARIE_SPI MONETARIE_DICT MONETARIE_SETTLEMENT MONETARIE_AUDIT MONETARIE_DLQ MONETARIE_CORE; do
  echo "[$(date)] Backup stream: ${STREAM}"
  nats stream backup "${STREAM}" \
    "/opt/monetarie/backups/nats/${STREAM}_$(date +%Y%m%d)" \
    --server=nats://10.10.40.5:4222
done
```

### Restauracao de Stream

```bash
# Restaurar stream a partir do backup
nats stream restore MONETARIE_SPI /opt/monetarie/backups/nats/MONETARIE_SPI_20260213 \
  --server=nats://10.10.40.5:4222

# Saida esperada:
# Starting restore of Stream "MONETARIE_SPI"
# 45231 / 45231 [====================] 100%
# Restore complete

# Verificar restauracao
nats stream info MONETARIE_SPI --server=nats://10.10.40.5:4222
```

### Configuracao dos Streams

Referencia rapida dos limites de cada stream para verificacao pos-restauracao:

| Stream | Subjects | Retencao | Max Bytes | Max Msgs |
|--------|----------|----------|-----------|----------|
| MONETARIE_SPI | `monetarie.spi.>` | 7 dias | 10 GB | 10M |
| MONETARIE_DICT | `monetarie.dict.>` | 7 dias | 5 GB | 5M |
| MONETARIE_SETTLEMENT | `monetarie.settlement.>` | 7 dias | 5 GB | 5M |
| MONETARIE_AUDIT | `monetarie.audit.>` | 90 dias | 20 GB | 50M |
| MONETARIE_DLQ | `monetarie.dlq.>` | 90 dias | 2 GB | 1M |
| MONETARIE_CORE | `monetarie.core.>` | 7 dias | 5 GB | 5M |

## Backup de Dados da Aplicacao

### Certificados ICP-Brasil

Os certificados BACEN sao criticos para autenticacao mTLS e assinatura XMLDSig. Devem ser armazenados criptografados:

```bash
# Criar backup criptografado dos certificados
tar czf - /opt/monetarie/certs/ | \
  gpg --symmetric --cipher-algo AES256 \
  --output /opt/monetarie/backups/certs/certs_$(date +%Y%m%d).tar.gz.gpg

# Saida esperada:
# (solicita senha de criptografia)

# Upload para storage seguro
gsutil cp /opt/monetarie/backups/certs/certs_$(date +%Y%m%d).tar.gz.gpg \
  gs://fluxiq-backups/pix/certs/

# Restauracao
gpg --decrypt /opt/monetarie/backups/certs/certs_20260213.tar.gz.gpg | \
  tar xzf - -C /
```

::: danger Seguranca de certificados
Nunca armazene certificados ICP-Brasil sem criptografia. A senha GPG deve ser mantida em um cofre de senhas separado (Vault, GCP Secret Manager). A exposicao de certificados BACEN pode resultar em fraude financeira.
:::

### Configuracao (.env e Secrets)

```bash
# Backup dos arquivos de configuracao
tar czf /opt/monetarie/backups/config/env_$(date +%Y%m%d).tar.gz \
  /opt/monetarie/pix/.env* \
  /opt/monetarie/pix/deploy/

# Backup de secrets Kubernetes
kubectl get secrets -n pix -o yaml > \
  /opt/monetarie/backups/config/k8s_secrets_$(date +%Y%m%d).yaml

# Criptografar secrets
gpg --symmetric --cipher-algo AES256 \
  --output /opt/monetarie/backups/config/k8s_secrets_$(date +%Y%m%d).yaml.gpg \
  /opt/monetarie/backups/config/k8s_secrets_$(date +%Y%m%d).yaml

# Remover YAML nao criptografado
rm /opt/monetarie/backups/config/k8s_secrets_$(date +%Y%m%d).yaml
```

## Recuperacao de Desastres

### Objetivos

| Metrica | Alvo | Descricao |
|---------|------|-----------|
| **RTO** (Recovery Time Objective) | 2 horas | Tempo maximo para restauracao completa |
| **RPO** (Recovery Point Objective) | 15 minutos | Perda maxima de dados aceitavel |
| **MTTR** (Mean Time To Recovery) | 45 minutos | Tempo medio esperado para recuperacao |

### Runbook de Recuperacao Completa

Ordem de restauracao (dependencias respeitadas):

```mermaid
graph LR
    A[1. PostgreSQL] --> B[2. Redis]
    B --> C[3. NATS JetStream]
    C --> D[4. Aplicacao]
    D --> E[5. Verificacao]

    style A fill:#e74c3c,color:#fff
    style B fill:#e67e22,color:#fff
    style C fill:#f39c12,color:#fff
    style D fill:#27ae60,color:#fff
    style E fill:#3498db,color:#fff
```

#### Passo 1: Restaurar PostgreSQL (30 minutos)

```bash
# 1.1 Restaurar banco de dados
pg_restore \
  -h ${DB_HOST} \
  -U postgres \
  -d monetarie \
  --clean --if-exists \
  /opt/monetarie/backups/postgres/pix_backup_latest.dump

# 1.2 Executar migrations pendentes (caso o backup seja anterior a ultima migration)
kubectl exec -n pix deployment/pix-backend -- \
  bin/monetarie_pix eval "Shared.Release.migrate()"

# 1.3 Verificar integridade
psql -h ${DB_HOST} -U postgres -d monetarie -c "
  SELECT schemaname, COUNT(*) as tables
  FROM pg_tables
  WHERE schemaname LIKE 'monetarie_%'
  GROUP BY schemaname
  ORDER BY schemaname;
"

# Saida esperada:
#  schemaname          | tables
# ---------------------+--------
#  monetarie_audit        | 2
#  monetarie_auth         | 9
#  monetarie_dict         | 5
#  monetarie_settlement   | 8
#  monetarie_spi          | 7
#  monetarie_spi_msg      | 3
#  monetarie_spi_ref      | 6
```

#### Passo 2: Restaurar Redis (5 minutos)

```bash
# 2.1 Restaurar RDB
systemctl stop redis
cp /opt/monetarie/backups/redis/dump_latest.rdb /var/lib/redis/dump.rdb
chown redis:redis /var/lib/redis/dump.rdb
systemctl start redis

# 2.2 Verificar conectividade
redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} PING
# Saida esperada: PONG
```

#### Passo 3: Restaurar NATS JetStream (15 minutos)

```bash
# 3.1 Restaurar streams
for STREAM in MONETARIE_SPI MONETARIE_DICT MONETARIE_SETTLEMENT MONETARIE_AUDIT MONETARIE_DLQ MONETARIE_CORE; do
  nats stream restore "${STREAM}" \
    "/opt/monetarie/backups/nats/${STREAM}_latest" \
    --server=nats://${NATS_HOST}:${NATS_PORT}
done

# 3.2 Verificar streams
nats stream list --server=nats://${NATS_HOST}:${NATS_PORT}
```

#### Passo 4: Iniciar Aplicacao (10 minutos)

```bash
# 4.1 Reiniciar pods do backend
kubectl rollout restart deployment/pix-backend -n pix

# 4.2 Aguardar pods prontos
kubectl rollout status deployment/pix-backend -n pix --timeout=300s
# Saida esperada:
# deployment "pix-backend" successfully rolled out

# 4.3 Reiniciar frontends
kubectl rollout restart deployment/pix-admin-frontend -n pix
kubectl rollout restart deployment/pix-user-frontend -n pix
```

#### Passo 5: Verificacao (15 minutos)

```bash
# 5.1 Health check do backend
curl -s https://pixapi-dev.fluxiq.com.br/health | jq .
# Saida esperada:
# {
#   "status": "healthy",
#   "services": { ... },
#   "database": { "status": "healthy" },
#   "redis": { "status": "healthy" },
#   "nats": { "status": "healthy" }
# }

# 5.2 Verificar login
curl -s -X POST https://pixapi-dev.fluxiq.com.br/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"Admin@2026!"}' | jq .status
# Saida esperada: "ok"

# 5.3 Verificar transacoes
curl -s https://pixapi-dev.fluxiq.com.br/api/v1/transactions \
  -H "Cookie: pix_session=<token>" | jq '.total'
# Saida esperada: (numero >= 0)

# 5.4 Verificar workers NATS
kubectl logs deployment/pix-backend -n pix --tail=20 | grep "Heartbeat"
# Saida esperada:
# [InboundProcessor] Heartbeat: processed=0 failed=0 retried=0 uptime=60s
# [OutboundSender] Heartbeat: processed=0 failed=0 retried=0 uptime=60s
```

## Verificacao de Backups

Script de verificacao automatizada (executar semanalmente):

```bash
#!/bin/bash
# /opt/monetarie/scripts/verify-backup.sh

set -euo pipefail

echo "=== Verificacao de Backup Monetarie PIX ==="
echo "[$(date)] Iniciando verificacao..."

# 1. Verificar existencia do backup mais recente
LATEST_PG=$(ls -t /opt/monetarie/backups/postgres/pix_backup_*.dump 2>/dev/null | head -1)
if [ -z "$LATEST_PG" ]; then
  echo "ERRO: Nenhum backup PostgreSQL encontrado!"
  exit 1
fi
echo "OK: Ultimo backup PostgreSQL: ${LATEST_PG}"

# 2. Verificar integridade do arquivo
pg_restore --list "${LATEST_PG}" > /dev/null 2>&1
if [ $? -eq 0 ]; then
  echo "OK: Arquivo de backup integro"
else
  echo "ERRO: Arquivo de backup corrompido!"
  exit 1
fi

# 3. Restauracao de teste em banco temporario
psql -h ${DB_HOST} -U postgres -c "CREATE DATABASE monetarie_verify;" 2>/dev/null || true
pg_restore -h ${DB_HOST} -U postgres -d monetarie_verify "${LATEST_PG}" 2>/dev/null

TABLE_COUNT=$(psql -h ${DB_HOST} -U postgres -d monetarie_verify -t -c "
  SELECT COUNT(*) FROM pg_tables WHERE schemaname LIKE 'monetarie_%';
")
echo "OK: ${TABLE_COUNT} tabelas restauradas no banco de verificacao"

psql -h ${DB_HOST} -U postgres -c "DROP DATABASE monetarie_verify;"

echo "[$(date)] Verificacao concluida com sucesso"
```

## Resultado Esperado

Ao seguir este guia, voce tera:

- Backups automatizados de PostgreSQL (diario + WAL continuo) com rotacao de 30 dias
- Snapshots Redis a cada 15 minutos com AOF para durabilidade
- Backups de todas as 6 streams NATS JetStream
- Certificados ICP-Brasil armazenados com criptografia GPG
- Um runbook testado de recuperacao de desastres com RTO de 2 horas
- Script de verificacao automatizada para validar integridade dos backups
