FCM — Polqo Migration Plan
Status: 🟡 Ready — prerequisite extraction Phase 0–4 confirmed DONE 2026-05-19. Polqo migration eksekusi belum dimulai (kredensial Firebase di services/firebase_service masih project Kesles, belum di-swap ke project Polqo).
Owner: Backend Lead
Prasyarat: ✅ extraction-plan.md Phase 4 DONE (firebase_service single source of truth).
Dokumen terkait:
architecture.md— desain serviceextraction-plan.md— ekstraksi dari embedded ke serviceshadow-mode-plan.md— shadow mode sebelum cutoverphase4-readiness.md— observation window 14 hari sebelum Phase 4- ADR 0009 (polqo repo) — Firebase project isolation Polqo vs Kesles
- ADR 0005 (polqo repo) — fork-and-run-parallel extraction pattern
Status reality update (2026-05-14)
Plan ini ditulis 2026-05-04 ketika extraction belum dimulai. Update kondisi saat ini:
Yang sudah selesai:
- ✅
firebase-serviceextraction Phase 0–2 selesai, live di VM production - ✅ Phase 1 (
FCM_TOKEN_STORE=service) + Phase 2 (FCM_TRANSPORT=service) aktif - ✅ DB migration 125 (
app_version,heartbeat_at) applied - ✅ Caller di
merchant_core_apisemua via wrapperdispatchPush - ✅ Phase B.1 multi-staff role policy aktif (eligibility per event type)
- ✅ Phase 4 step 1 (2026-05-14):
merchant_core_api/internal/push/fcm.godihapus. Source of truth Firebase SDK tunggal diservices/firebase_service/. Mirror obligation expired.dispatchPushsignature →(*SendResult, error).
Belum selesai (prasyarat Polqo migration):
- ⏳ Phase 3 observation window — sampai 2026-05-25 (14 hari) sesuai
phase4-readiness.md. Decision GO/NO-GO untuk Phase 4 sisa step. - ⏳ Phase 4 step 4–6 — hapus flag
FCM_TRANSPORT+FCM_TOKEN_STORE+ fallback DB diregisterPushTokenViaConfiguredStore. ImplementasiMarkTokenInvaliddi service (auto-deactivate token saat UNREGISTERED).
Keputusan operasional yang affect Polqo plan (Opsi C hybrid, 2026-05-11):
Production merchant_core_api/.env.production TIDAK lagi menyimpan
FIREBASE_* credential. Hanya services/firebase_service/.env.production yang
punya. Konsekuensi untuk Polqo migration:
- Rollback path saat Polqo cutover lebih sempit — kalau Polqo mati, FCM
Kesles tetap bisa fallback ke
services/firebase_service(Firebase Kesles). Tapi kalau firebase_service Kesles juga di-decommission (Phase P4 plan ini), tidak ada lagi safety net. Pertahankan firebase_service Kesles minimal 2-4 minggu setelah Polqo full cutover (P3) sebelum hapus. - Firebase credential rotation — sebelumnya 2 lokasi (core_api + firebase_service), sekarang 1 lokasi (firebase_service saja). Rotasi sebelum Polqo cutover cuma butuh update 1 file env.
1. Konteks
Setelah firebase-service berdiri sebagai service mandiri (lihat extraction plan),
langkah berikutnya adalah memindahkan traffic FCM Kesles ke Polqo FCM Service
(polqo-fcm-service) yang berjalan sebagai notification-as-a-service multi-tenant.
Tujuan migrasi ini:
- Kesles tidak lagi mengelola Firebase credential sendiri — Polqo yang mengelola
- Polqo mendapat traffic FCM pertamanya sebagai tenant
kesles - Infrastruktur push terpusat — WA, FCM, SMS semua dari satu platform
2. Prasyarat Sebelum Migrasi Dimulai
Semua item berikut harus selesai sebelum Phase 1 migrasi dimulai:
| Prasyarat | Status (2026-05-18) | Catatan |
|---|---|---|
firebase-service Kesles sudah production (extraction Phase 3) | 🟡 Live di VM, observation 14 hari — 7 hari tersisa | Decision GO/NO-GO 2026-05-25 |
firebase-service extraction Phase 4 cleanup | ✅ DONE 2026-05-14 (dimulai lebih awal dari Phase 3 GO) | Mirror obligation expired. Step 4 Opsi C outcome pending update post-soak. |
polqo-fcm-service sudah punya endpoint /internal/fcm/send dan /send-bulk | ⏳ | Wajib — external dependency dari tim Polqo |
| Polqo punya Firebase project terpisah dari Kesles (ADR 0009) | ⏳ | Wajib — jangan pakai project yang sama |
Polqo punya tenant registration untuk tenant_id=kesles | ⏳ | Wajib — need coordination |
Shadow mode selesai (lihat shadow-mode-plan.md) | ⏳ | Sangat dianjurkan |
Polqo bisa verifikasi X-Tenant-ID + X-Internal-API-Key di setiap request | ⏳ | Wajib |
Backfill push token dari db_kesles_merchant ke Polqo DB selesai | ⏳ | Wajib sebelum cutover. Update 2026-05-26: scaffold db_kesles_merchant_notification sudah ready (target intermediate sebelum lift ke Polqo). |
3. Arsitektur Target
Saat ini (post-extraction, pre-migration)
merchant_core_api
│ HTTP POST /internal/fcm/send
▼
firebase-service (Kesles, port 8093)
│ FCM HTTP v1 API
▼
Firebase (project: kesles-merchant)
Target akhir (post-migration)
merchant_core_api
│ HTTP POST /internal/fcm/send (sama — tidak berubah)
▼
firebase-service (Kesles, port 8093) ← thin proxy / adapter
│ HTTP POST /api/fcm/send?tenant_id=kesles
▼
polqo-fcm-service (api.polqo.com, port 8082)
│ FCM HTTP v1 API
▼
Firebase (project: polqo-notifications) ← BERBEDA dari project Kesles
merchant_core_api tidak tahu perbedaan — tetap memanggil firebase-service lokal.
firebase-service yang berubah peran menjadi proxy ke Polqo.
4. Feature Flag
Feature flag diset di firebase-service (bukan merchant_core_api):
USE_POLQO_FCM=false # default — kirim langsung ke Firebase Kesles
USE_POLQO_FCM=true # proxy ke Polqo FCM service
POLQO_FCM_BASE_URL=https://api.polqo.com
POLQO_FCM_TENANT_ID=kesles
POLQO_FCM_API_KEY=<api-key-dari-polqo>
Saat USE_POLQO_FCM=true, firebase-service menjadi thin proxy —
meneruskan request ke Polqo tanpa memanggil Firebase langsung.
5. Tahapan Migrasi
Phase P0 — Token Backfill
Estimasi: 1 hari
Sebelum Polqo bisa kirim push ke device Kesles, Polqo perlu tahu push token masing-masing user. Ada dua mekanisme:
Opsi A: Backfill batch (satu kali)
-- Export semua token aktif dari Kesles.
-- Saat ini: query db_kesles_merchant.notification.fcm_push_tokens
-- Post DB extraction (Phase D): query db_kesles_merchant_notification.notification.fcm_push_tokens
-- Schema sama → kolom & struktur tidak berubah, cukup swap DSN.
SELECT user_id, push_token, platform_code, device_id, app_version, last_seen_at
FROM notification.fcm_push_tokens
WHERE is_active = TRUE
AND last_seen_at > now() - interval '30 days';
Script Go/Python: baca query hasil → POST ke polqo-fcm-service /internal/fcm/tokens
satu per satu (atau batch insert via Polqo admin API).
Opsi B: Forward register real-time (preferred)
firebase-service Kesles mem-forward setiap POST /internal/fcm/tokens ke Polqo
segera setelah simpan ke DB lokal (saat USE_POLQO_FCM=false maupun true).
Ini memastikan token Polqo selalu up-to-date tanpa backfill manual.
Rekomendasi: Jalankan Opsi A sekali (backfill historis), lalu aktifkan Opsi B untuk token baru / refresh.
- Script backfill dibuat dan ditest di staging Polqo
- Script dijalankan ke production Polqo
- Verifikasi: query Polqo
/internal/fcm/tokens?merchant_id=<uuid>returns data
Phase P1 — Shadow Mode (dual-send)
Estimasi: 3–5 hari
Lihat shadow-mode-plan.md untuk detail lengkap.
Ringkasan: firebase-service mengirim push ke dua tujuan secara paralel —
Firebase Kesles (primary) dan Polqo (shadow). Hanya response dari Kesles
yang dikembalikan ke caller. Polqo failure tidak mempengaruhi delivery.
Goal shadow mode:
- Verifikasi Polqo bisa deliver push ke device Kesles
- Bandingkan delivery rate dan error rate
- Pastikan token backfill lengkap (tidak ada token yang miss di Polqo)
Durasi shadow mode: minimal 48 jam sebelum cutover.
Phase P2 — Gradual Cutover per Event Type
Estimasi: 3–5 hari
Setelah shadow mode stabil, mulai cutover per event type dari paling aman:
| Urutan | Event type | Risiko | Cutover |
|---|---|---|---|
| 1 | login_alert | Rendah | Hari 1 |
| 2 | news | Rendah | Hari 1 |
| 3 | merchant_status_* | Rendah | Hari 1 |
| 4 | order_* (9 event) | Menengah | Hari 2 |
| 5 | merchant_activated | Menengah | Hari 3 |
| 6 | transaction_info | Tinggi | Hari 4–5 (setelah yang lain stabil) |
Mekanisme cutover per event type:
Di firebase-service, ada config per event type:
# Format: POLQO_FCM_EVENTS=event_type_1,event_type_2
POLQO_FCM_EVENTS=login_alert,news,merchant_status_pending
Event yang ada di list → kirim ke Polqo. Event yang tidak ada → kirim ke Firebase Kesles langsung.
Ini memungkinkan cutover bertahap tanpa deploy ulang (hanya restart env).
- Login alert dan news → Polqo (Hari 1)
- Merchant status events → Polqo (Hari 1–2)
- Order events → Polqo (Hari 2–3)
- Transaction info → Polqo (Hari 4–5)
- Monitor setiap step: delivery rate, error rate, latency
Phase P3 — Full Cutover
Estimasi: 1 hari
Setelah semua event type di Phase P2 stabil minimal 24 jam:
- Set
USE_POLQO_FCM=truedifirebase-serviceproduction - Hapus
POLQO_FCM_EVENTSenv (sudah tidak diperlukan — semua ke Polqo) - Monitor 4 jam pertama secara aktif
- Revoke Firebase credential Kesles (simpan di vault dulu, jangan langsung hapus)
Acceptance criteria Phase P3:
- Seluruh push delivered via Polqo, zero delivery via Firebase Kesles
- Push delivery rate sama atau lebih baik dari baseline
- Zero regresi di
merchant_core_api(tidak ada error baru di caller)
Phase P4 — Cleanup dan Decommission
Estimasi: 1 hari (sprint berikutnya)
Setelah P3 stabil minimal 2 minggu:
- Hapus Firebase credential Kesles dari vault
- Hapus code path
USE_POLQO_FCM=falsedarifirebase-service - Hapus
firebase-serviceKesles jika Polqo sudah support direct call darimerchant_core_api(opsional — bisa tetap jalan sebagai adapter layer) - Update
service-topology.mddan arsitektur docs - Update ADR 0009 status →
supersededatauimplemented
6. Token Lifecycle selama Migrasi
Saat shadow mode aktif
Semua register/refresh token ditulis ke dua tempat:
notification.fcm_push_tokens(DB Kesles) — viafirebase-servicelokal- Polqo token store — via Polqo
/internal/fcm/tokensendpoint
Saat cutover (P2–P3)
Token yang masuk setelah cutover otomatis di Polqo. Token lama (sebelum cutover) sudah di-backfill di Phase P0.
Token invalidasi
Saat Polqo mendeteksi token UNREGISTERED:
- Polqo deactivate di token store Polqo
- Polqo harus memanggil balik
DELETE /internal/fcm/tokens/{token}kefirebase-serviceKesles agar DB lokal juga update
Ini memerlukan webhook atau callback dari Polqo ke Kesles. Polqo harus menyediakan mekanisme ini sebelum full cutover dilakukan.
7. Rollback Plan
Rollback dari Phase P1 (shadow mode)
Matikan shadow mode:
# Di firebase-service, hapus atau set kosong:
POLQO_SHADOW_ENABLED=false
Restart firebase-service — primary delivery via Firebase Kesles tetap jalan.
Zero impact ke end user.
Rollback dari Phase P2 (gradual cutover)
Set POLQO_FCM_EVENTS kembali ke list kosong atau event yang sudah stabil saja:
POLQO_FCM_EVENTS= # kosong = semua tetap ke Firebase Kesles
Restart firebase-service.
Rollback dari Phase P3 (full cutover)
USE_POLQO_FCM=false
Restart firebase-service. Firebase Kesles credential masih valid (belum di-revoke
sampai P4).
Catatan penting: Jangan revoke Firebase Kesles credential sampai P3 sudah stabil minimal 2 minggu.
8. Risiko dan Mitigasi
| Risiko | Likelihood | Impact | Mitigasi |
|---|---|---|---|
| Polqo Firebase project tidak bisa deliver ke device Kesles | Rendah | Tinggi | Shadow mode wajib sebelum cutover |
| Token backfill tidak lengkap — user lama tidak dapat push | Menengah | Tinggi | Verifikasi sample sebelum P2 |
| Polqo tidak punya callback untuk token invalidasi | Menengah | Menengah | Implement sebelum P3, atau manual sync |
| Latency tambahan dari hop ke Polqo | Rendah | Rendah | SLA Polqo < 200ms; test di staging |
| Polqo rate limit memotong delivery saat volume tinggi | Rendah | Tinggi | Konfirmasi rate limit sebelum P2 |
| Firebase Kesles credential di-revoke sebelum waktunya | Rendah | Tinggi | P4 cleanup hanya setelah 2 minggu stabil |
9. Koordinasi dengan Tim Polqo
Item yang perlu dikonfirmasi / dikerjakan bersama tim Polqo:
- Polqo menyediakan
tenant_id=keslesdan API key untukfirebase-serviceKesles - Polqo konfirmasi endpoint schema:
/api/fcm/senddengantenant_idheader atau query param - Polqo menyediakan mekanisme callback / webhook untuk token invalidasi
- Polqo menyediakan Firebase project terpisah (ADR 0009 compliance)
- Polqo menyediakan dashboard monitoring per tenant untuk Kesles
- Polqo konfirmasi rate limit (request/detik) untuk tenant Kesles
- Polqo konfirmasi SLA uptime dan SLA latency untuk FCM delivery
10. Checklist Go/No-Go untuk Full Cutover (Phase P3)
Semua item berikut harus YES sebelum USE_POLQO_FCM=true diset di production:
- Shadow mode berjalan > 48 jam tanpa error signifikan di Polqo
- Polqo delivery rate ≥ Firebase Kesles delivery rate (dari shadow mode)
- Token backfill 100% selesai dan diverifikasi
- Polqo callback untuk token invalidasi sudah tested
- Gradual cutover P2 selesai untuk semua event type rendah/menengah (Hari 1–3)
- Monitoring alert Polqo sudah setup (delivery rate, error rate, latency)
- Rollback plan sudah ditest di staging (set
USE_POLQO_FCM=false→ recovery) - Firebase Kesles credential belum di-revoke
- Tim on-call aware dan siap monitoring selama 4 jam pertama post-cutover
11. Timeline Estimasi
| Phase | Durasi | Catatan |
|---|---|---|
| Extraction plan selesai (prasyarat) | Selesai terlebih dahulu | |
| P0 — Token backfill | 1 hari | |
| P1 — Shadow mode | 3–5 hari | Minimal 48 jam observasi |
| P2 — Gradual cutover | 3–5 hari | Per event type |
| P3 — Full cutover | 1 hari | |
| P4 — Cleanup | 1 hari | 2 minggu setelah P3 |
| Total | ~2–3 minggu | Tergantung kesiapan Polqo |
12. Dokumen Terkait
architecture.mdextraction-plan.md— tahap sebelumnyashadow-mode-plan.md— detail Phase P1services/whatsapp/architecture.md— referensi pola yang sama