# Sao Lưu & Khôi Phục Thảm Họa

## Mục Tiêu RTO / RPO

| Chỉ số | Mục tiêu | Ghi chú |
|--------|----------|---------|
| **RPO** (Mục tiêu Điểm Khôi phục) | ≤ 24 giờ | Sao lưu hàng ngày lúc 02:00 UTC; trường hợp xấu nhất là mất toàn bộ dữ liệu trong một ngày |
| **RTO** (Mục tiêu Thời gian Khôi phục) | ≤ 30 phút | Khôi phục từ bản sao lưu volume cục bộ; lâu hơn nếu lấy từ nơi lưu trữ ngoài site |

> Để giảm RPO hơn nữa, hãy xem xét lưu trữ WAL cho PostgreSQL (khôi phục liên tục theo thời gian thực) và lên lịch sao lưu thường xuyên hơn.

---

## Sao Lưu PostgreSQL

### Tổng quan

Sao lưu PostgreSQL tự động hàng ngày chạy bên trong Docker container `pg-backup` bằng `pg_dump` với nén định dạng tùy chỉnh. Các bản sao lưu được lưu trữ trong Docker volume `pg_backups`.

## Cấu Hình Sao Lưu

| Thiết lập | Mặc định | Biến môi trường |
|-----------|---------|----------------|
| Lịch | Hàng ngày lúc 02:00 UTC | Cron trong service `pg-backup` |
| Thời gian lưu | 7 ngày | `BACKUP_RETENTION_DAYS` |
| Định dạng | Tùy chỉnh (`pg_dump --format=custom`) | — |
| Nén | Mức 6 | — |
| Lưu trữ | Docker volume `pg_backups` | — |

## Liệt Kê Các Bản Sao Lưu

```bash
docker exec goodgo-pg-backup ls -lh /backups/
```

## Sao Lưu Thủ Công

```bash
docker exec goodgo-pg-backup /scripts/pg-backup.sh
```

## Quy Trình Khôi Phục

### 1. Xác định bản sao lưu cần khôi phục

```bash
docker exec goodgo-pg-backup ls -lht /backups/
```

### 2. Dừng các service ứng dụng

```bash
docker compose stop ai-services
# Stop any NestJS API processes
```

### 3. Chạy lệnh khôi phục

```bash
docker exec -it goodgo-pg-backup /scripts/pg-restore.sh /backups/goodgo_YYYYMMDD_HHMMSS.sql.gz
```

Script khôi phục sẽ:
- Chấm dứt các kết nối cơ sở dữ liệu đang hoạt động
- Xóa và tạo lại cơ sở dữ liệu
- Khôi phục từ bản sao lưu đã chọn

### 4. Xác minh khôi phục

```bash
docker exec goodgo-postgres psql -U goodgo -d goodgo -c '\dt'
docker exec goodgo-postgres psql -U goodgo -d goodgo -c 'SELECT count(*) FROM "User";'
```

### 5. Chạy migration Prisma (nếu cần)

```bash
pnpm prisma migrate deploy
```

### 6. Khởi động lại các service

```bash
docker compose up -d
```

## Xác Minh Bản Sao Lưu

Kiểm tra log sao lưu:

```bash
docker exec goodgo-pg-backup cat /var/log/pg-backup.log
```

Xác minh tính toàn vẹn của bản sao lưu mà không cần khôi phục:

```bash
docker exec goodgo-pg-backup pg_restore --list /backups/goodgo_YYYYMMDD_HHMMSS.sql.gz
```

---

## Sao Lưu & Khôi Phục Redis

Redis được cấu hình với tính năng bền vững AOF (`--appendonly yes`). Dữ liệu được lưu trong Docker volume `redis_data`.

### Snapshot Thủ Công

```bash
# Trigger an RDB snapshot
docker exec goodgo-redis redis-cli -a "$REDIS_PASSWORD" BGSAVE

# Wait for completion
docker exec goodgo-redis redis-cli -a "$REDIS_PASSWORD" LASTSAVE
```

### Sao Lưu Volume

```bash
# Stop Redis to ensure consistent snapshot
docker compose stop redis

# Copy volume data to a backup location
docker run --rm -v goodgo-platform-ai_redis_data:/data -v $(pwd)/backups:/backup \
  alpine tar czf /backup/redis_$(date +%Y%m%d_%H%M%S).tar.gz -C /data .

docker compose start redis
```

### Khôi Phục Redis

```bash
docker compose stop redis

# Clear existing data and restore
docker run --rm -v goodgo-platform-ai_redis_data:/data -v $(pwd)/backups:/backup \
  alpine sh -c "rm -rf /data/* && tar xzf /backup/redis_YYYYMMDD_HHMMSS.tar.gz -C /data"

docker compose start redis
```

> **Lưu ý:** Redis được dùng làm cache với chính sách loại bỏ `allkeys-lru`. Mất toàn bộ dữ liệu không nghiêm trọng — API sẽ tự động nạp lại các mục cache theo yêu cầu. Việc khôi phục chỉ cần thiết khi dữ liệu phiên hoặc trạng thái hàng đợi phải được giữ nguyên.

