Skip to main content

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 service
  • extraction-plan.md — ekstraksi dari embedded ke service
  • shadow-mode-plan.md — shadow mode sebelum cutover
  • phase4-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-service extraction 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_api semua via wrapper dispatchPush
  • ✅ 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.go dihapus. Source of truth Firebase SDK tunggal di services/firebase_service/. Mirror obligation expired. dispatchPush signature → (*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 di registerPushTokenViaConfiguredStore. Implementasi MarkTokenInvalid di 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:

  1. Kesles tidak lagi mengelola Firebase credential sendiri — Polqo yang mengelola
  2. Polqo mendapat traffic FCM pertamanya sebagai tenant kesles
  3. 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:

PrasyaratStatus (2026-05-18)Catatan
firebase-service Kesles sudah production (extraction Phase 3)🟡 Live di VM, observation 14 hari — 7 hari tersisaDecision 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:

UrutanEvent typeRisikoCutover
1login_alertRendahHari 1
2newsRendahHari 1
3merchant_status_*RendahHari 1
4order_* (9 event)MenengahHari 2
5merchant_activatedMenengahHari 3
6transaction_infoTinggiHari 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=true di firebase-service production
  • Hapus POLQO_FCM_EVENTS env (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=false dari firebase-service
  • Hapus firebase-service Kesles jika Polqo sudah support direct call dari merchant_core_api (opsional — bisa tetap jalan sebagai adapter layer)
  • Update service-topology.md dan arsitektur docs
  • Update ADR 0009 status → superseded atau implemented

6. Token Lifecycle selama Migrasi​

Saat shadow mode aktif​

Semua register/refresh token ditulis ke dua tempat:

  • notification.fcm_push_tokens (DB Kesles) — via firebase-service lokal
  • Polqo token store — via Polqo /internal/fcm/tokens endpoint

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} ke firebase-service Kesles 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​

RisikoLikelihoodImpactMitigasi
Polqo Firebase project tidak bisa deliver ke device KeslesRendahTinggiShadow mode wajib sebelum cutover
Token backfill tidak lengkap — user lama tidak dapat pushMenengahTinggiVerifikasi sample sebelum P2
Polqo tidak punya callback untuk token invalidasiMenengahMenengahImplement sebelum P3, atau manual sync
Latency tambahan dari hop ke PolqoRendahRendahSLA Polqo < 200ms; test di staging
Polqo rate limit memotong delivery saat volume tinggiRendahTinggiKonfirmasi rate limit sebelum P2
Firebase Kesles credential di-revoke sebelum waktunyaRendahTinggiP4 cleanup hanya setelah 2 minggu stabil

9. Koordinasi dengan Tim Polqo​

Item yang perlu dikonfirmasi / dikerjakan bersama tim Polqo:

  • Polqo menyediakan tenant_id=kesles dan API key untuk firebase-service Kesles
  • Polqo konfirmasi endpoint schema: /api/fcm/send dengan tenant_id header 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​

PhaseDurasiCatatan
Extraction plan selesai (prasyarat)Selesai terlebih dahulu
P0 — Token backfill1 hari
P1 — Shadow mode3–5 hariMinimal 48 jam observasi
P2 — Gradual cutover3–5 hariPer event type
P3 — Full cutover1 hari
P4 — Cleanup1 hari2 minggu setelah P3
Total~2–3 mingguTergantung kesiapan Polqo

12. Dokumen Terkait​