Data access layer
All case queries are centralized inlib/dal/cases.ts. This prevents query duplication and ensures consistent patterns.
Core functions
Listing cases
| Function | Description |
|---|---|
casesDAL.listByDate(supabase, facilityId, date) | Cases for a facility on a specific date |
casesDAL.listByDateRange(supabase, facilityId, dateRange, pagination?) | Cases within a date range |
casesDAL.listForCasesPage(...) | Full-featured list with tab filtering, sorting, pagination |
casesDAL.listForAnalytics(supabase, facilityId, dateRange, surgeonId?) | Optimized select for analytics |
casesDAL.search(supabase, facilityId, searchTerm, limit) | Search by case number |
Single case
| Function | Description |
|---|---|
casesDAL.getById(supabase, caseId) | Full detail with milestones, flags, staff, devices |
Mutations
| Function | Description |
|---|---|
casesDAL.recordMilestone(supabase, caseId, facilityMilestoneId, timestamp) | Record or update a milestone timestamp (upsert) |
Aggregations
| Function | Description |
|---|---|
casesDAL.countByTab(...) | Tab badge counts (all, today, scheduled, in_progress, completed, data_quality) |
casesDAL.flagsByCase(supabase, caseIds[]) | Flag summaries for a batch of cases |
Type system
List view (minimal)
Detail view (full)
ExtendsCaseListItem with patient info, case_milestones[], case_flags[], case_staff[], and case_implant_companies[].
Analytics view (optimized)
Key RPCs
| Function | Description |
|---|---|
create_case_with_milestones(...) | Creates case + populates milestones from resolved template |
finalize_draft_case(...) | Converts draft to scheduled status |
get_surgeon_day_overview(...) | Returns a surgeon’s full day summary as JSON |
Data fetching pattern
Always use theuseSupabaseQuery hook:
Common patterns
Fetching a single case with all relations
Fetching a single case with all relations
Use
casesDAL.getById() which includes milestones, flags, staff, and device companies in a single query. The return type is the full CaseDetail interface.Recording a milestone
Recording a milestone
Use
casesDAL.recordMilestone() which performs an upsert — it creates the milestone record if it doesn’t exist or updates the timestamp if it does. This prevents duplicate milestone entries.Filtering for analytics
Filtering for analytics
Use
casesDAL.listForAnalytics() which returns a minimal select optimized for chart rendering. It excludes expensive joins (staff, devices) that analytics views don’t need.