- Customer: com.halobestie.client.client_app → com.mybestie
- Mitra: com.halobestie.mitra.mitra_app → com.mybestie.mitra
- iOS bundle IDs renamed to match (no .clientApp/.mitra camelCase legacy)
Mechanical rename touches Android build.gradle/Manifest/MainActivity
package, iOS pbxproj/Info.plist bundle IDs, Firebase configs
(google-services.json + GoogleService-Info.plist + firebase_options.dart),
new HaloBestie/Mitra launcher icons via flutter_launcher_icons (pubspec
config + adaptive-icon resources + AppIcon imageset), and the appId
references in every customer maestro flow + both .maestro/config.yaml
files. brandLogoBg (#FF699F) added to halo_tokens for the launcher pink.
Followup: re-register apps in Firebase consoles using the new package IDs;
strategy memo at project-firebase-env-strategy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stage 9 sweep on Client_Phone AVD + physical mitra phone:
- 01_smoke ✅
- 02_onboarding_verified ✅
- 03_onboarding_anon ✅
- 04_payment_expired ✅
- 05_searching_timeout: in progress when wrap-up began
- 06–08: not yet attempted
## Real shipping bugs fixed (would have hit prod)
1. **Router carve-out too narrow** (router.dart). The AuthAnonymousData
carve-out only protected /auth/display-name. On refreshListenable
notify after loginAnonymous resolves, GoRouter re-evaluates the
*bottom* of the navigation stack (/welcome — also an auth route),
and the AuthAnonymousData fallback redirected to /home, tearing down
the verif sheet before it could open. Loosened to allow any auth
route under AuthAnonymousData.
2. **Phase 4 multi-screen payment never called startSearch**
(searching_screen.dart). The legacy single-screen /payment did
`pairing.startSearch()` on confirm. The Phase 4 flow is
waiting → notif-gate → /chat/searching with no intermediate that
owned the call — customers would land on the searching screen with
no pairing in flight and never get matched. Added the kickoff to
searching_screen::initState when state is PairingInitialData and
paymentDraft.paymentId is set.
## Test infrastructure
- Self-contained Maestro flows 04 + 05 with inline verified-onboarding
prelude, distinct test phones per flow, robust waits.
- 02 + 03 fixed: malformed `extendedWaitUntil` (visible: + notVisible:
true → Maestro parsed as compound predicate); now use proper
notVisible: block.
- New dev-only POST /internal/_test/force-confirm-payment so flows can
advance past the waiting-payment screen without going through Xendit.
- /internal/_test/reset-phone now cascades through chat_messages →
chat_sessions → payment_sessions → auth_sessions before deleting the
customer row (FK 23503 was blocking re-runs).
- /internal/_test/force-pairing-timeout now accepts both
`searching` and `pending_acceptance` states (mitra-online dev means
the chat_session transitions through searching very quickly).
- mark_latest_payment_paid.js helper script for Stage 5+ flows.
## Maestro YAML quirks documented in flows
- text: matches anchored regex against the FULL content-desc — need .*
wildcards for substring, e.g. "mulai.*Rp.*" not "mulai".
- The middot `·` and other special unicode break naive matching;
always use .* anchors when the source string contains them.
- runFlow `when:` evaluates immediately; pair with waitForAnimationToEnd
or a preceding extendedWaitUntil before branching.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Searching screen: soft-prompt card reskin, pulsing-dots panel replaces
the spinner, inline 5-min timeout panel with `coba cari lagi` (resets
pairing notifier + routes to /payment/entry for a fresh funnel — the
server-side payment is failed_pairing at that point so a stale retry
isn't valid) and `kembali ke home` ghost CTA.
Bestie-found screen: S9 Match-V4 reskin — HaloOrb + status dot +
'halo, aku bestie {name}' + `mulai sesi {N} menit →` with N pulled from
the active session's duration_minutes.
Targeted-wait overlay (new) at /chat/waiting-targeted/:mitraId. Three
sub-states from pairingProvider's PairingTargetedWaitingData:
waiting (20s countdown) / accepted (routes to chat) / declined (stubbed
BestieOfflinePopup with a TODO pointing to Stage 8). Reached via
payment_screen._routeToSearchOnConfirmed when the confirm carried a
targetedMitraId — keeps the mandatory payment-before-pairing invariant.
Dev-only POST /internal/_test/force-pairing-timeout drives the 5-min
timeout shortcut for the Maestro flow without waiting live.
Maestro 05_searching_timeout.yaml + force_pairing_timeout.js helper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>