DRC-APP is a full-stack diabetic retinopathy screening platform. It includes:
- A web frontend (Vite + React) for administrators, doctors and patients.
- An Express/Node backend that performs admin-level operations and uses the Supabase service role for privileged DB access.
- An Expo React Native mobile app (in
mobile/) which mirrors the web UI and is intended for on-device viewing and lightweight workflows. - Supabase PostgreSQL backend with Row Level Security (RLS) protecting patient data.
This README documents the repository layout, local setup, running instructions, migration notes, and troubleshooting tips.
mobile/— Expo React Native app (mobile client).client/— Vite React web application (web client).server/— Node/Express backend routes and API wrappers used by the web frontend.supabase/— Supabase config and SQL migrations. Seesupabase/migrations/.shared/— Shared types and DB schema definitions.
Key files to note:
mobile/src/lib/api.ts— Mobile Supabase API wrapper and helper mappings (fixes fortimestampandidcasting).supabase/migrations/20260128000000_add_admin_rls_policies.sql— Migration that adds anis_admin()helper and policies to allow admins to SELECT/UPDATEprofiles.client/src/pages/patient-dashboard.tsx— Reference web patient dashboard used as a basis for the mobile patient dashboard.mobile/src/screens/FAQScreen.tsx— Mobile FAQ screen (recently synced to match the web FAQ content).
Prerequisites
- Node.js (16+ recommended)
- npm (or pnpm/yarn)
- Git
- For mobile: Expo CLI (optional, we use
npx exposo global install is not required) - Supabase CLI if you plan to run migrations from CLI:
npm install -g supabaseor usenpx supabase
- Clone the repo (if not already):
git clone https://github.com/faizanshoukat5/DRC-APP.git
cd DRC-APP- Install dependencies
Root (installs server + client tools):
npm installMobile app (separate folder):
cd mobile
npm install- Environment variables
This project uses Supabase. Create a .env file (or set env vars in your shell) for each component.
-
For the mobile client (in
mobile/.envor environment):EXPO_PUBLIC_SUPABASE_URL= your Supabase URLEXPO_PUBLIC_SUPABASE_ANON_KEY= your Supabase anon public key
-
For the server (in
server/.env):SUPABASE_URL= your Supabase URLSUPABASE_SERVICE_ROLE_KEY= service_role key (keep secret)PORT= optional server port (default 3000)
Never commit your service role key to source control.
- Apply Supabase migrations
The repo contains SQL migrations under supabase/migrations/. The most important migration to be aware of is:
supabase/migrations/20260128000000_add_admin_rls_policies.sql
It creates an is_admin() helper and adds RLS policies enabling admins to SELECT and UPDATE the profiles table from the client (when appropriate).
You can apply migrations via the Supabase CLI (recommended) or paste the SQL into the Supabase SQL editor (UI).
Using the Supabase CLI (example):
# from the repo root (ensure supabase CLI is installed and you're logged in/linked to the project)
npx supabase db pushOr open the Supabase dashboard → SQL Editor and run the SQL file content.
Important: If you prefer to keep strict RLS, you can instead call admin endpoints on the server which use the service role and bypass RLS. The server has endpoints under server/routes.ts that use the supabaseAdmin client.
- Run the backend server
cd server
npm install
npm run devThe server uses the service role key to perform admin actions (e.g., listing pending doctors). Keep the server protected; do not expose your service role key in client bundles.
- Run the web client (Vite)
# from repo root
npm run dev- Run the mobile Expo app
cd mobile
npx expo start --tunnel --clearScan the QR code with Expo Go or open in a simulator/emulator. If you have an Android device connected, press a to open directly.
- The mobile app uses the Supabase anon client and is therefore subject to Row Level Security. Previously, admins could not list pending doctors from the mobile client because RLS only allowed owners to select their own
profilesrows. - To allow admin reads/updates from the mobile client we added the migration
supabase/migrations/20260128000000_add_admin_rls_policies.sql. Apply it to your Supabase project to enable admin view in the mobile client. - If you do not want to open admin-level RLS to the anon client, use the server endpoints (they use the
supabaseAdminservice role client) to fetch admin-only data and proxy it to the client.
- Mobile
api.tsmappings: thescanstable uses atimestampcolumn (notcreated_at), andidvalues are stored as bigint — we cast them to strings when returning to the client. - Patients cannot upload fundus images from the patient dashboard; upload and analysis features are restricted to the
doctorrole. The mobile navigator registers theAnalysisroute only for doctors. - The server contains endpoints that require the service role (privileged) — avoid calling
supabaseAdminfrom browser/mobile clients.
- Expo errors about SDK: make sure you're in the
mobile/folder when runningnpx expo start. - If
npx supabase db pushopens a different process, ensure your current working directory is the repo root and thesupabasefolder exists. - If RLS blocks admin reads on mobile, either apply the admin RLS migration or use the backend admin endpoints.
- Fork the repo and create a feature branch.
- Implement changes and add tests where possible.
- Open a Pull Request describing the change and link any related issues.
If you're adding DB migrations, include them under supabase/migrations/ and document the reasoning.
Last updated: 2026-01-28
🔬 RetinaAI is a compact, clinician-first application for diabetic retinopathy (DR) screening. It includes a React + Vite frontend, an Express server API that integrates with Supabase for storage and auth, and a simple scan storage and retrieval system with a stubbed inference flow (replaceable by a real model).
- 🚀 Quick start
- 🧩 Architecture
- ⚙️ Prerequisites & Environment
- 💻 Local development
- 📦 Build & Production
- 🗂 Data model & API reference
- 🧪 Testing & QA (recommendations)
- 🔒 Security & privacy
- 🛠 Extending the inference/model pipeline
- 🧭 Project layout & key files
- 🤝 Contributing
- 📄 Additional docs
- Clone the repo:
git clone <repo-url>
cd DRC-APP- Install dependencies (npm):
npm install
# or your package manager of choice (pnpm, yarn)-
Create environment variables (see
.env.exampleguidance below). -
Start development servers (run server + client in two terminals):
PowerShell (Windows):
$env:NODE_ENV = 'development'
npm run dev # starts the Express server (server/index.ts)
npm run dev:client # in another terminal starts Vite client (port 5173)Note: npm run dev sets NODE_ENV directly inline in package.json; using PowerShell, prefixing with $env:NODE_ENV = 'development' ensures it works on Windows.
- Client: Vite + React + TypeScript, Tailwind CSS, TanStack Query and shadcn-style UI primitives.
- Server: Express.js TypeScript API (server/), uses Supabase admin client for DB/storage.
- Shared: Zod schemas and Drizzle table definitions under
shared/schema.ts. - Storage: Supabase buckets for images and a
scanstable for results.
Key design goals:
- Clinician-first UI (mobile container layout), role-based routing (patient, doctor, admin).
- Simple server-side API for image upload, scan creation, and user/profile management.
- Replaceable inference pipeline; currently uses a placeholder (server/routes.ts).
Required global tools (recommended):
- Node.js (>=18 LTS)
- npm (or pnpm / yarn)
- A Supabase project (or a local Supabase setup)
Important environment variables:
For client (Vite):
- VITE_SUPABASE_URL
- VITE_SUPABASE_ANON_KEY
For server (Express):
- SUPABASE_URL
- SUPABASE_SERVICE_ROLE_KEY (or SUPABASE_ANON_KEY for lower privileges)
- PORT (optional, defaults to 5000)
Example .env values (do NOT commit secrets):
VITE_SUPABASE_URL=https://xyz.supabase.co
VITE_SUPABASE_ANON_KEY=public-anon-key
SUPABASE_URL=https://xyz.supabase.co
SUPABASE_SERVICE_ROLE_KEY=service-role-key
PORT=5000
Notes:
- Client uses Vite env vars prefixed with
VITE_. - The server expects a service role key for admin operations (create/read scans, manage profiles).
Recommended workflow:
- Ensure env vars are configured.
- Start the server (PowerShell):
$env:NODE_ENV = 'development'
npm run dev- Start the client in a separate terminal:
npm run dev:client- Open the client at http://localhost:5173 and the server on the port shown (default 5000).
Helpful scripts (from package.json):
npm run dev:client— run the front-end (Vite).npm run dev— run the server in dev mode usingtsx.npm run build— runs server build script (script/build.ts) which builds production bundles.npm run start— run the built server bundle.npm run check— TypeScript type check.npm run db:push— push Drizzle migrations to the DB.
- Build (single command):
npm run build- Start production server (after build):
NODE_ENV=production npm start
# or on PowerShell
$env:NODE_ENV = 'production'; npm startDeployment recommendations:
- Client: Vercel, Netlify, or static hosting from the built assets.
- Server: Host on Railway, Fly.io, Render, or a VPS. Ensure your Supabase keys and DB are provided as environment variables in the host.
- For a single-host deployment,
script/build.tshelps bundle and produce runnable server artifacts.
Shared schema: shared/schema.ts (Zod + Drizzle definitions)
Scans table (key fields):
- id, patient_id, timestamp
- original_image_url, heatmap_image_url
- diagnosis, severity, confidence
- model_version, inference_mode, inference_time, preprocessing_method
- metadata (JSON)
Server API highlights (prefix /api):
-
Auth & Profiles
GET /api/auth/me— authenticated profilePOST /api/auth/profile— create/update profile after sign-up
-
Admin
GET /api/admin/doctors/pending— pending doctors (admin only)POST /api/admin/doctors/:id/approve— approve doctor (admin)POST /api/admin/doctors/:id/reject— reject doctor (admin)
-
Doctor/Patient relationships
GET /api/doctors/approved— list approved doctorsPOST /api/patient/select-doctor— patient selects a doctor (patient only)GET /api/patient/my-doctor— get assigned doctor (patient only)GET /api/doctor/my-patients— get patients assigned to a doctor (doctor only)
-
Scans
GET /api/scans— list scans (filter by role)GET /api/scans/recent?limit=n— recent scansGET /api/scans/:id— single scanPOST /api/scans— create scan (approved doctor)POST /api/doctor/upload— image upload (multer) + placeholder inferenceGET /api/patients/:patientId/scans— patient scans (approved doctor)
Auth: protected endpoints expect an Authorization header Bearer <access_token> (client uses a Supabase session token).
Current project does not include automated tests. Suggested additions:
- Unit tests: Jest + ts-jest for server-side logic and React component tests.
- Integration: Supertest for API routes, testing auth flows and DB interactions (against a test DB).
- E2E: Playwright or Cypress for user flows (login, upload, results export).
Add CI (GitHub Actions) to run type checks, lint, tests, and optional build.
- Use Supabase policies and restricted service role keys only on the server.
- Never commit
.envwith keys; store secrets in the host's secret manager. - Ensure HTTPS in production. Consider logging and audit trails for patient data access.
Current behavior: /api/doctor/upload performs a placeholder inference and stores a stubbed scan record. To integrate a real model:
-
Implement an inference service:
- Option A: Containerized model server (FastAPI / Flask) with GPU access.
- Option B: Cloud endpoint (GCP, AWS SageMaker) with a REST API.
- Option C: On-device TFLite for local/edge inference (then send results to server).
-
Replace the placeholder inference in
server/routes.tswith a call to your model service. Steps:- Upload image to Supabase storage (already present in route).
- Call model endpoint with image or storage URL.
- Retrieve prediction (diagnosis, severity, confidence) and heatmap image.
- Persist to
scanstable viastorage.createScan()includingheatmapImageUrl.
-
Considerations:
- Performance: async model calls, queueing (e.g., RabbitMQ) for high throughput.
- Security: validate model responses, sanitize image URLs.
- Explainability: save and surface heatmap overlays as images/URLs.
Top-level layout (important files & folders):
-
client/ — React front-end (Vite)
- src/
- App.tsx — role-based routing and providers
- pages/ — screens (landing, home, dashboards, results, analysis, faq, etc.)
- components/ —
mobile-layoutand UI primitives - lib/ —
api.ts,supabaseClient.ts,queryClient.ts - hooks/ —
useAuth.ts,use-mobile.tsx - index.css — theme tokens & CSS variables
- src/
-
server/ — Express API
- index.ts — server bootstrap
- routes.ts — main API route handlers
- storage.ts — DB wrapper for scans
- supabaseClient.ts — admin client & config
-
shared/
- schema.ts — Zod + Drizzle schema (source-of-truth)
-
supabase/ — migrations & config (if using Supabase migrations locally)
-
docs/design-implementation.md — design & component documentation
-
docs/design-implementation.doc — Word-compatible doc (auto-generated)
- Fork & branch from
main. - Add unit tests and update docs when changing behavior.
- Follow TypeScript strictness & run
npm run checkbefore PR.
Suggested PR checklist:
- Type checks pass (
npm run check). - New features include tests.
- Update
docs/design-implementation.mdwhen changing UI, API, or data shape.
- Design and component documentation:
docs/design-implementation.mdanddocs/design-implementation.doc📁 - Database migrations:
supabase/migrations/