Files
halobestie-clone/TECH_DEBT.md
ramadhan sjamsani 1908e98012 Phase 4 Stage 10 Maestro: 09_chat_tab.yaml + seed-pending-payment endpoint
Closes the Stage 10 acceptance criterion §10.11 #13 (Maestro coverage).

- New dev-only `POST /internal/_test/seed-pending-payment` — inserts a
  payment_sessions row in `pending` status with expires_at 20m out, so
  the Pembayaran sub-tab has a deterministic row to render. Body
  accepts { phone, isExtension?, amount?, durationMinutes?, mode? }.
  Gated on NODE_ENV != 'production' like the other test routes.

- New Maestro helper script `seed_pending_payment.js` mirrors the
  existing seed_history_session pattern.

- New flow `09_chat_tab.yaml`:
    cold-start onboarding → home (returning view) →
    seed completed session + seed pending payment →
    tap "💬 chat" bottom-nav → lands on /chat/aktif via redirect →
    assert "aktif" / "pembayaran" / "selesai" pills + empty-state copy →
    tap pembayaran → assert "menunggu pembayaran sesi" + "bayar Rp..." →
    tap selesai → assert "X menit" duration row → tap row → assert
    "Transkrip Chat" appbar → back → still on /chat/selesai.

  Maestro parsed the YAML cleanly and started executing against the
  device; full run requires backend + online mitra in dev DB (same
  pre-reqs as flows 03/05/06/08).

- TECH_DEBT entry: Stage 10 retired the standalone bestie-history list
  screen, which means (a) the "curhat lagi" targeted-payment entry
  point has no UI affordance anywhere in the app — its plumbing in
  payment_notifier / payment_screen is now orphaned, and (b) the
  Stage 8 flow `08_returning_targeted.yaml` will fail at
  `assertVisible: "Riwayat Chat"` because it expects the deleted
  screen. Three fix paths listed in the entry for product to pick.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 20:24:50 +08:00

6.2 KiB

Tech Debt

Running list of known shortcuts, deferred hardening, and "good enough for now" decisions that need follow-up before they bite us in production.

Format: [date] short title, then enough context for someone (or future-you) to act on it without re-deriving the discussion.


Backend

[2026-05-11] Public GET /api/public/bestie/available needs rate limiting before prod

File: backend/src/routes/public/public.bestie-availability.routes.js

Decision: The endpoint was made unauthenticated by business requirement — SHome1st renders before any JWT exists, and the CTA must reflect global mitra availability so users see whether bestie is online before committing to onboarding. Response is intentionally a single boolean (no count, no IDs).

Why it's debt: No auth + no rate limit. The 10s in-memory cache bounds DB load, but a single attacker can still hammer the endpoint to:

  • run sustained traffic against the public listener (DoS surface)
  • scrape available over time to infer mitra online/offline patterns (weak information leak — only "is anyone online", but still a signal)

