A comprehensive, multi-tenant laboratory management system built with FastAPI, SQLModel, and PostgreSQL.
- Docker and Docker Compose
- Python 3.11+
- Make (optional, for convenience commands)
git clone <repository-url> cd celuma-backend
docker-compose up -d
curl http://localhost:8000/api/v1/health
- JSON Payloads: All POST endpoints use JSON request bodies for optimal data handling
- Pydantic Schemas: Complete type safety and automatic validation for all endpoints
- Enhanced Authentication: Robust JWT system with token blacklisting
- Auto-generated Documentation: Complete OpenAPI/Swagger documentation
- Comprehensive Testing: Full test suite with automatic cleanup
- Admin User Control: Complete CRUD operations for user management
- User Invitations: Streamlined email-based user onboarding with expiring tokens
- User Profiles: Avatar support for user identification
- Role-Based Access: Support for admin, pathologist, lab_tech, assistant, billing, and viewer roles
- Active Status Management: Enable/disable user access without data loss
- Status Tracking: Complete workflow from DRAFT → IN_REVIEW → APPROVED → PUBLISHED
- Pathologist Review: Dedicated endpoints for report approval and change requests
- Digital Signatures: Pathologist signing with timestamp tracking
- Report Retraction: Ability to withdraw published reports when necessary
- Worklist Management: Dedicated worklist for pathologists to track reports in review
- Audit Trail: Complete logging of all workflow transitions
- Report Templates: JSON-based templates for report structure management
- Template Management: CRUD operations for report templates with active/inactive status
- Service Catalog: Manage pricing and service offerings with validity periods
- Invoice Line Items: Detailed billing with service linkage and quantity support
- Payment Tracking: Automatic invoice status updates based on payments
- Billing Locks: Control report access based on payment status
- Balance Calculations: Automatic tracking of invoice and order balances
- Event Timeline: Complete case history tracking with 16+ event types
- Dashboard: Aggregated statistics and recent activity across the system
- Password Reset: Secure token-based password recovery system
- Tenant Branding: Logo support and active status management
- Enriched APIs: Related data included in responses (branch, patient, order info)
The API is designed with JSON request bodies for all POST endpoints, providing:
- Excellent data validation with Pydantic schemas
- Strong type safety and developer experience
- Consistent API design following REST best practices
- Auto-generated documentation and examples
The project includes a test suite located in the tests/ directory, using pytest with coverage reporting.
# Run unit tests with coverage report make test-unit # Or directly with pytest python3 -m pytest --cov=app --cov-branch --cov-report=term-missing
tests/
├── __init__.py # Package initialization
├── conftest.py # Shared fixtures and configuration
├── test_models.py # Database model tests
├── test_order_comments.py # Order comment and mention tests
├── test_rbac_phase2.py # RBAC system tests
├── test_schemas.py # Pydantic schema validation tests
└── test_security.py # Authentication and security tests
# From project root python run_tests.py # Or with pytest directly python3 -m pytest tests/ # All tests python3 -m pytest tests/test_models.py # Model tests only python3 -m pytest tests/test_rbac_phase2.py # RBAC tests only
- API Endpoints - Complete API reference (JSON updated)
- API Examples - Usage examples with JSON payloads
- Database Schema - Database design and migrations
- Testing Guide - Testing setup and available test suites
- Logging Guide - Iconography and logging guidelines
- Deployment Guide - Complete deployment documentation
- FastAPI: Modern, fast web framework
- SQLModel: SQL databases in Python, designed for simplicity
- PostgreSQL: Robust, production-ready database
- Alembic: Database migration management
- Docker: Containerized deployment
- Pydantic: Data validation and serialization
- Tenant isolation
- Branch management
- User role-based access control
- JWT authentication with token blacklisting
- Comprehensive audit logging
- JSON-first: All POST endpoints use JSON request bodies
- Type-safe: Complete Pydantic schema validation
- Auto-documented: OpenAPI/Swagger documentation
- RESTful: Consistent API design patterns
- Validation: Automatic request/response validation
The project uses a single baseline migration (v1_0_0) that creates the complete schema.
New features are added as additional Alembic revisions on top of this baseline.
Each release is consolidated into one migration before it ships, so the chain records releases rather than the order in which features were developed:
v1_0_0 → v1_1_0 → v1_2_0 → v1_3_0 (head)
v1_3_0 is the whole Céluma 1.3 database delta in one revision —
versioned report templates, the letterhead domain, official-PDF artifact
fields, the publish lock, the notification domain, and the tenant-usage
domain with its reconciliation and threshold state. It replaced the fourteen
revisions the release was developed across, none of which was ever deployed
to staging, production or a customer database.
v1_3_0 is frozen. It is the final Céluma 1.3 database contract; Phase 5
validates it and does not rewrite it. Céluma 1.4's schema evolution begins
from v1_3_0 and is expected to ship as v1_4_0. See
docs/celuma-1.3/pre-phase-5-migration-squash/:
migration-release-contract.md for the numbering rule and the freeze, and
migration-local-database-transition-guide.md if your local database is
stamped at a revision that no longer exists (v1_10_0–v1_13_0).
Migrations run automatically on startup:
- Development:
docker compose up --buildrunsalembic upgrade headviainit_db.sh - GHCR:
docker-compose.ghcr.ymlincludes the same initialization service - Remote DB: All deployment options include automatic migration execution
# Check current migration status alembic current # Create a new migration after model changes alembic revision --autogenerate -m "short description" # Apply all pending migrations alembic upgrade head
Note:
v1_0_0is the baseline.alembic downgrade v1_2_0(rolling the Céluma 1.3 release back) is supported and validated, and destroys every row in the tables 1.3 introduced — the notification history, usage counters, limits, reconciliation history and threshold state. Clinical data is not touched. Downgrading belowv1_0_0is not supported; to reset a local database, drop and recreate it, then runalembic upgrade head.
# Drop and recreate (all data will be lost) docker compose exec db psql -U postgres -c "DROP DATABASE celumadb; CREATE DATABASE celumadb;" docker compose run --rm db-init
# Complete cleanup (removes all data) ./cleanup.sh # This removes: # - All containers # - Database volumes # - Dangling images
celuma-backend/
├── app/ # Main application code
│ ├── api/ # API endpoints
│ ├── core/ # Core configuration
│ ├── models/ # Database models
│ └── schemas/ # Pydantic schemas
├── tests/ # Testing suite
├── alembic/ # Database migrations
├── docker-compose.yml # Development environment
├── Makefile # Development commands
├── requirements.txt # Runtime dependencies (what the production image ships)
└── requirements-dev.txt # Runtime + test dependencies
make help # Show all available commands make setup # Create Python virtual environment make install # Install runtime dependencies only make install-dev # Install runtime + test dependencies (needed for make test-unit) make test-unit # Run unit tests with coverage report make build # Build Docker image make clean # Clean up Docker images and containers
# Database Management ./init_db.sh # Initialize database and run migrations ./cleanup.sh # Complete system cleanup # Deployment ./deploy_remote.sh # Deploy single container with remote database ./start.sh # Start API with database checks (used in containers)
- Health:
GET /api/v1/health - Authentication:
POST /api/v1/auth/login- Flexible login with username or emailPOST /api/v1/auth/register- User registration with optional usernamePOST /api/v1/auth/register/unified- Unified registration (tenant + branch + admin)GET /api/v1/auth/me- Get current user profilePUT /api/v1/auth/me- Update profile and passwordPOST /api/v1/auth/logout- Logout and token blacklistingPOST /api/v1/auth/password-reset/request- Request password reset emailPOST /api/v1/auth/password-reset/verify- Verify reset token validityPOST /api/v1/auth/password-reset/confirm- Set new password with token
- User Management (Admin only):
GET/POST/PUT/DELETE /api/v1/users/- Complete user CRUD operationsPOST /api/v1/users/{id}/toggle-active- Toggle user active statusPOST /api/v1/users/invitations- Send user invitationGET /api/v1/users/invitations/{token}- Get invitation detailsPOST /api/v1/users/invitations/{token}/accept- Accept invitationPOST /api/v1/users/{id}/avatar- Upload user avatar
- Tenants:
GET/POST /api/v1/tenants/- Tenants managementGET /api/v1/tenants/{id}- Get tenant detailsGET /api/v1/tenants/{id}/branches- List tenant branchesGET /api/v1/tenants/{id}/users- List tenant usersPATCH /api/v1/tenants/{id}- Update tenant (Admin)POST /api/v1/tenants/{id}/logo- Upload tenant logo (Admin)POST /api/v1/tenants/{id}/toggle- Toggle tenant active status (Admin)
- Branches:
GET/POST /api/v1/branches/ - Patients:
GET/POST /api/v1/patients/ - Laboratory:
GET/POST /api/v1/laboratory/orders/- Laboratory ordersPOST /api/v1/laboratory/orders/unified- Create order with samplesGET /api/v1/laboratory/orders/{id}- Get order detailsGET /api/v1/laboratory/orders/{id}/full- Get full order detailsPATCH /api/v1/laboratory/orders/{id}/notes- Update order notesGET /api/v1/laboratory/patients/{id}/orders- Patient ordersGET /api/v1/laboratory/patients/{id}/cases- Patient casesGET/POST /api/v1/laboratory/samples/- Samples managementGET /api/v1/laboratory/samples/{id}- Get sample detailsPATCH /api/v1/laboratory/samples/{id}/state- Update sample statePATCH /api/v1/laboratory/samples/{id}/notes- Update sample notesPOST /api/v1/laboratory/samples/{id}/images- Upload sample imageGET /api/v1/laboratory/samples/{id}/images- List sample imagesDELETE /api/v1/laboratory/samples/{id}/images/{image_id}- Delete imageGET /api/v1/laboratory/orders/{id}/events- Order timeline eventsPOST /api/v1/laboratory/orders/{id}/events- Add timeline eventGET /api/v1/laboratory/samples/{id}/events- Sample timeline events- Comments/Conversation:
GET /api/v1/laboratory/orders/{id}/comments- Get order commentsPOST /api/v1/laboratory/orders/{id}/comments- Add commentGET /api/v1/laboratory/users/search- Search users for mentions
- Labels:
GET /api/v1/laboratory/labels/- List labelsPOST /api/v1/laboratory/labels/- Create labelDELETE /api/v1/laboratory/labels/{id}- Delete label
- Collaboration:
PUT /api/v1/laboratory/orders/{id}/assignees- Update order assigneesPUT /api/v1/laboratory/orders/{id}/reviewers- Update order reviewersPUT /api/v1/laboratory/orders/{id}/labels- Update order labelsPUT /api/v1/laboratory/samples/{id}/assignees- Update sample assigneesPUT /api/v1/laboratory/samples/{id}/labels- Update sample labels
- Reports:
GET/POST /api/v1/reports/- Reports managementPOST /api/v1/reports/{id}/new_version- Create new report versionGET /api/v1/reports/{id}/versions- List report versionsPOST /api/v1/reports/{id}/pdf- Upload report PDFGET /api/v1/reports/{id}/pdf- Get report PDF presigned URL- Workflow (Pathologist endpoints):
POST /api/v1/reports/{id}/submit- Submit for reviewPOST /api/v1/reports/{id}/approve- Approve reportPOST /api/v1/reports/{id}/request-changes- Request changesPOST /api/v1/reports/{id}/sign- Sign and publishPOST /api/v1/reports/{id}/retract- Retract published reportGET /api/v1/reports/worklist- Get pathologist worklist
- Templates:
GET /api/v1/reports/templates/- List report templatesGET /api/v1/reports/templates/{id}- Get template detailsPOST /api/v1/reports/templates/- Create templatePUT /api/v1/reports/templates/{id}- Update templateDELETE /api/v1/reports/templates/{id}- Delete template
- Billing:
GET/POST /api/v1/billing/invoices/- Invoices managementGET /api/v1/billing/invoices/{id}- Get invoice detailsGET /api/v1/billing/invoices/{id}/full- Get invoice with items and paymentsPOST /api/v1/billing/invoices/{id}/items- Add invoice itemGET/POST /api/v1/billing/payments/- Payments managementGET /api/v1/billing/orders/{id}/balance- Get order payment balanceGET/POST/PUT/DELETE /api/v1/billing/catalog/- Service catalog management
- Dashboard:
GET /api/v1/dashboard/- Get dashboard statistics and recent activity
- Portal:
- Physician Portal (requires
portal:physician_accesspermission):GET /api/v1/portal/physician/orders- List physician's requested ordersGET /api/v1/portal/physician/orders/{id}/report- Get published report PDF
- Patient Portal (public, no auth required):
GET /api/v1/portal/patient/report- Get report by patient access code
- Physician Portal (requires
- RBAC:
GET /api/v1/rbac/permissions- List all available permissionsGET /api/v1/rbac/roles- List all roles with their permissionsGET /api/v1/rbac/users/{id}/roles- Get roles assigned to a userPUT /api/v1/rbac/users/{id}/roles- Update roles assigned to a user
- Worklist:
GET /api/v1/me/worklist- Get current user's worklist (assignments + reviews)GET /api/v1/assignments- List assignments for a given itemPOST /api/v1/assignments- Create a new assignmentDELETE /api/v1/assignments/{id}- Remove an assignmentGET /api/v1/report-reviews- List report reviews for an orderPOST /api/v1/report-reviews/{id}/decision- Submit approve/reject decision
- Flexible Login: Users can authenticate using either username or email
- Optional Username: Username field is completely optional during registration
- Multi-tenant Support: All authentication is tenant-scoped
- JWT Tokens: Secure stateless authentication with configurable expiration
- All endpoints require
Authorization: Bearer <token>except:GET /,GET /health,GET /api/v1/health,POST /api/v1/auth/login,POST /api/v1/auth/register,POST /api/v1/auth/register/unified.
# Start with local PostgreSQL database docker-compose up --build # This automatically: # 1. Creates PostgreSQL database # 2. Runs all Alembic migrations # 3. Starts the API server
# Use GHCR compose file with local database docker-compose -f docker-compose.ghcr.yml up --build # This includes: # - Database initialization service # - Automatic migrations # - Production-ready configuration
# Option 1: Using docker-compose with remote database export DATABASE_URL="postgresql://user:pass@host:5432/dbname" export JWT_SECRET="your-secret-key" docker-compose -f docker-compose.remote-db.yml up --build # Option 2: Deploy single container with remote database export DATABASE_URL="postgresql://user:pass@host:5432/dbname" export JWT_SECRET="your-secret-key" ./deploy_remote.sh
Create a .env file or set environment variables:
# Required DATABASE_URL=postgresql://user:pass@host:5432/dbname JWT_SECRET=your-super-secret-jwt-key # Optional (with defaults) JWT_EXPIRES_MIN=480 APP_NAME=celuma ENV=production # AWS S3 (required for image uploads) AWS_ACCESS_KEY_ID=your-aws-access-key AWS_SECRET_ACCESS_KEY=your-aws-secret AWS_REGION=us-east-1 S3_BUCKET_NAME=your-bucket-name # Media / CDN (optional) # Use CloudFront or CDN base URL for permanent public links MEDIA_PUBLIC_BASE_URL=https://dxxxxxxxxxxxx.cloudfront.net # Presigned URL expiry in seconds (used if generating presigned links) MEDIA_PRESIGNED_EXPIRE_SECONDS=3600 # Custom S3 endpoint (LocalStack/MinIO) # S3_ENDPOINT_URL=http://localhost:4566 # CORS — comma-separated list of allowed frontend origins. Defaults to the # local Vite dev/preview ports. Must never include a bare "*": combined with # allow_credentials=True (required for authenticated requests), Starlette # would send Access-Control-Allow-Origin: * on every response, which # browsers reject for credentialed requests. List the exact production # frontend origin(s) here in production. CORS_ALLOWED_ORIGINS=https://app.your-domain.com
- API health:
GET /api/v1/health - Database connectivity: Built into health endpoint
# Docker logs docker logs celuma-backend-api-1 # Or via docker compose docker compose logs -f api
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass:
make test - Submit a pull request
- All new features must include tests
- Run the full test suite before submitting:
make test - Maintain or improve test coverage
[Add your license information here]
For issues and questions:
- Review API examples
- Check the API reference
- Open an issue in the repository
Built with ❤️ for modern laboratory management