15 - Flutter Implementation Guide (Transport Module)
- 1. Feature folder
- 2. Models (mirror schemas exactly)
- 3. Repositories (dio)
- 4. Cubits
- 5. Screens
- 6. Validation (client mirror of DTOs)
- 7. Navigation (go_router)
- 8. DI registration (get_it)
- 9. Permissions & auth
- 10. Testing
- 11. Forward-looking hooks
Module-specific build guide on top of 00-shared/11 (Flutter architecture, get_it DI, dio, go_router, flutter_bloc) and 00-shared/06 (state patterns). Order = recommended implementation sequence; each step maps to source files.
1. Feature folder
lib/features/transport/
data/
dto/vehicle_dto.dart, driver_dto.dart, route_dto.dart,
route_assignment_dto.dart # envelope-payload mappers
repositories/vehicle_repository.dart, driver_repository.dart,
route_repository.dart, assignment_repository.dart
domain/ # thin models (Vehicle, Driver, Route,
models.dart # RouteStop, RouteAssignment, Shift)
presentation/
cubits/vehicle_list_cubit.dart, vehicle_form_cubit.dart,
driver_list_cubit.dart, driver_form_cubit.dart,
route_list_cubit.dart, route_form_cubit.dart,
assignment_cubit.dart, transport_overview_cubit.dart
screens/overview_screen.dart, vehicles_list_screen.dart,
vehicle_detail_screen.dart, drivers_list_screen.dart,
driver_detail_screen.dart, routes_list_screen.dart,
route_detail_screen.dart, route_editor_screen.dart,
assign_student_sheet.dart, student_assignments_screen.dart
widgets/stat_tile.dart, entity_status_badge.dart, shift_picker.dart,
route_stop_editor.dart, resource_picker.dart,
assignment_tile.dart, dependency_guard_dialog.dart,
conflict_field_error.dart
Widgets per 07_Component_Library.md; screens per 05/06.
2. Models (mirror schemas exactly)
Vehicle-vehicle.schema.ts:19-50: plateNumber, model, capacity (int), type (bus/van/car enum), status (active/maintenance/inactive), year?, color?, insuranceExpiry? (DateTime, server sends string - parse defensively), notes?.Driver-driver.schema.ts:13-47: firstName, lastName, licenseNumber, phone, email?, status (active/inactive/on_leave), licenseExpiry?, address?, emergencyContact?, joinedAt? (DateTime), notes?.Route-route.schema.ts:12-40: name, startPoint, endPoint, stopsList<RouteStop{name, order}>(keep sorted by order client-side), vehicleId?, driverId? (String ObjectIds), status, estimatedDuration?, notes?.RouteAssignment-route-assignment.schema.ts:12-38: routeId (populated -> Route), studentId, shift (morning/evening/both), status, stopName?, assignedAt? (DateTime), notes?.
Immutable classes + fromJson/toJson (repository maps envelope data).
Never send tenantId/isDeleted (server-owned, base.repository.ts:32-36).
3. Repositories (dio)
- Endpoints per
12_API_Mapping.md; base/api/v1+ApiBearerAuth(transport.controller.ts:23-26). - Paginated calls: parse
data+meta {page, limit, totalItems, totalPages, hasNext, hasPrevious}(buildPaginationMeta,transport.service.ts:75). - Typed errors:
ApiException(409, message)for conflicts (message verbatim - used directly inConflictFieldError);ApiException(404). - Assignment repo:
findByStudent(studentId)expectsrouteIdpopulated (route-assignment.repository.ts:20-24) - map nested route. - Single-flight + envelope mapping per
00-shared/11§"AppDio".
4. Cubits
Per 13_State_Management.md: implement VehicleListCubit first (pattern for
the other two lists), then form cubits (with conflicts map), then
AssignmentCubit (assign + student list), then TransportOverviewCubit.
Use the shared LoadState sealed class and pagination mixin
(00-shared/06 §3.1-3.2).
5. Screens
| Order | Screen | Key widgets | Source |
|---|---|---|---|
| 1 | Vehicles list/detail/form | EntityStatusBadge, ConflictFieldError, AppPagination | 06 §2-4 |
| 2 | Drivers list/detail/form | same + AppAvatar | 06 §5-7 |
| 3 | Routes list/detail | ResourcePicker (read), stop list | 06 §8-9 |
| 4 | Route editor | RouteStopEditor (ReorderableListView + order resequence), ResourcePicker | 06 §10 |
| 5 | Assign sheet + student assignments | ShiftPicker, StudentPicker, AssignmentTile | 06 §11-12 |
| 6 | Overview | StatTile x3 | 06 §1 |
6. Validation (client mirror of DTOs)
- Vehicle form: capacity
>= 1(create-vehicle.dto.ts:14-17); type from enum (:19-21). - Driver form: email
IsEmail-style regex (:22-24); datesIsDateString-> send ISO strings (:27-29, 41-44). - Route form: stops
{name, order}(create-route.dto.ts:11-19); optional vehicleId/driverId strings. - Assign: shift enum (
assign-route.dto.ts:13-15). - Conflict messages: render server text verbatim (
07§8).
7. Navigation (go_router)
/transport overview (auth + any transport.* read)
/transport/vehicles list | children: /:id detail
/transport/drivers list | children: /:id detail
/transport/routes list | children: /:id, /:id/edit
/transport/students/:studentId/transport assignments
Create forms = bottom sheets (phone) / dialogs (tablet), not routes
(00-shared/03). Planned: /transport/live, /transport/attendance,
/transport/fees placeholders (planned).
8. DI registration (get_it)
getIt.registerLazySingleton<VehicleRepository>(() => VehicleRepository(getIt()));
getIt.registerLazySingleton<DriverRepository>(() => DriverRepository(getIt()));
getIt.registerLazySingleton<RouteRepository>(() => RouteRepository(getIt()));
getIt.registerLazySingleton<AssignmentRepository>(() => AssignmentRepository(getIt()));
// cubits factory-registered per screen (pass params via constructor args)
9. Permissions & auth
- Gate FAB/menu on RBAC (
permissions.constants.ts:62-74); 403 handling per00-shared/07; JWT viaAppDiointerceptor (00-shared/11). - Note: RBAC guards on endpoints are not yet wired in the backend
(
AGENTS.md"Not yet implemented") - client still gates UI.
10. Testing
- Unit: cubit state transitions incl. 409 ->
Conflict, optimistic delete rollback (13§2-4); modelfromJsonfor populated assignment. - Widget: golden per screen (
00-shared/10§6); stop editor reorder test. - Integration: mock dio with fixture envelopes; pagination boundary tests
(
meta.hasNext). - E2E seeds per
14§7.
11. Forward-looking hooks
- Live tracking/attendance/fees screens scaffolded behind feature flags,
wired when backend lands (
IMPLEMENTATION_PLAN.md:229). - QR boarding
(forward-looking):mobile_scannerdependency flagged in00-shared/11§1. - Analytics events
transport.*(proposed)(05Analytics section).