HLA typing MVP: patient feature + staff admin web app#83
Merged
Conversation
- firebase_storage for uploading/downloading hla result documents - file_picker for staff selecting a result file to upload - needed by the hla typing feature
- HlaTestStatus with label/description/icon per stage - HlaTestStatusX helpers: order, isTerminal, next, isResultsReady, isPatientCancellable - HlaSubjectRelation for cross-match panel members - UserRole (patient/admin) to gate the admin side
- adds nullable UserRole with objectbox dbRole converter (defaults to patient) - threads role through ctor, copyWith, toMap and fromMap - drives the in-app admin ui gate
- HlaTestRequest objectbox entity with json converters for status, subjects and status history (mirrors the medication model pattern) - HlaSampleSubject and HlaStatusEvent plain models with toMap/fromMap - HlaAppointmentSlot with isAvailable / remainingSeats helpers - HlaRequestFormState to hold the in-progress request form
- remote service: request crud, realtime stream-by-id, admin list, transactional slot book/release, storage result upload - local service: thin objectbox cache for offline request viewing - services only do i/o and throw AppException; no business logic
- abstract interface + impl returning FutureEither via futureHandler - enforces business rules: one active request, valid patient transitions, cancel frees the slot - always includes the patient as the primary panel subject
- requests notifier (+ realtime active-request stream provider), request-form notifier, slots notifier, admin notifier (requests + slots) - follows the existing global-singleton + build-injection pattern for consistency - applies audit fixes for this feature: no pii/state logging, no stackTrace force-unwrap
- status chip and vertical status timeline - subject tile + add-subject bottom sheet - slot tile for the appointment picker
- intro explainer with request / view-active cta - request form: build panel + consent + submit - requests list, realtime status timeline (book/cancel/results actions), results view/download - consent checkbox added for sending medical data to partner labs abroad
- request queue with status filter - request detail: advance status with note, view panel, upload result document - appointment slot management (create + activate/deactivate) - gated on role == admin at the entry point
- exports models, services, repository, providers and screens
- add patient and admin hla routes to the router - status/results/admin-detail take a :requestId path param - regenerate routes.gr.dart
- adds the HlaTestRequest entity to the objectbox model - adds UserProfile.dbRole property - incidental build_runner refresh of water_log_notifier.g.dart
- tappable card on the dashboard linking to the hla intro screen
- patient "hla typing" tile for everyone - admin "hla admin" tile shown only when role == admin
- firestore rules for hla_test_requests (owner create/cancel/edit-while-requested, admin full control) and hla_appointment_slots (admin-managed, ±1 bookedCount for booking transaction) - admin gate via console-managed hla_admins collection that clients cannot write, avoiding role self-escalation - storage rules locking hla_results files to the owning patient + admins - composite indexes for the request and slot queries; wire storage into firebase.json
- status helper coverage: order, next, terminal, cancellable, results-ready - request toMap/fromMap round-trip incl subjects and status history - hasResults and self-subject behaviour
- flutter web-only project under admin/ for a monorepo-style sibling app - pubspec with firebase, flutter_riverpod, file_picker, intl, url_launcher deps - web shell (index.html, manifest, icons) and default tooling config
- main.dart initializes firebase and mounts the app inside a ProviderScope - firebase_options.dart with web config; apiKey/appId are placeholders pending a registered web app (flutterfire configure) - shares the circle-60af7 project identifiers with the mobile app
- enums (HlaTestStatus, HlaSubjectRelation) with helpers, names matching the mobile app - material 3 theme with the brand purple seed and shared spacing tokens - date formatting helpers and a lightweight AdminException
- pure-dart HlaTestRequest, HlaSampleSubject, HlaStatusEvent, HlaAppointmentSlot - no objectbox; serialization matches the mobile app so the same firestore docs round-trip - genotype kept as a raw string since the admin only displays it
- auth service: google sign-in via browser popup, no google_sign_in plugin needed on web - hla admin service: realtime request/slot streams, request update, storage upload via putData, slot create + transactional release - isAdmin check against the hla_admins collection
- orchestrates business logic: append status events, set result fields, free a slot when a booked request is cancelled - delegates i/o to the service which throws AdminException
- no codegen: plain Notifier/AsyncNotifier providers - auth state + admin gate, status filter, realtime requests and slots streams - AdminActions notifier for advance-status / upload-result / put-slot using AsyncValue.guard
- status chip and a compact vertical status timeline
- app_root gates on auth state then admin status (signed out / not admin / admin) - google sign-in screen and an access-denied screen with sign out
- navigation rail switching between requests and slots - top bar showing the signed-in admin email with a sign out action
- master/detail: filterable realtime list on the left, selected request on the right - detail view: advance status with note, view the sample panel, upload a result document + summary, journey timeline
- realtime list of appointment slots with booked/capacity - add-slot dialog (date/time, location, capacity) and an active/hidden toggle
- status helper coverage (next, isResultsReady) - HlaTestRequest fromMap/toMap round-trip against the firestore doc shape
- explains the standalone web app and how it shares firebase with the mobile app - setup steps: flutterfire configure web, enable google provider, deploy rules, provision hla_admins - run/build/test commands and architecture overview
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Implements the HLA typing MVP end to end: a new patient-facing HLA feature in the mobile app, and a standalone Flutter web admin dashboard (
admin/) for Circle staff to manage requests. Both talk to the same Firebase project and the same Firestore collections (hla_test_requests,hla_appointment_slots,hla_admins) and Storage path (hla_results/), with serialization that round-trips between the two apps.HLA (Human Leukocyte Antigen) typing supports the broader Sickle Cell care journey; this MVP lets a patient request a test, book a collection slot, track progress through the lab pipeline, and receive results — while staff drive each request forward and upload the final report.
Mobile app (
lib/features/hla/)Follows the existing feature-first structure (models / services / repositories / providers / screens / components).
HlaTestStatusmodels the full journey:requested → bookingConfirmed → collected → sentForTesting → inTransit → tested → resultsProcessing → resultsAvailable → resultsSent, plus a terminalcancelledstate. Each status carries a patient-facing label, description, and icon; the status timeline component renders the journey.HlaTestRequest,HlaSampleSubject,HlaStatusEvent,HlaAppointmentSlotmodels; local (ObjectBox) + remote (Firestore/Storage) services; repository returnsFutureEitherper the project's functional error-handling convention.hla_requests,hla_request_form,hla_slots,hla_admin) with generated*.g.dart.routes.dart/routes.gr.dart; HLA entry points added to home and profile screens;rolefield added toUserProfileand HLA/role enums added.Admin web app (
admin/)A deliberately decoupled sibling app — the mobile HLA models are ObjectBox entities pulling in mobile-only plugins that don't build for web, so the admin app re-implements the small HLA data layer in pure Dart with matching serialization. See
admin/README.mdfor full setup.putDatafor web) plus an optional summary; sets status to Results available.hla_admins/{uid}, not the profilerolefield: a non-admin signs in but hits an "access denied" screen and writes are rejected by the rules.Security & infra
firestore.rules,storage.rules, andfirestore.indexes.jsonupdated/added for the new collections and Storage path (shared between both apps).firebase_storageandfile_pickerdeps added to the mobile app.Testing
test/features/hla/hla_models_test.dart(model serialization).admin/test/widget_test.dart.Notes / follow-ups
admin/lib/firebase_options.dartrequires real web credentials viaflutterfire configurebefore the admin app connects (documented in the README).firebase.json.🤖 Generated with Claude Code