Mitigation before prod:

  • Per-IP rate limit (suggested: ~30 req/min/IP, headroom over the legitimate 5s client poll cadence = 12 req/min/IP).
  • Implement via @fastify/rate-limit plugin so other public endpoints can share the policy as we add them under /api/public/*.
  • Verify Cloud Run / NLB preserves real client IP and that request.ip reflects it (Fastify already has trustProxy: true).

Not required: auth, captcha, or removing the count from /api/client/mitra-availability (that route stays authed for CC/debug).


Client app

[2026-05-11] Social-login (Google / Apple) has no entry point after S3a rewrite

Files: client_app/lib/features/auth/screens/register_screen.dart (no longer renders them); client_app/lib/core/auth/auth_providers_provider.dart (still wired).

Decision: RegisterScreen was rewritten to match Figma S3Phone 1:1 (step-dots + name greeting + privacy card + tanpa-verif ghost link). Figma S3a shows no Google/Apple buttons, so they were removed from this screen.

Why it's debt: Google/Apple buttons used to render here when the authProvidersProvider flags were enabled. Today both flags are false (creds pending — see Phase 3.4 Status memory), so nothing visible is missing. But the moment /api/shared/auth-providers flips either flag, the buttons have nowhere to live.

Fix-when-creds-arrive:

  • Decide where Google/Apple buttons belong (likely a dedicated login screen reachable from the SHome1st "masuk →" banner), or whether to bring them back to S3a as Figma-friendly tiles above the phone input.
  • loginGoogle / loginApple on authProvider are still intact, so the wiring is one button widget away.

[2026-05-12] Stage 10 — "curhat lagi" entry point lost; Stage 8 Maestro flow broken

Files: client_app/lib/features/home/widgets/bestie_choice_sheet.dart (line ~54, now routes to /chat); client_app/.maestro/flows/08_returning_targeted.yaml (asserts "Riwayat Chat" + "curhat lagi" which no longer render).

Decision: Stage 10 retired chat_history_screen.dart and re-pointed the BestieChoiceSheet "bestie yang udah kenal" CTA at /chat (which redirects to /chat/aktif). The Selesai sub-tab matches Figma SChatList — transcript-only, no per-row "curhat lagi" button.

Why it's debt: The "curhat lagi" targeted-payment entry point lived only on the deleted history screen (line 213 label: 'curhat lagi'context.push('/payment', extra: { 'targetedMitraId': ... })). After Stage 10 there is no UI affordance to start a targeted payment against a known mitra from the customer app — only the general "Mulai Curhat → blast" path. The targeted-payment plumbing in payment_notifier.dart / payment_screen.dart is now orphaned (still wired, no caller).

Side-effect: 08_returning_targeted.yaml (Stage 8) expects to navigate from BestieChoiceSheet → bestie-history list → "curhat lagi" tap → targeted payment. The middle screen is gone; the flow will fail at assertVisible: "Riwayat Chat".

Fix options (pick one with product):

  • A. Add a "curhat lagi" secondary CTA on Selesai rows (deviates from Figma SChatList but restores the feature). Update 08_returning_targeted.yaml to navigate /chat/selesai → tap row's curhat-lagi → targeted payment.
  • B. Keep Selesai as transcript-only per Figma; reintroduce a "pick a past bestie" picker reachable from BestieChoiceSheet (essentially restore chat_history_screen.dart under a new name + route, kept separate from the Chat tab).
  • C. Drop the "curhat lagi" feature entirely. Update mermaid + BestieChoiceSheet copy to remove the "bestie yang udah kenal" branch. Delete orphaned targeted-payment plumbing.

Until decided, 08_returning_targeted.yaml should be marked .skip or the Stage 8 flow rewritten against the new home → SHomeReturning history list (which DOES still render bestie rows via bestieHistoryProvider, but those rows tap-through to transcripts only — same "no curhat lagi" gap).

[2026-05-12] S5 ESP screen retired from spec — code still ships it

Files: client_app/lib/features/onboarding/ (S5ESP screen + nav wiring); screens/onboarding.jsx::S5ESP (Figma reference still in handoff); any espSelectionProvider / espSkippedProvider Riverpod state.

Decision: Business removed the ESP multi-select step from the customer flow on 2026-05-12. Both verified and anonymous branches now go from VerifChoiceSheet straight to the usp_seen? gate. See requirement/flow_customer.mermaid.md §2.

Why it's debt: Stage 2 (commit 2645bcd) shipped the ESP screen and its state providers. The screen is still reachable in the current build. The mermaid spec is the source of truth — the code has drifted behind by one business decision.

Fix:

  • Delete the ESP screen widget and its route registration.
  • Remove espSelectionProvider / espSkippedProvider and any nav step that routes through ESP.
  • Wire VerifChoiceSheet → USPGate → (USP screen | skip → next) directly.
  • Drop the "ESP is decorative only" memory (it's now superseded by removal).
  • Keep screens/onboarding.jsx::S5ESP in the Figma handoff folder — it's history, not active design.