A comprehensive, multi-tenant healthcare management system for dialysis centers built with Go, PostgreSQL, and React.
- Multi-tenant Architecture: Secure hospital isolation using PostgreSQL Row Level Security (RLS)
- Comprehensive Patient Management: Demographics, medical history, dialysis sessions, medications
- Clinical Workflows: Session management, vital signs tracking, assessments, complications
- Staff & Scheduling: User management, roles, shift scheduling
- Equipment & Inventory: Dialysis machines, consumables, maintenance tracking
- Billing & Finance: Treatment billing, insurance claims, financial reporting
- Laboratory Integration: Test orders, results tracking, trend analysis
- Reporting & Printing: Monthly Mortality Report (MMR), clinical reports, lab result printouts, patient history printouts
- Platform Administration: Hidden
/platformconsole forsuper_adminusers; hospital admins use Staff Management
- Backend: Go 1.26.1 + Gin web framework
- Database: PostgreSQL 16 with Row Level Security (RLS)
- Frontend: React 19 + Vite (responsive web app)
- Database Tools: sqlc (type-safe queries), goose (migrations)
- Authentication: JWT-based with multi-tenant context
For production, use separate environments for government and private hospitals:
- Government hospitals: one Ministry-hosted national DMS for public dialysis units.
- Private hospitals: a separate private-sector DMS environment, not mixed with government data.
- Database model: one shared PostgreSQL database per environment by default, with hospitals separated by
hospital_idand RLS. - Dedicated deployments: reserve these for large private chains, special legal requirements, or performance needs.
Platform administration belongs at /platform and should be restricted to super_admin users from the Ministry/DMS owner team. Individual hospitals should only use Staff Management for their own staff and roles.
See DEPLOYMENT_MODEL.md for the doctor-friendly deployment explanation and rollout plan.
- Go 1.26.1 or later
- PostgreSQL 16 (via Docker or remote VPS)
- Node.js 18+ and npm (for frontend)
- Docker & Docker Compose (for local PostgreSQL)
Choose one of three setup modes based on your hardware resources:
Best for: Resource-constrained machines, FREE hosting, fast setup
Benefits:
- 100% FREE forever (no credit card)
- 15-30 minute setup
- Frees ~500MB local RAM
- Includes web dashboard
- Automatic backups
Quick Start:
# 1. Sign up at supabase.com (FREE, no credit card)
# 2. Create project, get connection string
# 3. Install goose locally:
go install github.com/pressly/goose/v3/cmd/goose@latest
# 4. Run migrations from local machine:
cd backend
export SUPABASE_CONN="your_connection_string_here"
goose -dir internal/db/migrations postgres "$SUPABASE_CONN" up
# 5. Configure backend:
cp backend/.env.example.supabase backend/.env.supabase
# Edit with Supabase details
cp backend/.env.supabase backend/.env
# 6. Start backend
go run cmd/api/main.go
# 7. Start frontend
cd ../frontend && npm install && npm run devBest for: Machines with sufficient resources, offline development
# Start PostgreSQL
docker-compose up -d
# Copy environment file
cp backend/.env.example backend/.env
# Install dependencies
cd backend && go mod download
# Run migrations
cd backend
go run github.com/pressly/goose/v3/cmd/goose -dir internal/db/migrations postgres "postgres://dms:dms_dev_password@localhost:5432/dms?sslmode=disable" up
# Start backend
go run cmd/api/main.go
# In another terminal, start frontend
cd frontend
npm install
npm run devAccess at: http://localhost:5173
Best for: Production-like setup, faster performance, full server control
Benefits:
- Frees ~500MB local RAM
- Full control over PostgreSQL
- Lower latency than free services
- $5-6/month for VPS
Quick Start (after VPS setup):
# Configure remote database
cp backend/.env.example.remote backend/.env.remote
# Edit .env.remote with your VPS IP and password
# Activate remote configuration
cp backend/.env.remote backend/.env
# Start backend (lightweight, ~50-100MB)
cd backend && go run cmd/api/main.go
# Start frontend
cd frontend && npm run devFor real production, follow the environment split and access model in DEPLOYMENT_MODEL.md.
After running migrations and loading demo data:
- Email / username:
doctor@demo.com - Password:
password123 - Hospital: Demo Dialysis Center (DEMO)
- Username:
bampita-bico - Email:
msbico@gmail.com - Password: local/demo secret, rotate before production
- Access:
http://localhost:5173/platform
These credentials are for local/demo use only. Rotate all passwords before production.
DMS/
├── backend/
│ ├── cmd/api/ # Application entry point
│ ├── internal/
│ │ ├── config/ # Configuration management
│ │ ├── db/
│ │ │ ├── migrations/ # Database migrations (104 files)
│ │ │ ├── query/ # SQL query definitions (sqlc)
│ │ │ ├── sqlc/ # Generated Go code
│ │ │ ├── pool/ # Connection pool
│ │ │ └── tenant/ # Multi-tenant context
│ │ ├── http/
│ │ │ ├── handlers/ # HTTP handlers
│ │ │ ├── middleware/ # JWT auth, CORS, etc.
│ │ │ ├── routes/ # Route registration
│ │ │ └── server/ # HTTP server setup
│ │ └── security/ # JWT, password hashing
│ ├── scripts/ # Utility scripts, demo data
│ └── tools/ # Go tool dependencies
├── frontend/ # React web application
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ └── services/ # API service layer
│ └── public/ # Static assets
└── docs/ # Documentation
# Backend
# Build
cd backend && go build -o bin/api cmd/api/main.go
# Run tests
cd backend && go test ./...
# Create new migration
cd backend && go run github.com/pressly/goose/v3/cmd/goose -dir internal/db/migrations create migration_name sql
# Generate sqlc code (after query changes)
cd backend && go run github.com/sqlc-dev/sqlc/cmd/sqlc generate
# Frontend
# Install dependencies
cd frontend && npm install
# Run dev server
cd frontend && npm run dev
# Build for production
cd frontend && npm run buildDMS uses PostgreSQL Row Level Security (RLS) for tenant isolation:
- JWT Middleware extracts
hospital_idfrom token claims - Transaction Context sets PostgreSQL tenant variables such as
app.hospital_idandapp.current_hospital_id - RLS Policies automatically filter all queries by tenant
Example RLS Policy:
CREATE POLICY patients_isolation ON patients
USING (hospital_id = dms_current_hospital_id());This enforces hospital isolation at the database level and keeps normal hospital users inside their own hospital's records.
- Patient Management: Demographics, contacts, insurance, medical history
- Dialysis Sessions: Treatment tracking, vital signs, complications
- Vascular Access: Catheter and fistula management
- Laboratory: Test orders, results, alerts
- Medications: Prescriptions, administration, tracking
- Staff Management: Users, roles, permissions, scheduling
- Platform Admin: Hidden
/platformpage forsuper_adminusers only - Equipment: Dialysis machines, beds, maintenance schedules
- Inventory: Consumables, suppliers, stock tracking
- Billing: Treatment billing, insurance, payments
- Monthly Mortality Report (MMR) for Ministry reporting
- Printable patient history
- Printable lab results
- Clinical reports (patient outcomes, treatment compliance)
- Operational reports (session volume, equipment utilization)
- Financial reports (revenue, outstanding payments)
Base URL: http://localhost:8080/api/v1
Authentication: Bearer token (JWT)
Key Endpoints:
POST /auth/login- User authenticationGET /patients- List patients (tenant-scoped)POST /patients- Create patientGET /dialysis-sessions- List sessionsPOST /dialysis-sessions- Record session
See backend/internal/http/routes/ for complete endpoint list.
Backend (backend/.env):
APP_ENV=dev # dev or prod
HTTP_ADDR=:8080 # Server listen address
# Database (local or remote)
DB_HOST=localhost # Use VPS IP for remote
DB_PORT=5432
DB_NAME=dms
DB_USER=dms
DB_PASSWORD=dms_dev_password # Use secure password for remote
DB_SSLMODE=disable # Use require for production
DB_MAX_CONNS=4 # Connection pool size
# Security
JWT_SECRET=CHANGE_ME_DEV_ONLY # Must be secure in productionFrontend (frontend/.env):
VITE_API_URL=http://localhost:8080/api/v1- JWT secret is hardcoded (acceptable for development)
- SSL disabled for database connections
- CORS allows localhost origins
- Demo credentials available
- Use environment-specific JWT secrets (rotation recommended)
- Enforce SSL/TLS for all database connections
- Restrict CORS to production domains
- Remove demo data
- Implement rate limiting
- Add API key authentication for external integrations
- Setup monitoring and alerting
Create new migration:
cd backend
go run github.com/pressly/goose/v3/cmd/goose -dir internal/db/migrations create add_feature sqlApply migrations:
goose -dir internal/db/migrations postgres "CONNECTION_STRING" upRollback:
goose -dir internal/db/migrations postgres "CONNECTION_STRING" downLocal (Docker):
docker exec -t $(docker ps -qf "name=dms-postgres") pg_dump -U dms dms > backup.sqlRemote (VPS):
ssh VPS_IP "pg_dump -U dms dms | gzip" > backup.sql.gzFor production backup expectations, see DEPLOYMENT_MODEL.md.
Use Remote Database:
cp backend/.env.remote backend/.envUse Local Database:
docker-compose up -d
cp backend/.env.local backend/.env-
Database Changes:
- Create migration:
goose create feature_name sql - Write SQL with RLS policy
- Apply migration:
goose up
- Create migration:
-
Add Queries:
- Create
backend/internal/db/query/feature.sql - Write sqlc-annotated queries
- Generate:
sqlc generate
- Create
-
Create Handler:
- Add handler in
backend/internal/http/handlers/ - Register route in
backend/internal/http/routes/ - Apply JWT middleware for tenant-scoped endpoints
- Add handler in
-
Frontend Integration:
- Add API service in
frontend/src/services/ - Create components in
frontend/src/components/ - Add page in
frontend/src/pages/
- Add API service in
-
Test:
- Unit tests:
go test ./... - Manual testing: Use frontend or API client
- Verify multi-tenancy isolation
- Unit tests:
cd backend
go test ./... # All tests
go test -v ./internal/http/... # Specific package
go test -run TestName ./... # Specific testcd frontend
npm test # Run tests
npm run test:watch # Watch mode# Start backend and frontend
cd tests
./api_test.sh # Basic API health checkCheck:
- Database is running:
docker psorpsql -h VPS_IP - Environment variables:
cat backend/.env - Connection string format
- Migrations applied:
goose status
Check:
- Backend is running:
curl http://localhost:8080/health - Frontend
.envhas correct API URL - CORS configuration in
backend/internal/http/server/server.go - Browser console for errors
Verify:
- JWT token contains
hospital_idclaim tenant.SetLocalHospitalID()called before queries- RLS policies enabled:
SELECT tablename, rowsecurity FROM pg_tables;
- DEPLOYMENT_MODEL.md: Government/private deployment model, database decision, admin access model, rollout plan
- README_FIRST.md: Quick local start and first-use guide
- frontend/README.md: Frontend development notes
- backend/seeds/README.md: Reference-data seed notes
backend/internal/db/migrations/: Database schema definitions
This is currently a solo project for a specific healthcare facility. If adapting for your use:
- Review multi-tenancy implementation
- Customize clinical workflows for your region
- Update billing logic for your payment model
- Ensure compliance with local healthcare regulations (HIPAA, GDPR, etc.)
Proprietary - All rights reserved
For questions or issues:
- Review DEPLOYMENT_MODEL.md for deployment decisions
- Review migration files for database schema
Status: Backend and frontend in active development; production rollout requires the checklist in DEPLOYMENT_MODEL.md
Last Updated: 2026-05-25