Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

15 — Flutter Implementation Guide (Rooms Module)

Module extension of 00-shared/11 (Flutter App Architecture). Structure, widgets, cubits, repositories, DTOs, models, navigation, theme, extensions, localization, testing, performance. Forward-looking.


1. Structure

lib/features/rooms/
├── data/
│   ├── dto/
│   │   ├── room_dto.dart                 # envelope payload → model (fromJson/toJson)
│   │   └── room_create_dto.dart          # mirrors CreateRoomDto (create-room.dto.ts:11-38)
│   ├── models/
│   │   └── room.dart                     # domain model + RoomType enum
│   └── repositories/
│       └── rooms_repository.dart         # E1–E5 (12_API_Mapping)
├── domain/
│   └── room_code.dart                    # pure code-normalization (uppercase/trim) `(proposed)`
└── presentation/
    ├── cubit/
    │   ├── room_list_cubit.dart          # PaginatedListMixin<Room>
    │   ├── room_detail_cubit.dart
    │   └── room_editor_cubit.dart
    ├── pages/
    │   ├── room_list_page.dart           # S1
    │   ├── room_detail_page.dart         # S2
    │   └── room_editor_page.dart         # S3 (create + edit)
    └── widgets/
        ├── room_card.dart
        ├── room_type_icon.dart
        ├── capacity_badge.dart
        ├── facility_chips.dart
        ├── room_filter_bar.dart
        ├── room_type_picker.dart
        ├── room_code_field.dart
        ├── facility_input_chips.dart
        └── delete_room_dialog.dart

2. Models & enums (exact from schema)

enum RoomType { classroom, lab, library, office, hall, other } // room.schema.ts:7-14

Room mirrors room.schema.ts:16-35 + base.schema.ts: id, tenantId, name, code, capacity?, type (default classroom), building?, facilities: List<String>, createdBy?/updatedBy?, isDeleted, deletedAt?, deletedBy?, version, createdAt, updatedAt. Ids String; dates DateTime (parse ISO). Never send DTOs to widgets (00-shared/11 §4).

3. Repositories

RoomsRepository (dio via AppDio bearer/refresh/error interceptors — 00-shared/11 §5):

Future<Paginated<Room>> list({int page = 1, int limit = 20});          // E2
Future<Room> getById(String id);                                        // E3
Future<Room> create(RoomCreateDto dto);                                 // E1
Future<Room> update(String id, RoomCreateDto dto);                      // E4
Future<void> delete(String id);                                         // E5 (void!)
  • E5 returns void because the handler is void (rooms.service.ts:48) — local row removal after 200, never a payload.
  • Typed exceptions: ApiException(code, status, fieldDetails, message) from the error interceptor (00-shared/06 §5); DUPLICATE_RESOURCE (409) handled as field error in the editor.

4. Cubits (see 13)

RoomListCubit (PaginatedListMixin + client filters (proposed)), RoomDetailCubit (404 → NotFound state), RoomEditorCubit (form + dirty + 409-inline). All pure-Dart, DI via get_it lazy factories (00-shared/11 §2).

5. Navigation (go_router)

GoRoute(path: '/rooms', builder: RoomListPage, guards: [authGuard, permissionGuard('rooms.read')]),
GoRoute(path: '/rooms/new', builder: RoomEditorPage(create), guards: [authGuard, permissionGuard('rooms.create')]),
GoRoute(path: '/rooms/:id', builder: RoomDetailPage, guards: [authGuard, permissionGuard('rooms.read')]),
GoRoute(path: '/rooms/:id/edit', builder: RoomEditorPage(edit), guards: [authGuard, permissionGuard('rooms.update')]),

Permission guards mirror permissions.constants.ts:50-53 (rooms.read/create/update/delete). Server does not enforce these today (OQ-2 — rooms.controller.ts:19); the client guard is the only gate until the backend RBAC guard lands; server remains authoritative later (403 → 403 screen). Master-detail via StatefulShellBranch at ≥ 840 dp (00-shared/05 §3). Deep links (forward-looking): studylyon://rooms, studylyon://rooms/:id.

6. Theme

Standard AppTheme tokens (00-shared/02, 11); type-tinted icons via colorScheme.*Container variants (proposed). No literal colors in widgets (02 §10, 04 §7).

7. Extensions

Reuse shared (00-shared/11 §8): DateTime.toDisplayDate, context.showAppSnackbar, etc. Module additions: RoomType.displayName, RoomType.iconData (→ RoomTypeIcon), Room.capacityLabel ("Cap 40" / absent), String.normalizeRoomCode (uppercase + trim — wraps domain/room_code.dart).

8. Localization

Keys under features/rooms/ namespace in .arb (en + fr + hi smoke): rooms.title, rooms.list.empty, rooms.list.filter.empty, rooms.detail.notFound, rooms.editor.save, rooms.editor.code.duplicate, rooms.editor.capacity.min, rooms.delete.confirm.title, rooms.delete.confirm.typeName, rooms.snackbar.{created,updated,deleted,notFound}, rooms.offline. Server messages rendered via error-code→key map with business-4xx fallback (00-shared/11 §9, 07 §11).

9. Testing

LayerCoverage
Unitroom_code normalization vectors ("lab 2" → "LAB 2"); enum mapping; capacityLabel; pagination meta mapping (pagination-query.dto.ts:41-54)
CubitRoomListCubit pagination + dedupe + filter reset; RoomDetailCubit 404→NotFound; RoomEditorCubit 409-inline + dirty/discard
WidgetS1 loading/empty/error + filter chips; S3 code-duplicate hint; S4 typed-confirm disabled state; permission-gated FAB hidden
Golden3 screens × light/dark × 3 sizes; new components (07 §Golden)
Integrationcreate → list → detail → edit → delete → 404; duplicate-code journey
E2E (device cloud)P0: admin creates room, edits, deletes; read-only role sees list without FAB

Run: flutter analyze, flutter test, flutter test integration_test (00-shared/11 §12).

10. Performance

  • ListView.builder for S1; RepaintBoundary around RoomCards; AnimatedSize for facility expand.
  • Debounces: search 300 ms, code-duplicate hint 300 ms.
  • Caches keyed sl:{tenant}:rooms:... with TTLs from 13 §6; RefreshIndicator bypasses cache.
  • Profile against 00-shared/10 §1 budgets (list ≤ 300 ms p95, detail ≤ 250 ms).

11. Open items to wire when backend lands

  1. Server filter/sort/search on GET /rooms (OQ-3) — drop client-side RoomFilterBar filtering, move to query params; add sort/q support.
  2. Update-path duplicate check (OQ-1) — remove client-only warning; rely on 409; map DUPLICATE_RESOURCE inline on edit.
  3. RBAC guard on controller (OQ-2) — server becomes authoritative; keep client guards as UX, handle real 403.
  4. update-room.dto.ts (OQ-6) — partial PATCH; editor sends only dirty fields.
  5. Capacity bounds (OQ-7) — server @Min(1); client min mirrors exactly.
  6. In-use delete guard (OQ-4) — delete dialog shows "in use by N timetables/bookings" with server truth; blocked delete → snackbar.
  7. Bookings module (planned) — availability section + Book CTA on S2; bookings cubit + endpoints.
  8. QR signage (forward-looking)QRCodeCard on S2 + scan route; data already present (room.code, room.schema.ts:21-22).
  9. Utilization analytics (proposed) — reports surface reading bookings aggregates.
  10. WS rooms.updated (forward-looking) — cache invalidation on multi-device edits.