Lewati ke konten utama

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-bulkWajib — 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=keslesWajib — need coordination
Shadow mode selesai (lihat shadow-mode-plan.md)Sangat dianjurkan
Polqo bisa verifikasi X-Tenant-ID + X-Internal-API-Key di setiap requestWajib
Backfill push token dari db_kesles_merchant ke Polqo DB selesaiWajib 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