Next-generation, multi-tenant, serverless AI co-pilot for clinical workflows, triage prediction, and hospital operations.
- Overview
- Architecture
- Features
- Tech Stack
- Getting Started
- Environment Variables
- Database Setup (Supabase)
- Authentication & Security
- Role Permissions
- Project Structure
- API Routes
- Deployment
MedOS AI is a multi-tenant, serverless-first, AI-augmented Hospital Management System built on the modern web stack. Each hospital operates as an isolated tenant with its own staff, patients, and data — all within a single deployment. The platform:
- Runs at zero cost at validation/prototype scale (Supabase free tier + Vercel hobby)
- Has a clear upgrade path to production (Supabase Pro + Vercel Pro)
- Supports multi-tenancy with hospital-scoped data isolation via RLS policies
- Enforces RBAC (Role-Based Access Control) at the middleware layer and database level
- Includes an AI Chat co-pilot powered by Hugging Face Inference for clinical support and triage
- Features a MEWS-based AI Triage Engine (Modified Early Warning Score) for risk stratification
- Automatically logs every write operation to an immutable audit trail
- Provides dark/light theme support with system preference detection
Browser (Next.js 16 App Router, React 19)
│
├── / ─────────────── Landing Page (Client-rendered)
├── /login ──────────── Auth Page (Supabase Auth)
├── /signup/admin ────── Hospital Registration (creates tenant)
├── /signup/join ─────── Staff/Doctor Onboarding (token-gated)
└── /dashboard/* ─────── Protected (RBAC via middleware)
├── Overview ────── Role-aware KPI dashboard
├── AI Chat ─────── Conversational AI co-pilot
├── Patients ────── CRUD + detail drawer
├── Appointments ── Booking + status tracking
├── Pharmacy ────── Inventory + low-stock alerts
├── Lab ──────────── LOINC-coded orders + results
├── Radiology ───── PACS imaging + AI notes
├── Finance ─────── Revenue KPIs + billing
├── Staff ────────── Shifts + performance
├── Audit ────────── Immutable compliance logs
├── Settings ─────── Profile + password + session
└── Triage ────────── (redirects → AI Chat)
│
└── Supabase (PostgreSQL 16 + Auth + RLS)
Middleware (src/proxy.ts) intercepts all routes (except API, static assets, and images), validates the Supabase session, enforces RBAC permissions, and redirects unauthorised or unauthenticated requests.
| Module | Description |
|---|---|
| 🏠 Overview | Role-aware KPI cards (patients, appointments, low-stock, pending labs) + quick actions |
| 🤖 AI Chat | Conversational AI co-pilot for clinical workflows, documentation, and care support (all roles) |
| 🧠 AI Triage | MEWS-based risk stratification with colour-coded risk cards and save-to-record |
| 👥 Patients | Full CRUD, search, slide-in detail drawer with edit modal |
| 📅 Appointments | Booking modal, status tracking (Scheduled / Completed / Cancelled / No-show) |
| 💊 Pharmacy | Inventory management, low-stock alerting, upsert restocking |
| 🧪 Lab | LOINC-coded lab orders, result tracking, status filter pills |
| 🖥️ Radiology | PACS image logging with AI prediction and doctor notes, card grid view |
| 💰 Finance | Revenue KPIs, collection rate, filterable bills table (NGN) |
| 👔 Staff | Shift scheduling, performance star-ratings, role badges |
| 🛡️ Audit Logs | Immutable compliance trail with full-text search and table/action-type filters |
| ⚙️ Settings | Profile editing, password change, auto-logout status |
| 🌗 Theme | Dark/light mode with system preference detection and persistent toggle |
| 🔔 Activity Feed | Real-time notification bell with recent activity from all modules |
| 🧭 Breadcrumbs | Context-aware breadcrumb navigation across all dashboard pages |
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| UI Library | React 19 |
| Styling | Tailwind CSS v4 + custom clinical dark/light theme |
| UI Icons | Lucide React |
| Backend | Next.js API Routes (Node.js serverless) |
| Database | Supabase (PostgreSQL 16) |
| Auth | Supabase Auth + JWT |
| Session | @supabase/ssr (cookie-based, 7-day refresh) |
| AI Chat | Hugging Face Inference Router (via openai SDK) |
| Resend (appointment email alerts) | |
| Deployment | Vercel (Edge Network) |
git clone https://github.com/devadex247/medos.git
cd medosnpm installCreate a .env.local file in the project root. See Environment Variables below.
Follow the Database Setup section.
npm run devOpen http://localhost:3000 in your browser.
Create a .env.local file in the project root:
# ── Supabase (Required) ───────────────────────────
NEXT_PUBLIC_SUPABASE_URL=https://<your-project-ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your-anon-key>
SUPABASE_SERVICE_ROLE_KEY=<your-service-role-key> # Server-only, never expose to client
# ── Resend (Required for appointment email alerts) ─
RESEND_API_KEY=<your-resend-api-key>
# ── Hugging Face (Required for AI Chat co-pilot) ──
HF_TOKEN=<your-hugging-face-token>
# ── OpenAI (Optional — overrides HF for AI chat) ──
OPENAI_API_KEY=<your-openai-api-key>
OPENAI_CHAT_MODEL=<model-name> # Optional, defaults to router default
OPENAI_TRIAGE_MODEL=<model-name> # Optional, defaults to router defaultNever commit
.env.localto version control. It is already in.gitignore.
-
Create a new project at supabase.com
-
Navigate to SQL Editor in your project dashboard
-
Paste the entire contents of
supabase_schema.sqland run it -
The schema creates 19 tables with Row Level Security (RLS) policies:
# Table Purpose 1 usersPublic profiles (mirrors auth.users)2 hospitalsTenant organisations 3 hospital_access_tokensInvite tokens for staff onboarding 4 hospital_membershipsUser ↔ Hospital associations 5 departmentsHospital departments 6 doctorsDoctor profiles 7 patientsPatient records 8 appointmentsBooking & scheduling 9 medical_recordsClinical notes 10 patient_vitalsVital signs history 11 ai_recommendation_feedbackAI prediction feedback loop 12 admissionsInpatient admissions 13 inventoriesPharmacy stock 14 prescriptionsMedication prescriptions 15 staff_schedulesShift scheduling 16 billsFinancial billing 17 insurance_claimsInsurance claim tracking 18 lab_ordersLOINC-coded laboratory orders 19 radiology_imagesPACS imaging records 20 audit_logsImmutable compliance trail -
The schema also includes:
- Performance indexes on all foreign keys and common query patterns
- An auto-profile trigger (
on_auth_user_created) that creates apublic.usersrow on signup - Multi-tenant RLS policies scoped by
hospital_id
-
Configure Auth settings in your Supabase dashboard:
- JWT expiry: 604800 seconds (7 days)
- Refresh token rotation: Enabled
- Site URL: Your production URL (or
http://localhost:3000for local dev)
If you need to fix existing
hospital_idrelationships, seesupabase_fix_users_hospital_id.sql.
| Feature | Implementation |
|---|---|
| Session management | @supabase/ssr — cookie-based, works with Next.js SSR/RSC |
| 7-day sessions | Supabase refresh token rotation (configurable in dashboard) |
| Auto-logout | AutoLogoutHandler component — 15 min inactivity → sign out |
| RBAC middleware | src/proxy.ts — validates session + role on every request |
| Multi-tenant isolation | Hospital-scoped RLS policies on all data tables |
| Password reset | Supabase built-in email recovery flow |
| Token-gated signup | Staff/doctors join via hospital invite tokens |
| Server env validation | server-env.ts — startup checks for required environment variables |
The AutoLogoutHandler component listens for mousemove, keydown, click, scroll, and touchstart events. If no activity is detected for 15 minutes, it calls supabase.auth.signOut() and redirects to /login. A 60-second warning toast appears before sign-out.
| Role | Access |
|---|---|
owner_admin |
Full access to all modules including Finance, Staff, and Audit |
hospital_admin |
All modules including Finance, Staff, and Audit |
doctor |
Overview, AI Chat, Patients, Appointments, Lab, Radiology, Settings |
staff |
Overview, AI Chat, Patients, Appointments, Pharmacy, Lab, Radiology, Settings |
patient |
Overview, AI Chat, Settings (own data only) |
Roles are enforced at three levels:
- Middleware (
src/proxy.ts) — redirects on unauthenticated access or insufficient role - RBAC module (
src/lib/rbac.ts) — defines route-level permissions with typed route keys - Supabase RLS — prevents direct API calls from returning unauthorised data
src/
├── app/
│ ├── layout.tsx # Root layout (theme provider, fonts, dark mode script)
│ ├── globals.css # Tailwind v4 clinical dark/light theme
│ ├── page.tsx # Landing page (role previews, feature grid, CTA)
│ ├── login/page.tsx # Login page
│ ├── signup/
│ │ ├── admin/page.tsx # Hospital admin registration (creates tenant)
│ │ └── join/page.tsx # Staff/doctor onboarding (token-gated)
│ ├── api/
│ │ ├── activity/
│ │ │ ├── log/route.ts # POST — record audit activity
│ │ │ └── recent/route.ts # GET — fetch recent activity feed
│ │ ├── ai/
│ │ │ ├── chat/route.ts # POST — AI chat completion
│ │ │ └── triage/route.ts # POST — AI triage assessment
│ │ ├── auth/
│ │ │ ├── register-admin/route.ts # POST — hospital + admin registration
│ │ │ └── join-hospital/route.ts # POST — token-gated staff join
│ │ ├── health/route.ts # GET — health check + env status
│ │ ├── hospital/
│ │ │ └── invite-token/route.ts # POST/GET — generate/validate invite tokens
│ │ └── patients/route.ts # GET/POST/PUT/DELETE — patient CRUD
│ └── dashboard/
│ ├── layout.tsx # Sidebar + topbar shell (RBAC-filtered nav)
│ ├── page.tsx # Overview / KPI dashboard
│ ├── ai-chat/page.tsx # AI Chat co-pilot
│ ├── triage/page.tsx # Redirects → /dashboard/ai-chat
│ ├── patients/page.tsx # Patient management
│ ├── appointments/page.tsx
│ ├── pharmacy/page.tsx
│ ├── lab/page.tsx
│ ├── radiology/page.tsx
│ ├── finance/page.tsx
│ ├── staff/page.tsx
│ ├── audit/page.tsx # Immutable compliance logs
│ └── settings/page.tsx
├── components/
│ ├── AutoLogoutHandler.tsx # 15-min inactivity sign-out
│ ├── Breadcrumbs.tsx # Context-aware breadcrumb navigation
│ ├── EditModal.tsx # Generic slide-in modal for editing
│ ├── PatientEditForm.tsx # Patient-specific edit form
│ ├── ScrollToTop.tsx # Floating scroll-up button
│ ├── ThemeProvider.tsx # Dark/light theme context provider
│ └── ThemeToggle.tsx # Theme toggle button
├── lib/
│ ├── activity.ts # Activity logging + recent activity fetcher
│ ├── api-utils.ts # Shared API response helpers
│ ├── auth-context.ts # Auth context utilities
│ ├── rbac.ts # Role definitions, route permissions, access checks
│ ├── server-env.ts # Server-side env validation (required + optional)
│ ├── triage.ts # MEWS score calculator + risk stratification
│ └── supabase/
│ ├── admin.ts # Admin-level Supabase client (service role)
│ ├── client.ts # Browser-side Supabase client
│ ├── server.ts # Server-side Supabase client (RSC/API)
│ └── middleware.ts # Session refresh helper for middleware
└── proxy.ts # Next.js middleware — RBAC + auth enforcement
| Route | Method | Purpose |
|---|---|---|
/api/health |
GET | Health check + environment configuration status |
/api/auth/register-admin |
POST | Register a new hospital + owner admin account |
/api/auth/join-hospital |
POST | Token-gated staff/doctor registration |
/api/hospital/invite-token |
POST/GET | Generate or validate hospital invite tokens |
/api/patients |
GET/POST/PUT/DELETE | Full patient CRUD (hospital-scoped) |
/api/ai/chat |
POST | AI chat completion via Hugging Face / OpenAI |
/api/ai/triage |
POST | AI-powered triage assessment |
/api/activity/log |
POST | Record an audit activity entry |
/api/activity/recent |
GET | Fetch recent activity for the notification feed |
- Push your code to a GitHub repository
- Import the project at vercel.com/new
- Add all environment variables from
.env.localin the Vercel project settings - Vercel auto-detects Next.js and deploys to the Edge Network
# Or deploy from CLI
npx vercel --prodFor production workloads, upgrade your Supabase project to Pro to get:
- Dedicated Postgres with no pausing
- Point-in-time recovery (PITR)
- Higher connection limits
- Custom domains for Auth emails
MIT © 2026 MedOS Team