Skip to main content
ORbit’s API layer consists of Next.js API routes for server-side operations and Supabase RPC functions for database-level logic. Client-side data access goes directly through Supabase’s client library with RLS enforcement.
ORbit uses Supabase PostgREST for most data operations (no custom REST API needed). Next.js API routes are only used for operations requiring server-side secrets or multi-step orchestration (invitations, demo data generation, auth checks).

API routes

ORbit exposes the following Next.js API routes:

User management

MethodRoutePurpose
POST/api/invite/acceptAccept a user invitation
POST/api/admin/inviteSend an admin invitation (global admin)
POST/api/resend-inviteResend a pending invitation
POST/api/send-rep-inviteSend a device rep invitation
POST/api/create-device-repCreate a device rep account

Authentication

MethodRoutePurpose
GET/api/check-auth-statusVerify current auth session
GET/api/check-user-statusCheck user account status and permissions

Demo data

MethodRoutePurpose
POST/api/demo-dataManage demo data (purge, configure)
POST/api/demo-data/generateGenerate demo data with SSE streaming progress

Admin tools

MethodRoutePurpose
GET/api/admin/scan-pagesScan codebase for page documentation metadata

RPC functions

Supabase RPC functions handle operations that require transactional integrity or multi-table coordination. These are called via supabase.rpc('function_name', params).

Case lifecycle

FunctionParametersDescription
create_case_with_milestonescase data, facility_idCreates a case and pre-populates milestones from the resolved template
finalize_draft_casecase_idTransitions a draft case to scheduled status
get_surgeon_day_overviewsurgeon_id, dateReturns a surgeon’s cases for a given date

Analytics

FunctionParametersDescription
get_milestone_interval_mediansfacility_id, procedure_type_id, surgeon_id, milestone_template_idReturns median intervals between milestones with 3-tier cascade resolution
get_phase_mediansfacility_id, procedure_type_id, surgeon_id, milestone_template_idReturns median phase durations
resolve_template_phase_boundariesmilestone_template_idDerives phase boundaries from template items

Facility provisioning

FunctionParametersDescription
seed_facility_with_templatesfacility_id, config (JSONB)Seeds a new facility with configuration from global templates across 13+ categories

Data access layer

The web application uses a TypeScript data access layer (DAL) in lib/dal/:
ModuleScope
core.tsShared utilities and base query patterns
cases.tsCase CRUD, status transitions, milestone recording
facilities.tsFacility settings and configuration
users.tsUser management and role operations
lookups.tsCached lookup data (procedures, rooms, surgeons)
flag-rules.tsFlag rule CRUD operations
phase-resolver.tsTemplate-based phase boundary resolution

Client-side data fetching

All client-side data fetching uses the useSupabaseQuery hook:
import { useSupabaseQuery } from '@/lib/hooks/useSupabaseQuery';

const { data, isLoading, error } = useSupabaseQuery(
  ['cases', facilityId],    // Cache key
  async (supabase) => {     // Query function
    const { data, error } = await supabase
      .from('cases')
      .select('*, procedure_types(*), surgeons:users!surgeon_id(*)')
      .eq('facility_id', facilityId)
      .eq('is_active', true)
      .order('case_date', { ascending: false });
    if (error) throw error;
    return data;
  }
);

Authentication

All API access requires a valid Supabase Auth session. The auth flow:
  1. User authenticates via Supabase Auth (email/password)
  2. Next.js middleware validates the session on every request
  3. The Supabase client automatically includes the auth token
  4. RLS policies on every table enforce facility-scoped access
See Authentication for details.

Rate limiting

API routes that handle authentication (login, password reset) implement rate limiting to prevent abuse. Rate limits are tracked per IP and per user.

Key conventions

Use direct Supabase for standard CRUD operations — PostgREST + RLS handles security automatically. Use API routes only when you need server-side secrets (e.g., sending invite emails), SSE streaming (demo generator), or operations that shouldn’t expose the implementation to the client.
Use RPC functions for operations requiring transactional integrity (case creation with milestones), complex multi-table joins (analytics medians), or when the logic is too complex for PostgREST’s query syntax. Use client queries for simple reads, filters, and pagination.
DAL functions throw errors that are caught by useSupabaseQuery. API routes return JSON with { error: string } and appropriate HTTP status codes. Never return raw Supabase errors to the client.

Next steps