Phase 3.1 WIP: Riverpod migration (client_app Auth + ChatOpening)

- 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>
This commit is contained in:
2026-04-09 13:51:17 +08:00
parent b0502ac92b
commit d15b2f05fc
25 changed files with 2513 additions and 461 deletions

84
requirement/phase3.1.md Normal file
View File

@@ -0,0 +1,84 @@
# PRD: Phase 3 Stabilization & State Management Migration
# Overview
**Goal:** Stabilize Phase 3 (Chat Engine) through end-to-end testing and migrate Flutter state management from BLoC to Riverpod + flutter_hooks
**Success looks like:** All Phase 3 features are verified working end-to-end across client_app, mitra_app, and control_center. Both Flutter apps use Riverpod as their sole state management solution.
## Background
- Phase 3 (Chat Engine) is fully scaffolded but has not been end-to-end tested
- Current Flutter apps use BLoC pattern; Riverpod is preferred for maintainability and reduced boilerplate
- Migration should happen before Phase 4 to avoid compounding tech debt
## FCM fallback for Chat Engine
### Mitra Pairing
- Add configuration on Control center to configure Mitra's app require to ping or not.
- When Control Center allow non ping, application or backend will not force mitra to ping and allow them to keep online even when the app is closed or in backround
- Modify Mitra Pairing confirmation to send notification through FCM when websocket to Mitra is closed
### Bi-Directional Chat (WebSocket + FCM)
#### Mitra App
- When there is new unread message, mitra app must shows badge on active session
- When there is new unread message, mitra app must shows badge on the chat active session inside active session page
- Unread badge on each active session will be cleared when the message has been read
- Unread badge on active session button on main page will be cleared when the message has been read
#### Customer App
- When there is new unread message, Customer app must shows badge on active session
- Unread badge will be cleared when unread message has been cleared
### Chat Closure & Extension
- When chat closure called, backend will send closure signal to both Mitra and Customer
- Backend will use FCM if the websocket connection is down
### Control Center
- Control center shows configuration for ping from mitra
## Riverpod Migration
### Scope
- Migrate all BLoC classes in `client_app` and `mitra_app` to Riverpod annotation-based providers
- Replace `flutter_bloc` with `flutter_riverpod`, `riverpod_annotation`, `flutter_hooks`, and `hooks_riverpod`
- Add `riverpod_generator` + `build_runner` as dev dependencies for code generation
- No backend or control_center changes
### Migration Strategy
- [ ] Add Riverpod dependencies (`flutter_riverpod`, `hooks_riverpod`, `riverpod_annotation`) and dev dependencies (`riverpod_generator`, `build_runner`, `custom_lint`, `riverpod_lint`)
- [ ] Wrap app root with `ProviderScope`
- [ ] Migrate one Bloc at a time, starting with the simplest (e.g. AuthBloc)
- [ ] For each migrated Bloc:
1. Replace `Bloc`/`Cubit` class with `@riverpod` annotated `Notifier` or `AsyncNotifier` (extending `_$ClassName`)
2. Replace `BlocEvent` + `emit()` pattern with notifier methods that update `state` directly
3. Run `dart run build_runner build` to generate `.g.dart` files
4. Replace `BlocProvider` with generated provider (e.g. `authProvider`)
5. Replace `BlocBuilder` widgets with `ConsumerWidget` + `ref.watch()`
6. Replace `BlocListener` with `ref.listen()` inside widget or provider
7. Use `HookConsumerWidget` where flutter_hooks are needed (e.g. `useTextEditingController`, `useEffect`)
- [ ] Run E2E verification after each migration to catch regressions
- [ ] Remove `flutter_bloc` dependency only after all Blocs are migrated
### Affected Blocs
- [ ] `client_app` — AuthBloc, PairingBloc, ChatBloc, ChatOpeningBloc, SessionClosureBloc
- [ ] `mitra_app` — AuthBloc, OnlineStatusBloc, MitraChatBloc, ExtensionBloc
# Non-Functional Requirement
- [ ] WebSocket reconnects gracefully after network interruption (within 5s on stable network)
- [ ] Use FCM to send command or message when websocket is down
- [ ] No message loss during brief disconnects — undelivered messages sync on reconnect
- [ ] Chat screen maintains scroll position and input draft on app lifecycle events (background/foreground)
- [ ] Riverpod migration introduces zero new UI bugs — feature parity with BLoC implementation
# Tech Stack
- State management: Riverpod + flutter_hooks (replacing flutter_bloc)
- No backend changes expected — migration is Flutter-only