KB-2CFB rev 7

Migration Plan v2: Chuyển nhà về VPS — 6 Checkpoints

9 min read Revision 7
migrationVPSGCPPostgreSQLplanS109

MIGRATION PLAN v2: CHUYỂN NHÀ VỀ VPS — 6 CHECKPOINTS

S109 | 11/03/2026 | Huyen phê duyệt | v2 — sau kiểm tra thực tế search_knowledge("migration plan chuyển nhà VPS")


BỐI CẢNH

GCP đốt ₫45K/ngày do cross-region transfer (VPS EU ↔ GCP Singapore). Chuyển tất cả về VPS, chỉ giữ Secret Manager ($2/tháng).

PHÁT HIỆN TỪ KIỂM TRA THỰC TẾ (11/03/2026):

  • PostgreSQL 16 chạy rồi (container workflow-postgres, healthy 11 ngày)
  • PG nằm compose RIÊNG (nuxt-repo/web/.directus/docker-compose.yaml) → cần merge
  • Firestore: 4 core files, server.py nặng nhất (~20 refs) → MEDIUM-HIGH
  • GCS Bucket: 2 files, LOW complexity (chỉ ingestion) → nhanh hơn dự kiến
  • ⚠️ Agent-data + Nuxt image pull từ Artifact Registry → CP-1 PHẢI XONG TRƯỚC disable billing
  • Disk: 59GB available / 96GB total → đủ
  • 14 secrets, phần lớn cần giữ

THỨ TỰ BẮT BUỘC

CP-0  Consolidate Docker + Backup           ← chuẩn bị
CP-1  Artifact Registry → GH Direct         ← BẮT BUỘC TRƯỚC disable billing
CP-B  DISABLE BILLING GCP                   ← chỉ sau CP-1 xong
CP-2  GCS Buckets → VPS Local               ← 0.5-1 ngày (giảm từ 1.5)
CP-3  Firestore → PostgreSQL                ← 2-3 ngày (core)
CP-4  Verify + Cleanup                      ← 1 ngày
CP-5  Domain migration (bonus)              ← song song

CP-0: CONSOLIDATE DOCKER + BACKUP (Ngày 0, ~0.5 ngày)

⚠️ KHÔNG disable billing ở bước này — agent-data + nuxt vẫn cần pull image từ AR!

Checklist:

  • Upload Luật Hạ tầng VPS
  • Cập nhật Hiến pháp v3.2
  • Merge workflow-postgres vào main /opt/incomex/docker/docker-compose.yml:
    • Thêm postgres service, volume mapping, network
    • Đổi container_name → postgres (khớp migration commands)
    • Đảm bảo cùng Docker network với agent-data
  • Tạo database + user:
    docker exec postgres psql -U postgres -c "CREATE DATABASE incomex_metadata;"docker exec postgres psql -U postgres -c "CREATE USER incomex WITH PASSWORD '***';"docker exec postgres psql -U postgres -c "GRANT ALL ON DATABASE incomex_metadata TO incomex;"
    
  • Backup Firestore: gcloud firestore export gs://[BUCKET]/firestore-backup-pre-migration/
  • Backup Buckets: gsutil -m rsync -r gs://huyen1974_agent_data_knowledge_test /opt/incomex/backups/gcs-pre-migration/

Verify:

  • docker exec postgres psql -U incomex -d incomex_metadata -c "SELECT 1;" → OK
  • docker compose ps → postgres healthy trong main compose
  • Backup files tồn tại

CP-1: ARTIFACT REGISTRY → GH DIRECT DEPLOY (Ngày 1, ~0.5 ngày)

⚠️ PHẢI XONG trước disable billing — nếu không, agent-data + nuxt không deploy được!

Thực tế phát hiện:

  • agent-data-test ĐÃ CÓ deploy-vps.yml nhưng vẫn pull image từ AR
  • web-test có proven pattern: GH Actions → build → SSH push → docker compose up
  • Cần refactor: build image trên GH Actions/VPS, KHÔNG pull từ AR

Checklist:

  • Refactor deploy-vps.yml cho agent-data-test: bỏ AR pull, build local hoặc GH Actions build + scp
  • Disable/xóa artifact-registry-cd.yml workflow
  • Đảm bảo Nuxt deploy cũng không phụ thuộc AR (kiểm tra nuxt workflow)
  • Test: push commit → build → deploy → health check pass

Verify:

  • curl https://vps.incomexsaigoncorp.vn/api/health → 200 sau deploy mới (KHÔNG dùng AR)
  • Pipeline GREEN trên GitHub Actions
  • Không có asia-southeast1-docker.pkg.dev trong workflow files

CP-B: DISABLE BILLING GCP (Ngay sau CP-1 pass)

Chỉ thực hiện SAU KHI CP-1 verify thành công.

Checklist:

  • GCP Console → Billing → Account Management → Actions (⋮) cạnh Github-chatgpt → Disable billing
  • HOẶC: Huyen xác nhận cho tôi thao tác qua Computer Use

Verify:

  • Deploy agent-data vẫn hoạt động (không phụ thuộc AR)
  • Deploy nuxt vẫn hoạt động
  • curl https://vps.incomexsaigoncorp.vn/api/health → 200
  • Billing reports: chi phí giảm xuống ~₫0 (trừ Secret Manager)

CP-2: GCS BUCKETS → VPS LOCAL STORAGE (Ngày 1-2, ~0.5-1 ngày — giảm từ 1.5)

