Transform medical records into actionable insights. Upload, process, and understand patient documents in seconds with AI-powered document extraction.
medflow/
├── apps/
│ ├── api/ # Express.js backend (port 4000)
│ └── web/ # Next.js frontend (port 3000)
├── docker-compose.yml
└── package.json # Root scripts for running both apps
# Install dependencies
npm install
cd apps/api && npm install
cd ../web && npm install
cd ../..
# Start both servers
npm run dev- Frontend: http://localhost:3000
- API: http://localhost:4000
# Database (Supabase PostgreSQL)
DATABASE_URL="postgresql://..."
SUPABASE_URL="https://xxx.supabase.co"
SUPABASE_SERVICE_KEY="..."
# Redis (for job queues)
REDIS_HOST=localhost
REDIS_PORT=6379
# JWT Authentication
JWT_SECRET=your-secret-key
JWT_EXPIRES_IN=7d
# Server
PORT=4000
CLIENT_URL=http://localhost:3000
NODE_ENV=developmentNEXT_PUBLIC_API_URL=http://localhost:4000Base URL: http://localhost:4000
All endpoints except /api/auth/register and /api/auth/login require a Bearer token in the Authorization header:
Authorization: Bearer <token>
POST /api/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "password123",
"name": "John Doe"
}Response:
{
"user": { "id": "...", "email": "...", "name": "..." },
"token": "jwt-token"
}POST /api/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "password123"
}Response:
{
"user": { "id": "...", "email": "...", "name": "..." },
"token": "jwt-token"
}GET /api/auth/me
Authorization: Bearer <token>GET /api/patients?search=john&limit=20&offset=0
Authorization: Bearer <token>Query Parameters:
search(optional): Filter by name or external IDlimit(optional): Number of results (default: 20, max: 100)offset(optional): Pagination offset (default: 0)
Response:
{
"patients": [...],
"total": 150,
"limit": 20,
"offset": 0
}POST /api/patients
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "John Doe",
"dateOfBirth": "1990-05-15",
"externalId": "MRN-12345",
"metadata": { "insuranceId": "INS-123" }
}GET /api/patients/:id
Authorization: Bearer <token>GET /api/patients/:id/summary
Authorization: Bearer <token>Response includes:
- Patient details
documentCount: Total documentslastDocumentAt: Most recent document dateprocessingDocuments: Documents currently being processed
PUT /api/patients/:id
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "Jane Doe",
"dateOfBirth": "1990-05-15"
}DELETE /api/patients/:id
Authorization: Bearer <token>POST /api/documents
Authorization: Bearer <token>
Content-Type: multipart/form-data
file: <binary>
patientId: "patient-id"
documentType: "DISCHARGE_SUMMARY" (optional)Document Types:
DISCHARGE_SUMMARYLAB_RESULTCONSULTATION_NOTEPRESCRIPTIONRADIOLOGY_REPORTUNKNOWN
GET /api/documents/:id
Authorization: Bearer <token>GET /api/documents/patient/:patientId
Authorization: Bearer <token>DELETE /api/documents/:id
Authorization: Bearer <token>GET /healthResponse:
{
"status": "ok",
"timestamp": "2024-01-15T12:00:00.000Z"
}id: Primary keyemail: Unique emailpasswordHash: Bcrypt hashname: Display namecreatedAt,updatedAt
id: Primary keyuserId: Foreign key to Username: Patient namedateOfBirth: Optional dateexternalId: Optional MRN/external IDmetadata: JSON field for custom data
id: Primary keypatientId: Foreign key to PatientoriginalFilename: Original file namestoragePath: Path in Supabase storagedocumentType: Enum (DISCHARGE_SUMMARY, LAB_RESULT, etc.)status: Processing status (PENDING, PROCESSING, COMPLETED, FAILED)
id: Primary keydocumentId: Foreign key to DocumentextractedData: JSON with extracted fieldsconfidenceScore: AI confidence (0-1)
id: Primary keypatientId: Foreign key to PatienteventType: DIAGNOSIS, MEDICATION_START, PROCEDURE, etc.eventDate: When the event occurreddescription: Event descriptionstructuredData: JSON with event details
Frontend:
- Next.js 16 (App Router)
- TypeScript
- Tailwind CSS
- Framer Motion
- Lucide Icons
Backend:
- Express.js 5
- TypeScript
- Prisma ORM
- PostgreSQL (Supabase)
- Redis + BullMQ (job queues)
- JWT authentication
Infrastructure:
- Supabase (database + file storage)
- Redis (local or hosted)
# Root level
npm run dev # Run both API and web
npm run dev:api # Run only API
npm run dev:web # Run only web
# API (from apps/api)
npm run dev # Development server
npm run build # Build for production
npm run db:push # Push Prisma schema to database
npm run db:studio # Open Prisma Studio
# Web (from apps/web)
npm run dev # Development server
npm run build # Build for productionPrivate - All rights reserved