REFACTOR_PLAN.md¶
Garuda Chain — Rencana Refactor Bertahap
| Metadata | |
|---|---|
| Versi dokumen | 1.0.0 |
| Prinsip utama | Tidak mengganggu production |
| Pendekatan | Parallel implementation + gradual migration |
| Terakhir diperbarui | 2026-07-04 |
1. Prinsip Refactor¶
┌────────────────────────────────────────────────────────────┐
│ ATURAN MUTLAK │
├────────────────────────────────────────────────────────────┤
│ 1. JANGAN hapus fitur yang berjalan di production │
│ 2. JANGAN ubah UI/UX yang dipakai pengguna tanpa approval │
│ 3. JANGAN deploy refactor besar langsung ke mainnet │
│ 4. SETIAP perubahan harus backward compatible │
│ 5. SETIAP fase punya rollback plan │
│ 6. SETIAP fase punya test suite │
│ 7. Production tetap di apps/api, apps/wallet (v1) │
│ 8. Eksperimen di staging: apps/api-v2, branch develop │
└────────────────────────────────────────────────────────────┘
2. Diagram Strategi¶
Production (v1) Staging (v2 / refactor)
───────────────── ─────────────────────────
apps/api ─── parallel ──▶ apps/api-v2
apps/wallet ─── gradual ──▶ apps/wallet (module shell)
packages/sdk ─── extend ───▶ packages/{sdk,types,ui-core,config}
chain/deployments ◀── SSOT ────── generate-deployments.ts
data/*.json ─── migrate ──▶ PostgreSQL (staging first)
3. Fase Refactor¶
Fase 0 — Dokumentasi & Inventaris ✅¶
Durasi: 1 minggu · Risk: None · Production impact: None
| Task | Status | Output |
|---|---|---|
| SYSTEM_ARCHITECTURE.md | ✅ | docs/architecture/ |
| PROJECT_ROADMAP.md | ✅ | docs/architecture/ |
| API_DOCUMENTATION.md | ✅ | docs/architecture/ |
| DATABASE_SCHEMA.md | ✅ | docs/architecture/ |
| SECURITY_AUDIT.md | ✅ | docs/architecture/ |
| REFACTOR_PLAN.md | ✅ | Dokumen ini |
| Update mkdocs nav | ⏳ | mkdocs.yml |
Rollback: N/A (docs only)
Fase 1 — Shared Foundation¶
Durasi: 2–3 minggu · Risk: Low · Production impact: None (build-time only)
1.1 Deployment Registry Generator¶
Masalah: packages/sdk/src/deployments.ts drift dari chain/deployments/mainnet.json
Solusi:
chain/deployments/*.json
↓ scripts/generate-deployments.ts (prebuild)
packages/sdk/src/deployments.ts (generated)
Files baru:
- scripts/generate-deployments.ts
- packages/config/ — Zod schema untuk deployment JSON
Files tidak diubah: Production runtime behavior
Test: Diff generator output vs manual verify addresses
Rollback: Revert script; restore manual deployments.ts
1.2 packages/types¶
Masalah: Duplikasi type definitions (bridge, GNFT, GarudaPay) di wallet, explorer, api
Solusi:
packages/types/
├── src/
│ ├── gnft.ts
│ ├── bridge.ts
│ ├── garudaPay.ts
│ ├── community.ts
│ └── index.ts
└── package.json
Migrasi konsumen (non-breaking):
1. API imports dari @garuda-chain/types (re-export existing types)
2. Wallet + Explorer: import bertahap per modul
3. Hapus duplikat hanya setelah semua konsumen migrated
Rollback: Revert imports ke local types
1.3 packages/ui-core¶
Masalah: gnftDisplay.ts duplikat di wallet dan explorer
Solusi:
packages/ui-core/
├── src/
│ ├── gnftDisplay.ts # unified dengan options
│ ├── formatAddress.ts # shortenHash / formatShortAddress
│ └── index.ts
Catatan: Explorer hideHolder: true default; Wallet hideHolder: false — satu fungsi, parameter berbeda.
Rollback: Restore local copies
1.4 API Test Bootstrap¶
Masalah: Zero automated tests di API
Solusi:
apps/api/
├── vitest.config.ts
└── src/__tests__/
├── health.test.ts
├── walletAuth.test.ts
├── communityCheckIn.test.ts
├── gnftMetadata.test.ts
└── bridgeQuote.test.ts
CI: Add npm run test -w @garuda-chain/api to pipeline
Rollback: Remove test files (no production impact)
Fase 2 — API Decomposition (Staging Parallel)¶
Durasi: 4–6 minggu · Risk: Medium · Production impact: None
2.1 Extract inline routes dari index.ts¶
Saat ini: ~340 baris bootstrap + inline routes di apps/api/src/index.ts
Target structure (v1 — same app, better organization):
apps/api/src/
├── index.ts # Bootstrap only (~50 lines)
├── routes/
│ ├── chain.ts # NEW: blocks, txs, accounts (from index.ts)
│ └── ... (existing)
└── services/
├── chainService.ts # RPC logic extracted
└── accountService.ts
Approach: Extract tanpa mengubah response shape · Test parity
Rollback: Git revert single PR
2.2 apps/api-v2 Skeleton (Staging Only)¶
Struktur Clean Architecture:
apps/api-v2/
├── src/
│ ├── domain/
│ │ ├── entities/
│ │ └── repositories/ # interfaces
│ ├── application/
│ │ └── use-cases/
│ ├── infrastructure/
│ │ ├── persistence/
│ │ │ ├── json/ # adapter existing stores
│ │ │ └── postgres/ # new adapter
│ │ └── blockchain/
│ │ └── rpcAdapter.ts
│ └── presentation/
│ ├── routes/
│ └── middleware/
├── package.json
└── Dockerfile
Scope fase 2.2: Read-only endpoints only
- GET /health
- GET /api/v2/chain
- GET /api/v2/network/contracts
- GET /api/v2/gnft/listings
Deploy: Staging only, port 4001, Caddy route api-v2.staging.garudachain.id
Rollback: Remove container; v1 unaffected
2.3 Garuda Pay Route Split¶
Masalah: garudaPay.ts ~700 baris
Target:
apps/api/src/routes/garudaPay/
├── index.ts # router mount
├── profile.ts
├── charge.ts
├── transfer.ts
├── fiat.ts
└── cs.ts
Constraint: Same URL paths, same response — internal refactor only
Fase 3 — Database Migration (Staging)¶
Durasi: 4–6 minggu · Risk: High · Production impact: None until Fase 5
3.1 PostgreSQL Setup¶
# docker-compose.staging.yml addition
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: garuda_staging
volumes:
- pgdata:/var/lib/postgresql/data
3.2 Repository Pattern¶
// domain/repositories/GarudaPayRepository.ts
interface GarudaPayRepository {
getProfile(address: string): Promise<GarudaPayProfile>;
saveProfile(address: string, profile: GarudaPayProfile): Promise<void>;
// ...
}
// infrastructure/persistence/json/JsonGarudaPayRepository.ts — wraps existing
// infrastructure/persistence/postgres/PgGarudaPayRepository.ts — new
3.3 Dual-Write Migration¶
Week 1-2: Write to JSON only (baseline)
Week 3-4: Write to JSON + PostgreSQL (dual-write)
Week 5-6: Read from PostgreSQL, verify parity with JSON
Week 7+: Write PostgreSQL only, JSON as export backup
Verification script: scripts/migrate/verify-garuda-pay-parity.ts
Rollback: Flip env GARUDA_PAY_REPOSITORY=json
Fase 4 — Wallet Modularization¶
Durasi: 4–6 minggu · Risk: Medium · Production impact: Low (lazy load only)
4.1 Code Splitting¶
// MainWalletApp.tsx
const MarketScreen = lazy(() => import("./screens/MarketScreen"));
const NFTGalleryScreen = lazy(() => import("./screens/TemplateScreens").then(m => ({ default: m.NFTGalleryScreen })));
Target: Initial bundle < 600KB
4.2 Module Registry (POC)¶
// lib/modules/registry.ts
export interface GarudaModule {
id: string;
tabId?: string;
load: () => Promise<React.ComponentType>;
}
export const modules: GarudaModule[] = [
{ id: "core", load: () => import("../screens/DashboardScreens") },
{ id: "cards", tabId: "cards", load: () => import("../screens/TemplateScreens") },
// ...
];
Constraint: Tab behavior identical; only loading mechanism changes
4.3 Wallet Key Security (POC Staging)¶
Current: sessionStorage plaintext private key
Target:
Unlock → derive sessionToken (random UUID)
→ privateKey in closure/module singleton only
→ sessionStorage stores { sessionToken, address } only
→ clear on lock/tab close
Test: E2E unlock → send → lock → verify key not in sessionStorage
Rollback: Feature flag VITE_SECURE_SESSION=false
Fase 5 — Security Hardening¶
Durasi: 2–3 minggu · Risk: Low-Medium · Staging first
| Change | File | Rollback |
|---|---|---|
| Bridge relay auth | routes/bridge.ts |
Env BRIDGE_RELAY_OPEN=true (dev only) |
| CORS restrict | index.ts |
Env CORS_ORIGIN=* override |
| GraphQL auth | graphql/ |
Env GRAPHQL_PUBLIC=true |
| CSP headers | apps/wallet/public/_headers |
Remove header |
| Zod validation | per route | Disable middleware |
Production deploy: Only after 14-day staging soak
Fase 6 — Production Migration¶
Durasi: 4–8 minggu · Risk: High · Requires: All gates passed
Migration Order (safest first)¶
| Order | Component | Strategy | Downtime |
|---|---|---|---|
| 1 | Deployment registry | Build-time | Zero |
| 2 | Shared packages | Deprecation period | Zero |
| 3 | API inline route extract | Blue-green | Zero |
| 4 | Security hardening | Config deploy | Zero |
| 5 | Wallet code splitting | Cloudflare deploy | Zero |
| 6 | PostgreSQL Garuda Pay | Dual-write cutover | < 1 min |
| 7 | PostgreSQL KYC | Dual-write cutover | < 1 min |
| 8 | Community state DB | Background migration | Zero |
| 9 | API v2 shadow traffic | Gradual 10→50→100% | Zero |
| 10 | Wallet secure session | Feature flag rollout | Zero |
Gate Checklist (per component)¶
- [ ] Staging soak ≥ 14 days
- [ ] Automated tests pass
- [ ] Smoke test production-like load
- [ ] Rollback tested
- [ ] Monitoring alerts configured
- [ ] Runbook documented
- [ ] Team sign-off
4. Yang TIDAK Di-refactor¶
| Area | Alasan |
|---|---|
| Smart contracts production | Butuh audit + governance; redeploy only |
| Besu validator setup | Operational stability |
| Wallet visual design / branding | User-facing stability |
| Bottom nav structure | UX familiarity |
| Chain ID 8846 genesis | Immutable |
| Existing API URL paths | Backward compatibility |
5. Duplikasi Kode — Prioritas Konsolidasi¶
| Duplikat | Lokasi | Target | Fase |
|---|---|---|---|
gnftDisplay.ts |
wallet, explorer | packages/ui-core |
1 |
formatAddress |
wallet, explorer | packages/ui-core |
1 |
| Bridge types | wallet, explorer, admin | packages/types |
1 |
| RPC probing | wallet rpc.ts, explorer chain.ts, admin monitor.ts |
packages/sdk rpcHealth |
2 |
MaterialIcon.tsx |
wallet, admin | packages/ui-core |
2 |
| Chain client logic | wallet chain.ts, explorer chain.ts |
SDK + thin adapters | 3 |
Tidak dikonsolidasi: Explorer server cache (Next.js specific), Wallet encrypted storage (client specific)
6. Branch & Release Strategy¶
main ← production releases only
develop ← integration branch
feature/* ← per-phase work
release/* ← staging candidates
hotfix/* ← production critical fixes
Release cadence:
- Staging: weekly (auto dari develop)
- Production: monthly atau per-milestone (manual gate)
7. Testing Strategy¶
| Level | Tool | Coverage target |
|---|---|---|
| Unit | Vitest | API services, packages |
| Integration | Vitest + supertest | API routes |
| Contract | Foundry | Smart contracts (existing) |
| E2E Wallet | Playwright | Critical flows (staging) |
| E2E Staging | npm run staging:smoke |
Deploy gate |
| Load | k6 | API read 1000 RPS |
| Security | OWASP ZAP (staging) | Quarterly |
8. Monitoring Refactor Health¶
| Metric | Alert threshold |
|---|---|
| API error rate | > 1% for 5 min |
| API p99 latency | > 2s |
| Wallet JS errors (Sentry) | > 10/min |
| Bridge relay failures | > 3 consecutive |
| PostgreSQL replication lag | > 5s |
| JSON/DB parity drift | Any mismatch |
9. Rollback Playbook (Ringkas)¶
API deploy rollback¶
# VPS: restore previous Docker image
docker compose -f docker-compose.mainnet.yml -f docker-compose.production.yml up -d --no-deps api
Wallet rollback¶
# Cloudflare Pages: rollback to previous deployment via dashboard
# Or redeploy previous dist from git tag
git checkout <tag> && npm run wallet:deploy:cloudflare
Database rollback¶
# Flip repository adapter
export GARUDA_PAY_REPOSITORY=json
# Restore JSON from backup
cp data/garuda-pay-store.json.bak data/garuda-pay-store.json
docker compose restart api
10. Timeline Ringkas¶
| Fase | Durasi | Production touch? |
|---|---|---|
| 0 — Dokumentasi | 1 minggu | ❌ |
| 1 — Shared Foundation | 2-3 minggu | ❌ (build only) |
| 2 — API Decomposition | 4-6 minggu | ❌ |
| 3 — Database Migration | 4-6 minggu | ❌ (staging) |
| 4 — Wallet Modular | 4-6 minggu | ❌ (staging) / 🟡 (code split only) |
| 5 — Security Hardening | 2-3 minggu | 🟡 (after staging soak) |
| 6 — Production Migration | 4-8 minggu | ✅ (gradual) |
Total estimasi: 6–9 bulan untuk refactor penuh dengan zero-downtime migration.
11. Referensi¶
- SYSTEM_ARCHITECTURE.md
- PROJECT_ROADMAP.md
- DATABASE_SCHEMA.md — Section 7 (migrasi)
- SECURITY_AUDIT.md — Action plan
- staging-deployment.md