Customer-driven session end flow:
- AppBar 'akhiri' action on chat_screen (visible when connected and
not already closing).
- Tap fires confirm_end_step1 HaloPopup. lanjut akhiri -> step2;
gak jadi balik -> dismiss, stay in chat.
- confirm_end_step2 HaloPopup. tulis pesan penutup -> closing_message_sheet
HaloBottomSheet (textarea + kirim & akhiri / lewat — langsung akhiri).
lewati saja closes immediately.
- Both close paths POST /api/client/session/:sessionId/end via
session_closure_notifier.closeSession() and route to /chat/thank-you.
- 409 from the close endpoint surfaces a ClosureRejectedByMitraData
state and a stub HaloPopup with TODO(stage8) for the BestieOfflinePopup
returning variant.
Removed the legacy _showSessionExpiredDialog modal — Stage 6's
ChatExpiredBanner is the replacement notification.
Inline _buildGoodbyeView retained with a TODO for the mitra-side early
end flow (still reaches it).
endSessionTwoStepConfirmProvider hardcoded to true with a TODO — the
Stage 1.5 app_config row exists but no client-readable config endpoint
exists yet. Flip the provider to a FutureProvider once the read endpoint
ships.
Maestro 07_end_session_2step.yaml chains after the chat-happy flow
and asserts the Indonesian copy at each step.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add phase3.1 requirement and implementation plan docs
- Add Riverpod dependencies to both client_app and mitra_app
- Wrap both app roots with ProviderScope
- Migrate client_app AuthBloc → AuthNotifier (@riverpod annotation)
- Migrate client_app ChatOpeningBloc → chatPricingProvider (FutureProvider)
- Update router to use Riverpod-based auth state for redirects
- Update all auth screens (display name, register, OTP, force register)
- Update home screen and pricing bottom sheet
- Add android:usesCleartextTraffic for dev HTTP access on both apps
- mitra_app prepared with ProviderScope + ApiClient provider (blocs next)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Upgrade Fastify 4→5 with all plugins (@fastify/websocket 11, cors 11, sensible 6)
- Migrate all SSE endpoints to WebSocket + FCM push (mitra chat requests, customer pairing status)
- Add flutter_local_notifications for foreground push notifications with sound
- Add splash screen to both apps (hide auth loading flash)
- Introduce constants/enums across entire codebase (no raw string literals)
- Move price tiers from hardcoded array to app_config DB (data-driven, includes 1-min test tier)
- Add session ownership validation on all shared chat routes
- Add ownership checks on endSession, respondToExtension, requestExtension
- Fix session timer: auto-complete expired/stale sessions on server restart
- Add 5-min grace period for abandoned closing sessions
- Fix extension flow: proper session_resumed handling, clearExtensionRequest, closure grace timer cleanup
- Fix chat screens: ConnectChat in initState, session status check on connect
- Fix customer expired view: 5-min countdown, closure state priority over expired state
- Fix mitra extension UI: loading spinner, disable buttons, handle EXTENSION_RESOLVED error
- Fix GoRouter navigation consistency (no more Navigator.pushNamed)
- Fix goodbye view keyboard overflow (SingleChildScrollView)
- Add active session card on customer home screen with refresh on navigate back
- Fix PricingBottomSheet extension mode (RequestExtension instead of new pairing)
- Send session_resumed to both parties on extension accept
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>