Files
halobestie-clone/mitra_app/CLAUDE.md
ramadhan sjamsani 2b61c79a86 Phase 3.4: mitra_app self-managed auth cutover
Rips firebase_auth; phone OTP flow now talks directly to the new
backend endpoints, JWT access token lives in memory, refresh token
persists via flutter_secure_storage. WebSocket handshakes read the
access token from AuthBridge instead of Firebase.

Smoke-tested end-to-end against the backend via curl:
- otp/request → read stub code from backend log → otp/verify
- /api/mitra/auth/me + /api/shared/auth/refresh rotation
- logout → post-logout refresh correctly fails REFRESH_INVALID
- ACCOUNT_INACTIVE (403) + WRONG_FLOW (400) error paths verified
- Debug APK links cleanly

- pubspec: drop firebase_auth, add flutter_secure_storage
- core/auth/auth_bridge.dart: shared mutable state (access token +
  refresh callback + in-flight de-dup) as keepAlive provider
- core/auth/token_storage.dart: flutter_secure_storage wrapper
- core/auth/auth_notifier.dart: bootstrap → refresh; requestOtp +
  verifyOtp via /api/mitra/auth/*; logout; granular OTP error codes
- core/api/api_client.dart: Bearer from bridge + postRaw(skipAuth) for
  auth endpoints + single-retry 401 refresh
- core/chat/*_notifier.dart: WS auth frame reads bridge.accessToken
- features/auth/screens/otp_screen.dart: verificationId → otpRequestId
- mitra_app/CLAUDE.md: Auth section rewritten (was stale on Firebase)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 15:58:25 +08:00

1.4 KiB

Halo Bestie — Mitra App

Flutter mobile application for mental health professionals (mitra/partners).

See root CLAUDE.md for full project context and architectural decisions.

Stack

  • Framework: Flutter (iOS + Android)
  • Auth: Self-managed (Phase 3.4). Phone OTP only — no Google / Apple. Access token lives in memory on an AuthBridge; refresh token persists in flutter_secure_storage. firebase_auth is no longer used; firebase_messaging is kept for FCM push.
  • API: Calls public Fastify backend (/api/mitra/ and /api/shared/ routes). shared.auth covers refresh + logout for both apps.

Key Concepts

  • Users are mitra — trained mental health professionals
  • Core flow: phone OTP login → set availability → accept sessions → chat with client → receive payment
  • Mitra accounts require approval from control center before going live (backend returns ACCOUNT_INACTIVE 403 on OTP verify when is_active=false)

Conventions

  • Never call /api/client/ or /internal/ routes from this app
  • API calls go through ApiClient; it auto-attaches the JWT from AuthBridge and auto-refreshes on 401
  • WebSocket handshake (/api/shared/ws) sends the same access token in the first frame's {type:"auth", token} message
  • Mitra role is encoded in the JWT claims (user_type: "mitra") — the backend enforces the role per route; never trust client state alone