Thực tế: Chỉ 2 files dùng GCS (server.py, main.py), LOW complexity — chỉ ingestion. ⚠️ CP-0 phát hiện: Bucket huyen1974_agent_data_knowledge_test trả 404 — có thể đã xóa. Chỉ còn huyen1974-system-backups-shared (13 postgres backup files, 60KB). CP-2 có thể đơn giản hơn dự kiến.

Checklist:

  • Tạo /opt/incomex/data/storage/{uploads,knowledge,exports,snapshots,logs}
  • Sync: gsutil -m rsync -r gs://huyen1974_agent_data_knowledge_test /opt/incomex/data/storage/knowledge/
  • Refactor 2 files: thay google.cloud.storage → local filesystem
  • Cập nhật .env: STORAGE_PATH=/opt/incomex/data/storage
  • Cấu hình Nginx serve static files (nếu cần public access)

Verify:

  • Ingestion hoạt động từ local files
  • Không còn import google.cloud.storage trong code
  • df -h < 85%

CP-3: FIRESTORE → POSTGRESQL (Ngày 2-4, ~2-3 ngày) ⭐ QUAN TRỌNG NHẤT

Thực tế: 4 core files, server.py nặng nhất (~20 Firestore refs). Collections: kb_documents (chính), chat sessions/memory.

Chiến lược: Giữ nguyên interface _firestore(), thay backend → PostgreSQL

Checklist:

  • Export Firestore collections → JSON
  • Thiết kế PostgreSQL tables cho kb_documents + chat memory
  • Import data JSON → PostgreSQL
  • Refactor 4 files:
    • server.py: thay _firestore() → PostgreSQL queries (~20 calls)
    • main.py: thay firestore.Client() → PostgreSQL connection
    • resilient_client.py: thay probe_firestore()probe_postgres()
    • memory.py: thay Firestore chat memory → PostgreSQL
  • Cập nhật requirements.txt: bỏ firebase-admin, thêm asyncpg/psycopg2
  • Cập nhật .env: POSTGRES_URL=postgresql://incomex:***@postgres:5432/incomex_metadata
  • Test từng endpoint: CRUD, search, list, health

Verify:

  • Tất cả API endpoints đúng (so sánh với Firestore data)
  • Latency < 10ms (local PG) vs >100ms (Firestore trước đó)
  • grep -r "firestore\|firebase" /app/ --include="*.py" → 0 results (trừ comments)
  • Health check: postgres probe thay firestore probe

CP-4: VERIFY + CLEANUP (Ngày 5-6, ~1 ngày)

Trước CP-4: CP-3B — DIRECTUS MYSQL → POSTGRESQL (~1 ngày)

Mục tiêu: Directus chạy trên PostgreSQL thay MySQL. Retire MySQL. 1 database engine duy nhất.

Cách làm tổng quát:

  • Export MySQL data (mysqldump hoặc Directus schema migration)
  • Tạo Directus database trên PostgreSQL
  • Import data → PG
  • Đổi Directus config: DB_CLIENT=pg, DB_HOST=postgres, DB_DATABASE=directus
  • Verify Directus hoạt động bình thường
  • Retire MySQL container

Verify: Directus healthy, tất cả collections/items/flows hoạt động, MySQL container removed.

Checklist CP-4:

  • Monitor 24h: logs, errors, performance
  • Cập nhật: infrastructure context pack, VPS spec, CLAUDE.md, AGENTS.md, skills
  • Report: knowledge/current-state/reports/vps-migration-complete-report.md
  • GCP cleanup: xóa buckets rỗng, disable APIs không dùng
  • Xóa secrets không cần: GCS_BUCKET_BACKUP, Qdrant legacy

Verify:

  • Health 200, billing ≤₫52K/tháng, docs phản ánh thực tế

CP-5: DOMAIN MIGRATION (bonus, song song)

  • DNS: ai.incomexsaigoncorp.vn → A record 38.242.240.89
  • Certbot SSL + Nginx server block cho ai. domain
  • Disable Firebase Hosting
  • Verify: curl https://ai.incomexsaigoncorp.vn → 200

TIMELINE v2

Ngày 0:     CP-0 Consolidate Docker + Backup    ✅ DONE
Ngày 1:     CP-1 Artifact → Direct Deploy       ✅ DONE
            CP-2+CP-3 Buckets+Firestore → PG     [Claude Code] ← ĐANG LÀM
Ngày 2-4:   CP-2+CP-3 tiếp tục                   [Claude Code]
Ngày 4-5:   CP-3B Directus MySQL → PostgreSQL     [Claude Code]
            CP-B Disable billing GCP              [Huyen — sau xác nhận ổn định]
Ngày 5-6:   CP-4 Verify + Cleanup                 [Claude + Computer Use]
Song song:  CP-5 Domain migration                  [Claude Code]

Tổng: 5-6 ngày (giảm từ 5-6 nhờ CP-2 nhanh hơn, +1 ngày CP-3B)

CHI PHÍ TRƯỚC → SAU

Trước Sau
GCP ~$58/tháng ~$2/tháng
VPS $8/tháng $8/tháng
VPS RAM/Disk MySQL + PG chạy song song Chỉ PG — tiết kiệm ~1-2GB RAM
Tổng $66/tháng $10/tháng
Tiết kiệm 85% (~$672/năm)

Migration Plan v2.0 | S109 | 6 Checkpoints (CP-0,1,B,2,3,4,5) | Target: 4-5 ngày