---

## Sao Lưu & Khôi Phục Typesense

Dữ liệu Typesense được lưu trữ trong Docker volume `typesense_data`.

### Tạo Snapshot

```bash
# Typesense built-in snapshot API
curl -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
  "http://localhost:8108/operations/snapshot?snapshot_path=/data/snapshots/$(date +%Y%m%d)"
```

### Sao Lưu Volume

```bash
docker compose stop typesense

docker run --rm -v goodgo-platform-ai_typesense_data:/data -v $(pwd)/backups:/backup \
  alpine tar czf /backup/typesense_$(date +%Y%m%d_%H%M%S).tar.gz -C /data .

docker compose start typesense
```

### Khôi Phục Typesense

```bash
docker compose stop typesense

docker run --rm -v goodgo-platform-ai_typesense_data:/data -v $(pwd)/backups:/backup \
  alpine sh -c "rm -rf /data/* && tar xzf /backup/typesense_YYYYMMDD_HHMMSS.tar.gz -C /data"

docker compose start typesense
```

### Xây Dựng Lại Từ Nguồn

Nếu bản sao lưu không có sẵn, Typesense có thể được xây dựng lại bằng cách lập chỉ mục lại từ PostgreSQL:

```bash
# After Typesense restarts with empty data:
pnpm run typesense:reindex
```

---

## Sổ Tay Khôi Phục Thảm Họa

### Kịch bản 1: Lỗi PostgreSQL (container crash hoặc hỏng dữ liệu)

1. **Đánh giá:** `docker logs goodgo-postgres` — kiểm tra tình trạng hỏng dữ liệu hoặc OOM
2. **Dừng service:** `docker compose stop api ai-services`
3. **Thử khởi động lại:** `docker compose restart postgres`
4. Nếu khởi động lại thất bại (hỏng dữ liệu):
   - `docker compose stop postgres`
   - Xóa volume: `docker volume rm goodgo-platform-ai_postgres_data`
   - Tạo lại: `docker compose up -d postgres`
   - Khôi phục từ bản sao lưu: `docker exec goodgo-pg-backup /scripts/pg-restore.sh /backups/<latest>.sql.gz`
   - Xác minh: `docker exec goodgo-postgres psql -U goodgo -d goodgo -c '\dt'`
   - Chạy migration: `pnpm prisma migrate deploy`
5. **Khởi động lại các service:** `docker compose up -d`
6. **Xác minh:** Kiểm tra API health tại `http://localhost:3000/health`

**RTO dự kiến:** ~15 phút (sao lưu cục bộ), ~30 phút (sao lưu ngoài site)

### Kịch bản 2: Service Bị Crash (API, AI-services hoặc Web)

1. **Kiểm tra log:** `docker compose logs --tail=100 <service>`
2. **Khởi động lại service:** `docker compose restart <service>`
3. Nếu crash lặp lại:
   - Kiểm tra giới hạn tài nguyên: `docker stats`
   - Kiểm tra biến môi trường: `docker compose config`
   - Rollback về image tag trước nếu triển khai gần đây gây ra sự cố
4. **Xác minh:** Kiểm tra các endpoint health

**RTO dự kiến:** ~5 phút

### Kịch bản 3: Hỏng Toàn Bộ Máy Chủ

1. Cung cấp máy chủ mới với Docker + Docker Compose
2. Clone repo và thiết lập `.env` từ secrets manager
3. Pull image: `docker compose pull`
4. Khôi phục bản sao lưu PostgreSQL từ nơi lưu trữ ngoài site
5. Khởi động tất cả service: `docker compose up -d`
6. Kích hoạt lập chỉ mục lại Typesense: `pnpm run typesense:reindex`
7. Xác minh tất cả endpoint health

**RTO dự kiến:** ~60 phút (phụ thuộc vào tốc độ truyền bản sao lưu)

### Kịch bản 4: Hỏng Dữ Liệu (cấp độ ứng dụng)

1. Xác định phạm vi: những bảng/bản ghi nào bị ảnh hưởng
2. Nếu hạn chế: khôi phục các bảng cụ thể bằng `pg_restore --table=<name>`
3. Nếu diện rộng: khôi phục toàn bộ từ bản sao lưu tốt cuối cùng được biết đến
4. Xóa cache Redis: `docker exec goodgo-redis redis-cli -a "$REDIS_PASSWORD" FLUSHALL`
5. Lập chỉ mục lại Typesense: `pnpm run typesense:reindex`

---

## Tổng Hợp Log

Log được tổng hợp qua Loki + Promtail và có thể xem trong Grafana:

- **Grafana**: http://localhost:3002 (dashboard: "GoodGo - Logs")
- **Loki**: http://localhost:3100
- **Thời gian lưu log**: 15 ngày (được cấu hình trong `monitoring/loki/loki-config.yml`)
