Frontend Overview
kxinspect_frontend_flutter is a fixture-first Flutter app for the Contesting Charges assignment. It runs the full Accept/Contest journey with no backend, yet can be flipped to the FastAPI mock via a single --dart-define without changing widgets or BLoCs.
Toolchain
| Tool | Version |
|---|---|
| Flutter | 3.41.9 |
| Dart | 3.11.5 |
bloc / flutter_bloc | 9.1.x |
go_router | 17.4.x |
drift + drift_flutter | 2.28.x + 0.2.x |
dio | 5.9.x |
l10n | flutter_localizations + ARB en/cy |
pubspec.yaml resolves the manifest once (Part 1), later parts consume a frozen pubspec.lock.
Five visual states
| Screenshot → Route | Hub property | What it proves |
|---|---|---|
Hub Outstanding (/maintenance?tab=open) | BookingSelector + blue deadline banner + inventory/inspection/task/charge cards | booking switch, banner routing, task raise |
| Hub Accepted overlay | green accepted outline | lifecycle in hub |
Inspection (/inspections/{id}) | title type/code/room, notes, actions/updates | charged vs uncharged navigation |
Charge (/charges/{id}) | intro deadline copy, fields, KxPhotoStrip, Contest/Accept | evidence viewer, thumb routing |
Contest (/charges/{id}/contest) | multiline Reason, 10-grapheme gate, attachments | validation, optimistic submit, persistence |
History is the second hub tab (?tab=history) — accepted, contested, resolved, paid with reason snapshot + statement link.
Non-negotiables
- Fixture-only review —
flutter run --dart-define=DATA_SOURCE=fixtureneeds no network;assets/fixtures/app_state.json+manifest.json+vectors/+media/are committed byte-stable artefacts copied from the backend export. - Thin UI — widgets contain no transition logic;
features/*/applicationowns it, repositories expose typed streams. - Central routes — every
GoRoutelives inlib/router/app_router.dartwithKxRouteBuilder+KxRoutesconstants; no ad-hocNavigator.push. - Typed models — Drift ↔ domain mappers round-trip through
local_store/domain_mapper; bum swapfixture ↔ remoteswaps only DI, not widgets. - Responsive & a11y — 360→desktop no horizontal overflow, token contrasts WCAG AA, semantics tested, keyboard operable.
Entry points
| File | Role |
|---|---|
lib/main.dart | minimal main() → bootstrap() |
lib/bootstrap.dart | AppConfig.parse, registerDependencies, runApp(KxApp); catches AppConfigException and renders diagnostic |
lib/app/kx_app.dart | MaterialApp.router + theme/locale/connectivity cubits |
lib/router/app_router.dart | createAppRouter(config, cubits, FeatureSlots) |
lib/app/di/register_dependencies.dart | GetIt + DiModule extensions compose features |
What you can do right now
flutter pub get && flutter gen-l10n && dart run build_runner build --delete-conflicting-outputs
flutter run -d chrome --dart-define=DATA_SOURCE=fixture
# then:
flutter run -d chrome --dart-define=DATA_SOURCE=remote --dart-define=API_BASE_URL=http://127.0.0.1:8000
Next: Architecture for the layered view, or Routing for URL anatomy.