Last updated: 2026-08-22
This checkpoint is the source of continuity for Roadly mobile. Every phase must follow the approved Final Roadly Flutter Mobile Plan. A material change to the architecture, UX model, security model, shared libraries, or role boundaries must be explained and agreed before implementation.
- Flutter monorepo with customer, driver and component-catalog apps.
- Shared API, authentication, design-system, localization, maps, notification, realtime and testing packages.
- Better Auth native Bearer sessions stored with platform secure storage.
- Customer and driver sign-in with role-aware navigation.
- Customer registration using typed reactive forms and Roadly components.
- Customer phone-verification onboarding, including development verification codes when SMS delivery is not configured.
- Existing unverified customer sessions are routed to phone verification.
- Driver registration remains administrator-controlled and is not exposed in the driver app.
- Customer registration and phone-verification copy is localized in the EN/MS/ES/PT catalogs, including validation and dynamic verification text.
- Customer and driver apps use role-specific
StatefulShellRoutenavigation with independent branch stacks, Roadly bottom navigation on phones, and an adaptiveNavigationRailon tablets. - Shared
RoadlyAppShell,RoadlyAppBar, navigation-item, badge, and icon abstractions are exported byroadly_design_systemand demonstrated in the component catalog. - Phone-less authenticated customer and future Google sessions are routed to a localized typed phone-entry recovery screen before verification. The number remains pending until the backend verifies the six-digit code, then it is saved to the account.
- Customer authentication supports native Google sign-in through the official
google_sign_inpackage. Android obtains an ID token for the configured Web OAuth server client, Better Auth verifies it and returns the same signed Bearer session used by email sign-in. Google cancellation is silent, errors remain visible, driver authentication stays email-only, and role checks are unchanged. - Customer and driver authentication share localized reactive forgot/reset password screens. Better Auth issues the single-use email token, each app receives it through its registered custom scheme, and a successful reset revokes existing sessions.
- Customer and driver sessions now own an authenticated Socket.IO connection.
The native client supplies the opaque Better Auth session during the
handshake, follows sign-in/sign-out lifecycle changes, reconnects over
WebSocket, signs the user out when the server rejects an expired session,
and emits a
realtime:resync-requiredevent after reconnect so feature repositories can reload authoritative state from the API. - The customer Rent destination now consumes
/api/v1/vehicles/catalogusing typed models and server pagination. It preserves the approved shell and uses Roadly cards, badges, buttons, localized states, pull-to-refresh, and near-bottom incremental loading. - The driver Drive destination now consumes the approved driver profile,
availability, active-ride, accept, and reject APIs. Assignments are refetched
after
ride:updatedandrealtime:resync-required; processing actions are locked against duplicates, and rejection uses a typed reactive form with the backend's structured reasons. - The approved top-app-bar checklist is now part of the shared design-system contract: Home/Drive use a dark hero bar that visually joins the Roadly hero, shows the vehicle mark and ROADLY wordmark, removes the redundant route subtitle, and exposes notification and profile actions. Feature destinations use solid/contextual bars with their route label. Bars retain the platform safe area, 44-48 px action targets, accessible tooltips, sticky scaffold behavior, and phone/tablet responsiveness. Future scroll-aware screens must transition from hero to solid styling without changing navigation state.
- The customer Rent flow now consumes server rental options, unavailable date ranges, server-authoritative availability/pricing quotes, booking creation, and Stripe checkout-session creation. Booking creation still rechecks overlap and pricing in the backend transaction. Customer Activity loads only the signed-in customer's bookings, refreshes after realtime recovery, and uses the existing ownership-aware cancellation endpoint.
RoadlyDateFieldandRoadlyCheckboxextend the internal design system so rental forms do not introduce raw feature-local interactive controls. Rental and Activity copy is available in EN/MS/ES/PT.- The customer Ride destination now consumes the existing Kuala Lumpur ride
options, signed five-minute fare quote, request, Stripe card-authorization,
cash, cancellation, and customer-history APIs. It restores active rides from
the server, refetches after
ride:updatedand realtime resync events, prevents duplicate mutations, and combines ride history with rentals in Activity. Ride journey copy is localized in EN/MS/ES/PT. - The customer Ride planner now accepts customer-selected pickup and drop-off coordinates through native address search, current foreground GPS location, and a Roadly private coordinate picker. Curated KL points remain only as an offline fallback. Permission denied, permanently denied, disabled services, unresolved addresses and loading states are explicit and localized. No third-party map tiles receive the customer's precise coordinate. The signed backend quote and server-owned fare calculation are unchanged.
- Mobile rental payments and ride card authorization now register Android/iOS
roadly://paymentreturns. A pending booking or ride identifier is persisted before leaving the app, restored after a deep link, resume, sign-in, or app restart, and cleared only after cancellation or authoritative server resolution. Return parameters choose the refresh destination but never set payment state. Stripe webhooks and authenticated booking/ride responses stay authoritative. Angular keeps its existing web return URLs.
Roadly uses role-specific bottom navigation on phones. Primary destinations must not be replaced with a side drawer or horizontally scrolling section tabs. Authentication, onboarding, checkout, full-screen maps, and incoming driver offers can temporarily hide the bottom navigation.
The customer app has five persistent destinations:
- Home - active rental or ride, upcoming activity, notifications, and quick actions.
- Rent - vehicle discovery, filters, details, availability, and booking.
- Ride - pickup and destination, ride type, estimate, matching, and live trip. This destination may receive stronger visual emphasis.
- Activity - rental bookings, ride history, receipts, and feedback.
- Account - profile, currency, language, payment methods, support, and sign out.
Customer journey:
Session -> Sign in/Create account -> Phone verification -> Home
Rent -> Vehicle -> Dates -> Extras -> Review/payment -> Confirmation -> Activity
Ride -> Route -> Ride type -> Estimate/payment -> Matching -> Live trip -> Receipt/feedback
The driver app has four persistent destinations:
- Drive - shift availability, incoming offers, and active trip.
- Activity - completed, cancelled, and rejected trip history.
- Earnings - daily/weekly earnings, payouts, and statements.
- Account - vehicle, documents, ratings, language, support, and sign out.
Safety is not buried in navigation. An active trip must always expose a clear shield/SOS action. An incoming ride is a focused full-screen sheet with route, distance/time, ride type, expected earnings, countdown, Accept, and Reject. Reject requires a reason. Processing actions are disabled to prevent duplicate submission.
The Angular admin console remains the Roadly operations product. An admin area must not be introduced into the customer or driver mobile apps without a new approved plan.
- Use
go_routerwith a stateful shell and an independent navigation stack for every primary destination. - Preserve scroll position, filters, and form state when switching tabs.
- Android Back pops the active branch before leaving the application.
- Active rides/trips expose a badge or subtle status indicator on Ride/Drive.
- Support opened from a booking or ride automatically attaches that record.
- Notifications use a top-app-bar indicator with an unread count.
- On tablets, bottom navigation adapts to a
NavigationRailwhile retaining the same information architecture. - Ask for permissions contextually: location when its feature needs it and notifications only after explaining their value.
Flutter Material 3 is the rendering, accessibility, gesture, and platform
foundation. The product-facing UI library is the internal
roadly_design_system package. Roadly must not adopt a complete third-party UI
kit that makes the product look generic.
Approved supporting architecture:
- Forms and validation:
reactive_formswith typed form models. - Navigation:
go_router. - State management: Riverpod.
- Icons: one Roadly icon abstraction using a consistent Lucide-style family plus approved custom brand SVGs.
- Motion: centralized Roadly duration, curve, and transition tokens using Flutter animation primitives.
- Visual QA and documentation: the
roadly_catalogapplication.
Feature screens must consume shared Roadly interactive components rather than styling raw controls independently. Material widgets may be used internally to implement the shared components and as non-interactive layout primitives.
Required component coverage:
RoadlyAppShell,RoadlyBottomNavigation, andRoadlyAppBarRoadlyButton,RoadlyIconButton, and contextual action controlsRoadlyTextField,RoadlyPasswordField, andRoadlySelectRoadlyCard,RoadlyBadge, andRoadlyStatusChipRoadlyBottomSheet,RoadlyDialog, andRoadlyToastRoadlySkeleton,RoadlyEmptyState, and error/offline statesRoadlyMapControl,RoadlyRideOffer, andRoadlyTripTimeline
Every shared component must be demonstrated in the catalog for light/dark themes, disabled/loading/error states, accessibility text scaling, and phone/ tablet widths before broad feature adoption.
- Deep-night, teal, and electric-lime palette with accessible contrast.
- Smooth gradient transitions without obvious section boundaries.
- Route-line, movement, vehicle, and location-marker motifs.
- Spacious display typography with compact operational information.
- Purpose-built vehicle, booking, ride, driver-offer, and status components.
- Subtle purposeful motion; avoid decorative or distracting animation.
- Roadly loading feedback instead of generic oversized spinners.
- Central status vocabulary and semantic colors across customer and driver.
- Responsive layouts, touch targets, screen-reader semantics, keyboard safety, reduced-motion support, and clear offline/retry behavior.
Any new UI package must solve a necessary behavior, be reviewed first, and be
wrapped by roadly_design_system. It must not be used directly and
inconsistently across feature screens. Proposed departures must include the
reason, alternatives, and impact on UX, security, maintainability, backend, and
existing functionality before approval.
Resume from this list in order. The Customer/Driver Home and shared Support Centre phase is complete and must not be repeated.
- In progress: the component catalog now provides interactive theme, locale, text-scale and phone/tablet viewport controls. Widget tests exercise the supported locale/theme/viewport matrix at 200% text.
- Complete visual QA in
roadly_catalogfor phone/tablet widths, light/dark themes, EN/MS/ES/PT translations and accessible text scaling. - Run focused API, controller, widget, route and deep-link regression tests.
- Perform Android/iOS release configuration, signing, privacy permissions and store-readiness checks only after feature verification.
- Follow the executable sign-off checklist in
docs/release-gate.md.
- Driver offer acceptance now survives app restarts because the active-trip contract exposes the current offer status.
- The Drive destination advances trips through the backend state machine and requires cash-receipt confirmation before cash trips can be completed.
- Activity uses the server-paginated driver trip history.
- Activity now presents a branded trip summary, reactive server-backed status filtering, route timelines, semantic status badges and mobile-safe paging.
- Earnings shows server-calculated daily, weekly and monthly totals through a branded balance hero, comparable momentum bars, financial snapshots, modern settlement rows and payout history. Financial calculations remain owned by the backend.
- Account shows performance, compliance documents and safety incident reporting through typed API models and reactive forms.
- The driver Account UI uses a branded profile header, soft responsive metrics, compliance progress, modern document rows, collapsible operational forms and bottom-safe scrolling. Inactive emphasized destinations no longer compete visually with the selected navigation destination.
- Driver Account now combines the detailed Roadly dashboard with a swipeable quick-access hub inspired by premium mobility apps. Each feature card is a working shortcut to Performance, Documents, or Safety; it does not replace the full operational sections.
RoadlyFeatureCardandRoadlySettingsTileare shared design-system components and are demonstrated and widget-tested inroadly_catalog.- Customer and driver Account destinations now combine Roadly's detailed
operational sections with premium quick-access cards and a consistent
settings menu. Language, display currency and appearance are persisted by a
shared
RoadlyPreferencesController. - Language changes rebuild both apps immediately with the generated EN/MS/ES/PT catalogs; appearance follows system, light or dark mode without restarting.
- Customer vehicle catalog, rental availability, booking creation and ride quotes pass the selected display currency to the backend. The backend returns converted display snapshots from the live/fallback FX service while retaining USD rental and MYR ride transaction currencies for settlement and history.
- Realtime events continue to trigger an authoritative profile/active-trip refetch; financial and compliance rules remain server-owned.
roadly_supportowns a single reusable Support Centre for customer and driver roles; feature apps do not duplicate its forms or visual states.- Support requests use the existing authenticated backend and include the signed-in user's eligible rental and ride references.
- Inbox, new-request and conversation states support refresh, reply, resolved write protection and explicit reopening. All application forms are typed reactive forms built from Roadly design-system controls.
- Support is a contextual destination from Home/Drive and Account, preserving the approved five-item customer and four-item driver bottom navigation.
- Customer Home now combines brand storytelling with server-backed fleet, booking and active-ride summaries plus clear Rent, Ride, Activity and Support actions.
- Driver Drive now places Activity, Earnings and Support shortcuts before the shift and active-trip workflow while leaving dispatch behavior unchanged.
- API URL:
http://10.0.2.2:5000 - Customer entrypoint:
apps/roadly_customer/lib/main.dart - Driver entrypoint:
apps/roadly_driver/lib/main.dart - Restart the backend after Better Auth configuration changes; hot reload does not reload the Node.js authentication server.
- Customer Google sign-in also requires
--dart-define=GOOGLE_WEB_CLIENT_ID=<web-oauth-client-id>and an Android OAuth client forcom.roadly.roadly_customerwith the active SHA fingerprints.