13 - State Management (Transport Module)
- 1. Cubit map
- 2. VehicleListCubit
- 3. Detail + Form cubits (vehicle/driver/route share shape)
- 4. AssignmentCubit (assign sheet + student assignments)
- 5. TransportOverviewCubit
- 6. Cross-cutting
Per-screen Cubit/Bloc design on top of 00-shared/06 conventions (stack:
flutter_bloc+get_it; server state via dio repository;LoadState= Initial/Loading/Success/Error(ApiException)). Mermaid diagrams included.
1. Cubit map
| Cubit | Screen(s) (05) | Data |
|---|---|---|
VehicleListCubit | 2 | page, limit, List<Vehicle>, PaginationMeta |
VehicleDetailCubit | 3 | Vehicle, form state |
VehicleFormCubit | 4 | form model, field errors, submit |
DriverListCubit | 5 | page, limit, List<Driver>, meta |
DriverDetailCubit | 6 | Driver |
DriverFormCubit | 7 | form model, errors, submit |
RouteListCubit | 8 | page, limit, List<Route>, meta |
RouteDetailCubit | 9 | Route, resolved vehicle/driver refs |
RouteFormCubit | 10 | form model, stops order, resource picks, submit |
AssignmentCubit | 11/12 | assign sheet + student's assignment list |
TransportOverviewCubit | 1 | 3 counts (vehicles/routes/drivers) |
LiveTrackingCubit | 13 | (planned) |
AttendanceCubit / FeesCubit | 14/15 | (planned) |
Repositories (VehicleRepository, DriverRepository, RouteRepository,
AssignmentRepository in features/transport/data/) are the only layer
touching HTTP; they map envelopes to models and throw
ApiException(status, message) (00-shared/06 §2, §3).
2. VehicleListCubit
stateDiagram-v2
[*] --> Initial
Initial --> Loading: fetch(page)
Loading --> Success: 200 envelope
Loading --> Error: 401/500
Success --> Loading: nextPage/prevPage/pullToRefresh
Success --> Error: refetch fails (keep stale)
Error --> Loading: retry
Success --> Success: delete OK (optimistic)
Success --> Success: delete 409 (rollback + guard dialog)
- Fetch:
GET /transport/vehicles?page&limit(transport.controller.ts:36-40);metadrives pagination (buildPaginationMeta,transport.service.ts:75). - Delete flow: optimistic ->
DELETE /transport/vehicles/:id(transport.controller.ts:54-58); on 409/404 restore row + emitDeleteBlocked(ApiException)/NotFound(transport.service.ts:94-101).
3. Detail + Form cubits (vehicle/driver/route share shape)
sequenceDiagram
participant S as Screen
participant D as DetailCubit
participant F as FormCubit
participant R as Repo
participant A as API
S->>D: load(id)
D->>R: getById(id)
R->>A: GET /transport/<entity>/:id
A-->>R: doc (404 -> ApiException)
R-->>D: Vehicle/Driver/Route
D-->>S: Success(doc) / Error(404)
S->>F: init(doc?)
F->>R: create(dto) | update(id, dto)
R->>A: POST | PATCH /transport/<entity>
A-->>R: 409 ConflictException | 201/200 doc
R-->>F: Success(doc) | Conflict(fieldMessage)
F-->>S: SubmitDone / FieldError(conflict)
- Form state fields:
saved: bool,submitting: bool,conflicts: Map<String, String>(server 409 verbatim,transport.service.ts:38-45, 113-116, 177-190). - RouteFormCubit extras:
stops: List<RouteStopDraft>re-sequenced on reorder (route.schema.ts:23-24),vehicleId/driverIdoptional strings (create-route.dto.ts:41-49).
4. AssignmentCubit (assign sheet + student assignments)
stateDiagram-v2
[*] --> Idle
Idle --> Loading: loadStudentAssignments(studentId)
Loading --> Loaded(list): GET /transport/assignments/:studentId
Loading --> Error: 401/500
Loaded --> Submitting: submitAssign(dto)
Submitting --> Loaded: 201 (append, refresh)
Submitting --> Conflict: 409 duplicate
Conflict --> Submitting: change route/student, retry
Loaded --> Submitting: removeAssignment(id)
Submitting --> Loaded: 200 (optimistic remove)
Submitting --> Error: 404 (refetch)
- Submit:
POST /transport/assignbody fromAssignRouteDto(assign-route.dto.ts:4-26;transport.controller.ts:120-124). - 409 ->
Conflictwith message "Student already assigned to this route." (transport.service.ts:257) + "View existing" action -> student assignment screen (05§10). - Remove:
DELETE /transport/assignments/:id(transport.controller.ts:132-136).
5. TransportOverviewCubit
Three independent fetches (limit=1 for counts); per-tile LoadState
(06 §1) so one failure never blanks the hub. Data: meta.totalItems
(transport.service.ts:75, 146, 215). Refetch all on pull-to-refresh.
6. Cross-cutting
- Cache: entity lists cached in memory (
Hiveoptional) per tenant; detail screens read cache-first then refresh (offline tolerance,00-shared/10§2). - Ref resolution (route detail): vehicle/driver ids are raw ObjectIds
(
route.schema.ts:26-30); RouteDetailCubit resolves via cached lists orGET /transport/vehicles|drivers/:idin parallel; unresolved -> null. - Events as hints:
VehicleCreated/RouteCreated/StudentRouteAssigned(transport.service.ts:47-57, 121-128, 267-278) are server-side signals; client refresh is response-driven, not event-driven. - Permission gating: cubits expose
canCreate/canUpdate/canDeletefrom RBAC (permissions.constants.ts:62-74); UI hides actions accordingly. - Planned cubits: LiveTracking/Attendance/Fees
(planned)perIMPLEMENTATION_PLAN.md:229- no data contract yet.