Phase 3.3: topic sensitivity + Phase 3.4: auth foundation
Phase 3.3 — Session Topic Sensitivity (complete): - Backend: topic_sensitivity column + session_sensitivity_log, sensitivity service (flip with one-way-latch + audit), PATCH /api/shared/chat/sessions/:id/topic, topic carried in pairing + extension WS payloads, CC filter + sensitive stats + per-mitra sensitive columns on activity page - client_app: TopicSelectionBottomSheet before pricing, topic flows through pairing request, silent WS handler for session_topic_updated - mitra_app: SensitivityBadge + SensitivityTheme + sensitivityConfigProvider, overlay badge + yellow accent, chat screen app-bar toggle with configurable confirmation + latch, extension card shows current flag, history + transcript yellow theme - control_center: Sensitivitas Topik settings section, topic filter + column with inline audit log, sensitive stats dashboard card, mitra activity sensitive columns with QC flag Phase 3.4 — Self-Managed Auth (foundation only): - Migration: auth_sessions + otp_requests tables, social identity columns on customers, password_hash + lockout on control_center_users, OTP + CC lockout app_config keys - New services: password (bcrypt + complexity), token (JWT HS256 + refresh rotation, session_id claim pre-wires future Valkey revocation), social-identity (Google + Apple JWKS), OTP (Fazpass stub — real API TBD) - Constants: AuthProvider + OtpChannel - Middleware, auth route rewrites, WS auth update, Firebase → FCM isolation still pending (next chunk); Fazpass docs + Apple Developer setup still required before E2E testing Docs: - requirement/phase3.3.md, phase3.3-plan.md, phase3.3-testing.md - requirement/phase3.4.md, phase3.4-plan.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
216
requirement/phase3.3.md
Normal file
216
requirement/phase3.3.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# PRD: Session Topic Sensitivity
|
||||
|
||||
# Overview
|
||||
|
||||
**Goal:** Let customers flag a chat session as containing sensitive topics (sexuality, pornography, substance use) so mitras can prepare themselves, and give mitras the ability to re-flag the session mid-chat when the topic drifts.
|
||||
|
||||
**Success looks like:** Every new chat request carries an explicit topic flag (regular or sensitive), the mitra sees the flag on the incoming request and during the chat, mitras can decline on the spot based on the flag, and mitras can change the flag mid-session with an audit trail.
|
||||
|
||||
**Affects:** `client_app`, `mitra_app`, `backend`, `control_center`
|
||||
|
||||
## Background
|
||||
|
||||
- Current chat flow has no way for customers to warn mitras about sensitive topics (seksualitas, pornografi, penggunaan zat) before the session starts.
|
||||
- Mitras cannot prepare themselves or opt out based on topic sensitivity, which can lead to mid-session discomfort or early terminations.
|
||||
- Topics may also drift during a session; there is currently no way for the mitra to re-classify the session.
|
||||
|
||||
---
|
||||
|
||||
# Functional Requirement
|
||||
|
||||
## 1. Customer: Topic Selection Before Pricing
|
||||
|
||||
### Trigger
|
||||
- Customer taps **"Mulai Curhat"** on the home screen.
|
||||
- Before the pricing screen is shown, a bottom sheet appears asking the customer to classify their topic.
|
||||
|
||||
### Appearance
|
||||
- Bottom sheet, rounded top corners, consistent with existing app theme (pink doodle background).
|
||||
- Cannot be dismissed by tapping outside or swiping down — selection is **required** before the pricing screen is shown.
|
||||
- Back button (or system back) cancels the entire "Mulai Curhat" flow.
|
||||
|
||||
### Copy (Indonesian, non-judgmental)
|
||||
|
||||
- **Title:** Sebelum kita mulai
|
||||
- **Body:** Supaya kami bisa menyiapkan bestie yang tepat untukmu, boleh kami tahu sedikit tentang ceritamu? Tidak ada penilaian di sini — kamu aman bercerita apa pun.
|
||||
- **Sub-question:** Apakah ceritamu menyentuh topik seperti seksualitas, pornografi, atau penggunaan zat?
|
||||
- **Button A (primary):** Topik umum
|
||||
- **Button B (secondary, equal weight):** Topik sensitif
|
||||
- **Helper line below buttons:** Pilihan ini hanya membantu bestie menyiapkan diri. Kamu tetap bisa bercerita apa adanya.
|
||||
|
||||
### Behavior
|
||||
- Tapping either button stores the choice locally and proceeds to the existing pricing screen.
|
||||
- Customer **cannot change** the flag after this selection — it is locked for the duration of the session.
|
||||
- Flag is sent to the backend when the chat request is created (part of the pairing request payload).
|
||||
|
||||
---
|
||||
|
||||
## 2. Mitra: Sensitive Flag on Incoming Chat Request
|
||||
|
||||
### Appearance on Overlay
|
||||
- Incoming chat request overlay (from Phase 3.2) shows a **label** and **color accent** when the request is flagged sensitive.
|
||||
- Label: **"Topik sensitif"** (small badge, placed near the session metadata).
|
||||
- Color accent: warning-sign yellow (see Section 5 for exact color treatment).
|
||||
- Regular requests remain as today — no badge, no color change.
|
||||
|
||||
### Behavior
|
||||
- Mitra may accept or decline as today. No new dedicated "decline because sensitive" flow — the existing reject/ignore paths are sufficient.
|
||||
- No per-mitra opt-in setting (e.g., "I accept sensitive topics") in this phase.
|
||||
|
||||
### Push Notification
|
||||
- Push notification content (title/body) stays generic for now — the sensitivity label is surfaced only in the overlay.
|
||||
|
||||
---
|
||||
|
||||
## 3. Mitra: Chat Screen Background Color
|
||||
|
||||
### Sensitive Sessions
|
||||
- Chat screen background switches from pink doodle to **warning-yellow doodle** (same pattern, different base color).
|
||||
- A small persistent header or banner shows **"Topik sensitif"** label so the context is always visible.
|
||||
|
||||
### Regular Sessions
|
||||
- No change — pink doodle as today.
|
||||
|
||||
### Customer Side
|
||||
- Customer's chat screen **always** shows pink doodle, regardless of flag.
|
||||
- Customer is never given a color cue about topic sensitivity, even if the mitra later flips the flag.
|
||||
|
||||
---
|
||||
|
||||
## 4. Mitra: Flip Flag Mid-Session
|
||||
|
||||
### Control
|
||||
- Toggle icon in the mitra's chat screen app bar.
|
||||
- Tapping it flips the session flag (regular ↔ sensitive).
|
||||
|
||||
### Confirmation Dialog
|
||||
- By default, flipping shows a confirmation dialog:
|
||||
- **regular → sensitive:** "Tandai sesi ini sebagai sensitif?" — [Batal] [Tandai]
|
||||
- **sensitive → regular:** "Tandai sesi ini sebagai topik umum?" — [Batal] [Tandai]
|
||||
- The confirmation can be disabled via `app_config` key `sensitive_flip_confirmation_enabled` (default `true`). When disabled, the flip happens instantly and a toast appears ("Sesi ditandai sensitif" / "Sesi ditandai topik umum").
|
||||
|
||||
### One-Way Latch (Configurable)
|
||||
- By default, mitra can flip back and forth (regular ↔ sensitive).
|
||||
- A `app_config` key `sensitive_flag_one_way_latch` (default `false`) toggles to one-way mode: once sensitive, cannot revert to regular.
|
||||
- When latch is active and the session is already sensitive, the toggle icon is disabled (with a tooltip explaining why).
|
||||
|
||||
### Persistence
|
||||
- The flip updates `sessions.topic_sensitivity` immediately (backend-authoritative).
|
||||
- Every flip is recorded in `session_sensitivity_log` (see Section 7).
|
||||
|
||||
### WebSocket Event
|
||||
- Mitra's flip triggers a WS event to the customer (for future-proofing / analytics), but the customer's client **silently ignores it** — no UI change.
|
||||
- Multi-device mitra sync is not required in this phase (mitra app doesn't yet support concurrent multi-device sessions).
|
||||
|
||||
---
|
||||
|
||||
## 5. Visual Treatment
|
||||
|
||||
### Color Palette
|
||||
- **Pink** (existing): current doodle theme, used for regular sessions on both sides and for customer side always.
|
||||
- **Yellow**: warning-sign yellow, using the same doodle pattern as pink. Exact hex TBD during implementation — should read clearly as "attention / caution" without feeling alarming.
|
||||
|
||||
### Badge / Label
|
||||
- **"Topik sensitif"** pill-style badge, pink-text-on-yellow or dark-text-on-yellow for contrast.
|
||||
- Used on:
|
||||
- Incoming chat request overlay (mitra)
|
||||
- Chat screen header (mitra)
|
||||
- Extension request card (mitra)
|
||||
- Mitra chat history list row
|
||||
- Mitra transcript / history detail
|
||||
|
||||
### Customer Side
|
||||
- No yellow, no badge, no label — ever.
|
||||
|
||||
---
|
||||
|
||||
## 6. Extension Flow
|
||||
|
||||
### Mitra's Extension Request Card
|
||||
- When a customer requests extension, the mitra's extension UI shows the **current** session flag (i.e., whatever the flag is at the time the extension request arrives, including any mid-session mitra flip).
|
||||
- Treatment: same as incoming chat request — yellow color accent + "Topik sensitif" badge when applicable.
|
||||
|
||||
### On Extension Acceptance
|
||||
- The flag **carries over** to the extended session unchanged.
|
||||
- Customer is not re-asked about topic sensitivity on extension.
|
||||
|
||||
---
|
||||
|
||||
## 7. Audit Trail
|
||||
|
||||
### Table: `session_sensitivity_log`
|
||||
- `id` — PK
|
||||
- `session_id` — FK → sessions
|
||||
- `changed_by_mitra_id` — FK → mitras
|
||||
- `from_value` — `regular` | `sensitive`
|
||||
- `to_value` — `regular` | `sensitive`
|
||||
- `created_at` — timestamp
|
||||
|
||||
### When Logged
|
||||
- Every mitra flip (both directions).
|
||||
- Customer's initial selection is NOT logged here — it is the initial value of `sessions.topic_sensitivity`.
|
||||
|
||||
---
|
||||
|
||||
## 8. Mitra Chat History
|
||||
|
||||
### List Rows
|
||||
- Each past session row shows a small **"Topik sensitif"** badge if the session was flagged sensitive at any point.
|
||||
- Regular sessions have no badge.
|
||||
|
||||
### Transcript Detail
|
||||
- Sensitive sessions show the yellow doodle background in the transcript view.
|
||||
- Regular sessions show pink.
|
||||
|
||||
### Customer Side
|
||||
- Customer's history and transcript views are unchanged — no badge, no color change, ever.
|
||||
|
||||
---
|
||||
|
||||
## 9. Control Center
|
||||
|
||||
### Dashboard: Sensitive vs Regular Stats
|
||||
- New panel on the existing dashboard or session-management page: count and percentage of sensitive sessions over a date range.
|
||||
- Optionally: per-mitra breakdown (future nice-to-have — not blocking for this phase).
|
||||
|
||||
### Session Management Filter
|
||||
- Add a filter / sort on the session management page by `topic_sensitivity` (all / regular / sensitive).
|
||||
|
||||
### Config
|
||||
- Expose two new `app_config` keys on the existing config page:
|
||||
- `sensitive_flip_confirmation_enabled` (bool, default `true`) — whether mitra sees a confirmation dialog when flipping the flag.
|
||||
- `sensitive_flag_one_way_latch` (bool, default `false`) — whether mitra can only flip regular → sensitive (no flip back).
|
||||
|
||||
---
|
||||
|
||||
## 10. Out of Scope for Phase 3.3
|
||||
|
||||
- **Pricing differentiation** based on topic sensitivity. For now, the flag does not affect pricing. Schema should leave room for this in the future.
|
||||
- **Per-mitra opt-in** setting ("I accept sensitive topics"). Mitras decline on the spot via existing reject/ignore paths.
|
||||
- **Auto-moderation or keyword detection** — flag is self-reported by customer / mitra only.
|
||||
- **FCM push notification content** reflecting sensitivity — generic push only; label is in-app overlay only.
|
||||
- **Multi-device mitra sync** of flag flips.
|
||||
- **Customer-side visual cues** about topic sensitivity.
|
||||
|
||||
---
|
||||
|
||||
# Data Model Summary
|
||||
|
||||
### New columns
|
||||
- `sessions.topic_sensitivity` — enum `regular | sensitive`, NOT NULL, default `regular`.
|
||||
- `chat_requests.topic_sensitivity` — enum `regular | sensitive`, NOT NULL, default `regular` (mirrored for pre-acceptance visibility).
|
||||
|
||||
### New table
|
||||
- `session_sensitivity_log` (see Section 7).
|
||||
|
||||
### New `app_config` keys
|
||||
- `sensitive_flip_confirmation_enabled` (bool, default `true`)
|
||||
- `sensitive_flag_one_way_latch` (bool, default `false`)
|
||||
|
||||
---
|
||||
|
||||
# Tech Stack
|
||||
- Flutter for client_app / mitra_app (existing Riverpod state management)
|
||||
- Fastify backend (existing WebSocket plugin + pairing/extension services)
|
||||
- PostgreSQL migration for new columns + table
|
||||
- Control center: React + Vite (existing pages extended)
|
||||
Reference in New Issue
Block a user