# Phase 3.3 Testing & Outstanding Regression Checklist This is a **reminder document** — consolidated testing work for Phase 3.3 plus every outstanding test item carried over from earlier Phase 3 iterations. Tick boxes as you verify. --- ## Part 1 — Phase 3.3: Session Topic Sensitivity ### 1.1 Database / Migration - [ ] Migration runs cleanly on an existing dev DB (no errors, all `IF NOT EXISTS` / `ON CONFLICT` paths hit) - [ ] `chat_sessions.topic_sensitivity` column exists with default `'regular'` and NOT NULL - [ ] Existing sessions (created before the migration) have `topic_sensitivity = 'regular'` after migration - [ ] `session_sensitivity_log` table exists with correct FKs (sessions, mitras) - [ ] `idx_chat_sessions_topic_sensitivity` index created - [ ] `idx_session_sensitivity_log_session` index created - [ ] `app_config` has `sensitive_flip_confirmation_enabled = true` by default - [ ] `app_config` has `sensitive_flag_one_way_latch = false` by default ### 1.2 Customer Flow (client_app) **Topic selection bottom sheet** - [ ] Tap "Mulai Curhat" → topic selection bottom sheet appears - [ ] Sheet **cannot** be dismissed by tapping outside - [ ] Sheet **cannot** be dismissed by swiping down - [ ] System back button cancels entire "Mulai Curhat" flow (does NOT open pricing) - [ ] Copy matches PRD (title, body, sub-question, helper line) - [ ] "Topik umum" button styling is primary - [ ] "Topik sensitif" button styling is secondary but equal weight (not de-emphasized) **Request submission** - [ ] Tap "Topik umum" → pricing sheet opens with topic pre-selected as regular - [ ] Tap "Topik sensitif" → pricing sheet opens with topic pre-selected as sensitive - [ ] After pricing confirm → `POST /api/client/chat/request` body includes `topic_sensitivity: regular|sensitive` - [ ] Backend rejects request with missing `topic_sensitivity` (400 BAD_REQUEST) - [ ] Backend rejects request with invalid `topic_sensitivity` value (e.g., `"other"`) - [ ] Created `chat_sessions` row has correct `topic_sensitivity` value **Customer UI after request** - [ ] Chat screen stays pink (no yellow), regardless of flag - [ ] Customer history screen: no badge on any row regardless of flag - [ ] Customer transcript screen: stays pink - [ ] Customer receives `session_topic_updated` WS message after mitra flip → **no UI change**, no error, no crash ### 1.3 Mitra Flow — Incoming Request (mitra_app) - [ ] Regular request: overlay has no badge, no yellow accent - [ ] Sensitive request: overlay shows "Topik sensitif" badge + yellow accent - [ ] Overlay payload from WS includes `topic_sensitivity` - [ ] Overlay payload from FCM fallback includes `topic_sensitivity` (or app fetches on open) - [ ] Overlay payload from `getPendingRequestsForMitra` (app-resume path) includes `topic_sensitivity` - [ ] Mitra accepts sensitive request → lands in active chat screen with correct flag ### 1.4 Mitra Flow — Active Chat Screen - [ ] Sensitive active session: yellow doodle background - [ ] Regular active session: pink doodle (unchanged behavior) - [ ] Header banner shows "Topik sensitif" label only when sensitive - [ ] App-bar toggle icon visible (flag / flag_outlined depending on state) **Flip toggle — confirmation enabled (default)** - [ ] Tap toggle regular → sensitive → dialog appears: "Tandai sesi ini sebagai sensitif?" - [ ] "Batal" cancels, no state change, no audit log entry, no WS broadcast - [ ] "Tandai" flips, background turns yellow instantly, log entry created - [ ] Tap toggle sensitive → regular → dialog: "Tandai sesi ini sebagai topik umum?" **Flip toggle — confirmation disabled (via CC config)** - [ ] Toggle `sensitive_flip_confirmation_enabled` to `false` in CC - [ ] Flip happens immediately, toast "Sesi ditandai sensitif" / "Sesi ditandai topik umum" - [ ] No dialog appears **One-way latch — disabled (default)** - [ ] Can flip regular → sensitive → regular → sensitive freely **One-way latch — enabled (via CC config)** - [ ] Toggle `sensitive_flag_one_way_latch` to `true` in CC - [ ] Session that was regular: can flip to sensitive; toggle then disabled - [ ] Session that was already sensitive at latch-enable time: toggle disabled with tooltip - [ ] Attempt to flip sensitive → regular with latch on: API returns 409 `SENSITIVITY_LATCHED` - [ ] Error dialog shown: "Sesi sudah ditandai sensitif dan tidak bisa diubah kembali." **Audit trail** - [ ] Every successful flip creates a `session_sensitivity_log` row with correct `from_value`, `to_value`, `changed_by_mitra_id` - [ ] No-op flip (e.g., tap confirm but value didn't actually change) does NOT create a log row - [ ] Log entries ordered correctly (ascending `created_at`) ### 1.5 Mitra Flow — Extension - [ ] Customer requests extension on regular session → mitra extension card has no badge - [ ] Customer requests extension on sensitive session → mitra extension card shows "Topik sensitif" badge + yellow accent - [ ] Mitra flipped session mid-chat regular → sensitive, then customer requests extension → extension card reflects **current** sensitive flag - [ ] Extension accepted → flag carries over unchanged to extended session ### 1.6 Mitra Flow — History & Transcript - [ ] Mitra history list row shows "Topik sensitif" badge for sensitive sessions - [ ] Mitra history list row has no badge for regular sessions - [ ] Mitra transcript view: sensitive session → yellow doodle background - [ ] Mitra transcript view: regular session → pink doodle - [ ] Customer-side history and transcript: always pink, no badge ### 1.7 Mitra Flow — Edge Cases - [ ] Mitra tries to flip flag on a session they don't own → 403 FORBIDDEN - [ ] Mitra tries to flip flag on a `CLOSING` session → 409 SESSION_NOT_ACTIVE - [ ] Mitra tries to flip flag on a `COMPLETED` session → 409 SESSION_NOT_ACTIVE - [ ] Mitra tries to flip flag on an `EXPIRED` session → 409 SESSION_NOT_ACTIVE - [ ] Invalid `topic_sensitivity` value sent to PATCH endpoint → 400 BAD_REQUEST - [ ] Customer tries to call PATCH endpoint → 403 FORBIDDEN (only mitra allowed) ### 1.8 Control Center — Settings - [ ] Settings page has new "Sensitivitas Topik" section - [ ] `sensitive_flip_confirmation_enabled` checkbox reflects current backend value - [ ] `sensitive_flag_one_way_latch` checkbox reflects current backend value - [ ] PATCH `/internal/config/sensitivity` persists changes - [ ] Changes take effect immediately on next mitra flip (no app restart needed on mitra side, if mitra fetches config dynamically) ### 1.9 Control Center — Sessions Page - [ ] Sessions list has new filter dropdown (All / Umum / Sensitif) - [ ] Filter "Sensitif" returns only sessions with `topic_sensitivity = 'sensitive'` - [ ] Filter "Umum" returns only `regular` - [ ] Filter "All" returns everything (backward-compatible) - [ ] Filter works combined with existing status filter - [ ] Session list has new "Topik" column showing badge (green "Umum" / yellow "Sensitif") ### 1.10 Control Center — Session Detail - [ ] Session detail page shows current `topic_sensitivity` - [ ] Session detail shows sensitivity audit trail timeline: "Mitra {name} menandai topik sebagai {from→to} pada {timestamp}" - [ ] Timeline ordered ascending - [ ] Sessions with no flips show empty timeline (no error) ### 1.11 Control Center — Dashboard - [ ] Dashboard shows "Sesi Sensitif" card with total count + 30-day % breakdown - [ ] Percentage math correct (sensitive / total × 100, rounded to 1 decimal) - [ ] Edge case: 0 sessions in last 30 days → shows `0%` not `NaN` ### 1.12 Control Center — Mitra Activity - [ ] Summary table has new columns: Sensitive Total, Sensitive Accepted, Sensitive Rate (%) - [ ] Mitra with 0 sensitive requests shows `—` (not `0%`) - [ ] Sensitive rate computed correctly (sensitive_accepted / sensitive_total × 100) - [ ] Detail log table: optional new "Topik" column with badge - [ ] Date range filter still works with new columns ### 1.13 Control Center — Integration Regression - [ ] Existing settings (anonymity, free-trial, extension-timeout, early-end, mitra-ping, price-tiers) still work - [ ] Existing sessions filter (by status) still works - [ ] Existing dashboard cards still render --- ## Part 2 — Outstanding Items From Phase 3.2 Carried over from `project_phase3_testing_status.md` (2026-04-15): ### 2.1 Chat Request Overlay - [ ] **Multiple concurrent chat requests** — verify queue behavior (one shown at a time, next appears when current resolved) - [ ] Stale request: "cancelled by customer" message shown + requires acknowledge (no auto-dismiss) - [ ] Stale request: "accepted by other bestie" message shown + requires acknowledge - [ ] Stale request: "expired" message shown + requires acknowledge - [ ] Swipe-to-dismiss (ignore) does NOT send reject to backend - [ ] Ignored request eventually logs as `ignored` in `chat_request_notifications` after 60s timeout - [ ] Request `missed` (another mitra accepted first) logs correctly - [ ] `active_session_count` captured correctly at notification creation ### 2.2 End-to-End Flows - [ ] Full chat flow: pair → chat → extension → closure (customer + mitra) - [ ] Goodbye flow: session expires → closing → both submit goodbye → completed - [ ] Extension accepted mid-flow → session resumes, timer extends, no grace timer lingering - [ ] Extension rejected → session moves to closing, both see closure UI - [ ] Extension timeout (no mitra response) → closing ### 2.3 iOS Coverage (still partially untested) - [ ] OTP login on iOS (customer) - [ ] OTP login on iOS (mitra) - [ ] Push notifications on iOS (customer + mitra) - [ ] FCM token registration on iOS - [ ] Chat screen rendering on iOS - [ ] Back button behavior on iOS (deep-link pop fallback) - [ ] Overlay on iOS (from `project_phase3_testing_status`: iOS setup started but incomplete) - [ ] Splash screen on iOS - [ ] Onboarding carousel on iOS - [ ] Keyboard handling on iOS (chat input, goodbye form) --- ## Part 3 — Outstanding Items From Phase 3 / 3.1 ### 3.1 Session Lifecycle - [ ] Server restart mid-session: session timer is restored from DB (`restoreActiveTimers`) - [ ] Stale active sessions auto-complete on restart - [ ] Closing sessions with stale grace timers auto-complete on restart - [ ] Session expired from customer side (5-min countdown display) - [ ] Abandoned session during closure grace period → auto-completes - [ ] **Known limitation**: multi-instance backend sessions not supported until Valkey keyspace notifications implemented (out of scope, just confirm single-instance behavior) ### 3.2 Chat Mechanics - [ ] Message status transitions (sent → delivered → read) work correctly - [ ] Typing indicator shows/hides correctly on both sides - [ ] Messages received while backgrounded are marked `delivered` on foreground resume - [ ] Messages viewed are marked `read` and the read receipt propagates back to sender - [ ] Unread badge on home screen updates correctly (client_app + mitra_app) ### 3.3 Navigation / UI - [ ] All navigation uses `GoRouter.context.push/go` (no leftover `Navigator.pushNamed`) - [ ] Deep-linked screens work with `canPop` fallback + `PopScope` - [ ] `notification_service` uses `go` (not `push`) for terminal states - [ ] Splash screen hides auth loading flash on both apps - [ ] Goodbye views use `SingleChildScrollView` (no keyboard overflow) ### 3.4 Control Center Settings - [ ] Free trial config: toggle + duration edit - [ ] Extension timeout: edit seconds - [ ] Early end: toggle mitra / customer independently - [ ] Mitra ping: toggle require + interval - [ ] Price tiers: add / edit / remove tiers and verify client_app pricing sheet reflects changes --- ## Part 4 — Cross-Cutting / Pre-Release ### 4.1 Regression Checks (do after Phase 3.3 merge) - [ ] Existing customer auth flow still works (welcome → OTP → register → home) - [ ] Existing mitra auth flow still works - [ ] Existing control center login still works (admin@halobestie.com) - [ ] Pairing flow (mulai curhat → matched) still works end-to-end - [ ] All existing WS messages still processed (no regressions from new `session_topic_updated` handler) ### 4.2 Platform Coverage - [ ] Android: customer app on emulator (Medium_Phone_API_36.1) - [ ] Android: mitra app on physical device (SM-A530F, 52002a5db8e0c46b) - [ ] iOS: customer app (Mac + simulator / physical) - [ ] iOS: mitra app (Mac + simulator / physical) - [ ] Control center: Chrome latest - [ ] Control center: Firefox / Safari (if required) ### 4.3 Load / Concurrency (sanity) - [ ] 2 concurrent customers requesting chat at the same time — both find a mitra (or one waits) - [ ] 1 customer, 5 mitras online — blast notification reaches all 5 - [ ] Mitra accepts after another mitra already accepted → receives `missed` with `accepted_by_other` - [ ] Backend restart with active sessions → timers restored, no data loss ### 4.4 Config Flag Interactions - [ ] `sensitive_flag_one_way_latch = true` + existing sensitive session → toggle disabled - [ ] `sensitive_flip_confirmation_enabled = false` + rapid flips → no race, all logged in order - [ ] Both config flags toggled together → no conflict ### 4.5 Known Blockers / Deferred Not tests — tracked here so they don't get forgotten: - [ ] **Valkey keyspace notifications** — required for multi-instance session timers (noted in memory as future work) - [ ] **Mitra QC auto-flag** — auto-flagging high-rejection mitras on CC (future phase) - [ ] **Merge-on-link** for social login (currently reject-on-existing) - [ ] **Phase 3.4 auth migration** — separate phase, not blocking 3.3 testing