Phase 3.7: paid pairing flow + returning chat + extension flip
- Backend: payment_sessions + pairing_failures tables; payment.service.js and pairing-failure.service.js (new); rewritten pairing.service.js (payment-gated blast + targeted "Curhat lagi" + cancel + fallback); rewritten extension.service.js (data-driven auto-approve with offline safeguard, charge-at-approval); pricing.service.js (extension tiers without free trial); mitra-status.service.js (countAvailableMitras cached path); 60s sweeper for stale payment sessions - Backend routes: client.payment.routes, client.mitra-availability.routes, internal/failed-pairings.routes; client.chat.routes rewritten for payment-gated start + /returning + /cancel + /fallback-to-blast; internal/config.routes adds 4 new keys with Valkey invalidate publish - client_app: mitra-availability poll, payment screen + notifier, pairing notifier rewrite (PairingTargetedWaiting + PairingFailed states), targeted-waiting overlay + bestie-unavailable dialog, "Curhat lagi" CTA, failed-pairing terminal, extension via payment-session - mitra_app: PairingRequestType enum, returning-chat 20s countdown auto-dismiss, extension card "otomatis disetujui" copy - control_center: 4 new config rows in Settings, Failed Pairings page (filter + paginate + action menu), sidebar + route registered - Test infrastructure: Vitest backend (7/7 pass), Playwright CC (4/4 pass), Maestro mobile scaffold (CLI install pending) - Bugs found via Playwright + fixed: LoginPage labels not associated with inputs (a11y); backend internal CORS missing PATCH/PUT/DELETE in allow-methods (silent settings breakage in browsers since Stage 4) - Docs: phase3.7.md PRD, phase3.7-plan.md, phase3.7-questions.md (Q&A), phase3.7-testing.md (E2E checklist), phase3.7-test-run-2026-05-03.md (today's run results) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
124
requirement/phase3.7-questions.md
Normal file
124
requirement/phase3.7-questions.md
Normal file
@@ -0,0 +1,124 @@
|
||||
---
|
||||
status: ANSWERED — ready for PRD (phase3.7.md)
|
||||
captured: 2026-05-02
|
||||
answered: 2026-05-03
|
||||
---
|
||||
|
||||
# Phase 3.7 — Clarifying Questions (Answered)
|
||||
|
||||
Raw asks from user (2026-05-02 chat):
|
||||
|
||||
1. CTA Curhat on customer home is gated by mitra availability — pulled every 5 seconds.
|
||||
2. New session flow: **CTA → payment screen → payment confirmed → blast → mitra accept (idempotent) → chat starts**. (Today: blast happens immediately on CTA, no payment in path.)
|
||||
3. Customer can start a new session with the **same** mitra via a CTA on chat history.
|
||||
4. Returning-chat (same-mitra) requests need mitra approval. **20-second** window, **auto-reject** on timeout. Timeout configurable via control center.
|
||||
5. Session extension still requires approval, but **10-second** window with **auto-approve** on timeout (flip from today's auto-reject). Configurable via control center.
|
||||
|
||||
---
|
||||
|
||||
## Phase numbering — DECIDED
|
||||
|
||||
- Called **Phase 3.7** (next free after 3.6). Originally drafted as "Phase 4" but user prefers to keep 3.x numbering for this scope.
|
||||
|
||||
---
|
||||
|
||||
## Section 1 — CTA gated by mitra availability (5s poll)
|
||||
|
||||
| # | Q | Answer |
|
||||
|---|---|---|
|
||||
| 1.1 | Signal definition | **(b)** at least 1 mitra online **AND below max-customer capacity** |
|
||||
| 1.2 | Endpoint shape | New lightweight `GET /api/client/mitra-availability` → `{ available: bool, count?: number }`. **Backend reads from Valkey only — must not hit Postgres on every poll.** Count optional in payload (CC debugging), client only reads `available` |
|
||||
| 1.3 | Polling lifecycle | Foreground only. Pause on background, resume on foreground |
|
||||
| 1.4 | Disabled-state UX | **(a)** Greyed CTA with subtitle "Belum ada bestie tersedia" |
|
||||
| 1.5 | Visible count | Binary only — no number shown to user |
|
||||
| 1.6 | Stale data on poll fail | **(b)** Default to disabled |
|
||||
|
||||
---
|
||||
|
||||
## Section 2 — New flow: CTA → Payment → Blast → Accept → Chat
|
||||
|
||||
### 2a. Payment screen
|
||||
|
||||
| # | Q | Answer |
|
||||
|---|---|---|
|
||||
| 2a.1 | Integration depth | **Mocked** — no real Xendit in 3.7. Real Xendit deferred to a later phase |
|
||||
| 2a.2 | Pricing source | Keep existing Phase 3 mock pricing. Real pricing/tiers later (saved to memory) |
|
||||
| 2a.3 | Free trial UX | **(b)** "Gratis" Rp 0 confirmation step on the same payment screen — does not skip to blast |
|
||||
| 2a.4 | Abandonment | **(b)** Persist a "pending payment" / "abandoned" row; auto-expire after configurable timeout |
|
||||
| 2a.5 | Payment timeout | **20 minutes default**, **CC-configurable** (`payment_session_timeout_minutes`) |
|
||||
|
||||
### 2b. Blast → Accept
|
||||
|
||||
| # | Q | Answer |
|
||||
|---|---|---|
|
||||
| 2b.1 | Customer screen during blast | Reuse existing "Searching for bestie..." screen. Real design later via Claude design |
|
||||
| 2b.2 | Blast timeout | Same as Phase 2; verify it is CC-configurable, otherwise add `pairing_blast_timeout_seconds` |
|
||||
| 2b.3 | No mitra accepts within window | **Persist payment + log failed-pairing event with a tag** (e.g. `no_mitra_available`, `all_mitras_rejected`, `targeted_mitra_offline`, `targeted_mitra_rejected`, `targeted_mitra_timeout`, `payment_session_expired`, `customer_cancelled`). Surface to **Control Center for manual review/refund decision**. Customer-facing: hard-fail message for now (CTA copy will be revised later) |
|
||||
| 2b.4 | All mitras explicitly reject | Same as 2b.3 — different tag value |
|
||||
| 2b.5 | Idempotency on accept | Confirmed — keep Phase 2's DB-level uniqueness on session acceptance |
|
||||
|
||||
### 2c. Migration
|
||||
|
||||
| # | Q | Answer |
|
||||
|---|---|---|
|
||||
| 2c.1 | Replacement strategy | **Replace entirely** — delete the old instant-blast path. No feature flag |
|
||||
| 2c.2 | Existing screens | Reuse where possible; replace only when reuse is impractical |
|
||||
|
||||
---
|
||||
|
||||
## Section 3 — "Curhat lagi" with the same mitra (from chat history)
|
||||
|
||||
| # | Q | Answer |
|
||||
|---|---|---|
|
||||
| 3.1 | Per row or per partner | **(a)** CTA on every chat history row (simpler) |
|
||||
| 3.2 | Payment first | Yes — same payment screen as regular curhat |
|
||||
| 3.3 | Mitra offline at tap | **(a) but with popup** — show "Bestie sedang tidak online" popup. Offer "Chat dengan bestie lain" if any other mitra is available; otherwise just show the offline message |
|
||||
| 3.4 | Mitra at capacity | Same as 3.3 |
|
||||
| 3.5 | On rejection / 20s auto-reject | Same as 3.3. **Important:** payment is already taken by this point — **the same payment carries over to the general blast fallback (no double-charge)**. If fallback also fails, treat as 2b.3 (logged + CC review with appropriate tag) |
|
||||
| 3.6 | Bypass general gating | **Independent** — depends only on the targeted mitra's status, not the section 1 availability poll |
|
||||
| 3.7 | Anonymity | Unchanged (mitra always sees customer call_name) |
|
||||
|
||||
---
|
||||
|
||||
## Section 4 — Returning-chat approval window (20s, auto-reject)
|
||||
|
||||
| # | Q | Answer |
|
||||
|---|---|---|
|
||||
| 4.1 | Mitra UX | Reuse existing incoming-request notification component (FCM + foreground card), add visible 20s countdown |
|
||||
| 4.2 | Customer UX during 20s | **(a)** Overlay "Menunggu konfirmasi bestie..." with cancel button |
|
||||
| 4.3 | Auto-reject downstream | Same as 3.5 (popup → offer general blast fallback or fail; payment carries over) |
|
||||
| 4.4 | Mitra offline at request time | **(a)** Auto-reject immediately, do not wait 20s |
|
||||
| 4.5 | Control center config | New config row: `returning_chat_confirmation_timeout_seconds` (default 20). **Use a clear label and explanation in the CC UI** |
|
||||
| 4.6 | Concurrency (mitra mid-session with someone else) | **(c)** Send the card and let mitra decide |
|
||||
|
||||
---
|
||||
|
||||
## Section 5 — Extension approval flip (10s, **auto-approve**)
|
||||
|
||||
| # | Q | Answer |
|
||||
|---|---|---|
|
||||
| 5.1 | Behavioral flip — confirm | **Confirmed intentional** — flip from auto-reject → auto-approve |
|
||||
| 5.2 | Default value & config | **(c)** Keep existing extension-timeout row; add new `extension_default_action_on_timeout` enum (`auto_reject` \| `auto_approve`), default `auto_approve` |
|
||||
| 5.3 | Customer overlay during 10s | Same overlay as today, just shorter timer |
|
||||
| 5.4 | Charge timing for extension | **(b)** Charge at approval moment (auto-approve fires charge; explicit reject within 10s = no charge). **Important:** extension is NOT auto-charged — customer chooses time + price first (same UX as initial chat request, **without trial**) |
|
||||
| 5.5 | Mitra UX | Same extension card; copy adjusted to reflect auto-approve |
|
||||
| 5.6 | Mitra disconnected/offline during 10s | **(b)** Treat as auto-reject (safer for customer). **Domain rule (saved to memory): mitra can flip to offline mid-session — never use "in-session" as proxy for "online"** |
|
||||
|
||||
---
|
||||
|
||||
## Cross-cutting
|
||||
|
||||
| # | Q | Answer |
|
||||
|---|---|---|
|
||||
| X.1 | Refund / failed-pairing model | Single consistent model across 2b.3 / 3.5 / 4.3: payment row persists, event logged with **tag** (cause) for filtering/audit, surfaced to CC for manual review |
|
||||
| X.2 | Old instant-blast code | **Delete entirely**, no kill-switch, no feature flag |
|
||||
| X.3 | Free trial | Same payment screen UI, Rp 0 / "Gratis", with duration/tier picker shown |
|
||||
| X.4 | Anonymity | Unchanged |
|
||||
| X.5 | New CC configs | `pairing_blast_timeout_seconds` (only if not already), `payment_session_timeout_minutes` (default 20), `returning_chat_confirmation_timeout_seconds` (default 20), `extension_default_action_on_timeout` enum (default `auto_approve`) — no others |
|
||||
| X.6 | Phase numbering | **Phase 3.7** |
|
||||
|
||||
---
|
||||
|
||||
## Next step
|
||||
|
||||
PRD `phase3.7.md`, then `phase3.7-plan.md`, then code.
|
||||
Reference in New Issue
Block a user