Multi-Tenant Pharmacy SaaS Platform
Multiple pharmacies operating securely on one platform with subscription billing, analytics, and tenant isolation.
Overview
A multi-tenant SaaS platform enabling independent pharmacies to operate securely on shared infrastructure — with subscription billing, tenant isolation, analytics, and automated workflows.
Business Context
Independent pharmacies could not afford custom software but needed inventory control, billing, and analytics. A SaaS model allowed them to share infrastructure while keeping data completely isolated.
The Real Problem
Each pharmacy either used generic software that did not fit pharmacy workflows, or nothing at all. Subscription management was manual, analytics were nonexistent, and there was no way to centrally compare performance across locations.
Who Experienced the Problem
Independent pharmacy owners, pharmacists, and staff who needed affordable, specialized software without building it themselves.
Pain Points
- Generic POS software did not handle pharmacy-specific workflows
- Custom software was unaffordable for independent pharmacies
- No analytics to compare performance across locations
- Manual subscription management created billing errors and churn
- No data isolation — pharmacies did not trust shared platforms
Project Goals
- Build a multi-tenant platform with complete data isolation
- Automate subscription billing with plan-based feature gating
- Provide centralized analytics with per-tenant partitioning
- Support pharmacy-specific workflows (inventory, prescriptions, compliance)
- Reduce per-pharmacy onboarding from weeks to minutes
Requirements Gathering
Interviewed independent pharmacy owners and identified that affordability and data isolation were the two biggest barriers. This drove the decision toward a multi-tenant SaaS model with database-level isolation rather than separate instances per tenant.
Architecture Decisions
- Chose shared database with row-level isolation over database-per-tenant for cost efficiency
- Django middleware for automatic tenant resolution from subdomain or header
- PostgreSQL row-level security policies enforced at the database layer
- Subscription billing as a separate Django app within the project
- React SPA with tenant-aware API client that injects tenant context
Database Schema
API Design
- All endpoints tenant-scoped via middleware — no tenant ID in URL
- Subscription management endpoints with idempotent billing
- Analytics endpoints with per-tenant query scoping
- Webhook endpoints for payment provider callbacks
Authentication Strategy
JWT authentication with tenant context embedded in the token. RBAC enforced per tenant — a user in one tenant cannot access another tenant’s data even with a valid token. Session invalidation on subscription cancellation.
Technology Selection
- Django — mature multi-tenant patterns and robust ORM
- React — component reuse across tenant-customized UIs
- PostgreSQL — row-level security for guaranteed isolation
- Stripe — subscription billing with webhook integration
Trade-offs
- Shared database over database-per-tenant: lower cost but requires careful isolation
- Row-level security over app-level filtering: stronger isolation but more complex migrations
- SPA over SSR: simpler tenant customization but worse initial SEO
Challenges
- Ensuring no cross-tenant data leaks in shared queries
- Subscription downgrades with active sessions needing graceful handling
- Feature gating that was flexible enough for custom plans but maintainable
- Analytics queries that aggregated across tenants for platform admins without leaking to individual tenants
Solutions
- PostgreSQL row-level security policies as the isolation enforcement layer
- Grace period for downgraded subscriptions with feature deprecation warnings
- Feature flag service keyed by subscription plan ID
- Platform admin analytics with separate, aggregated data store
Performance Optimizations
- Tenant-scoped database queries with indexed tenant IDs
- Cached analytics dashboards per tenant with event-driven invalidation
- Background workers for subscription billing to avoid blocking requests
- Pre-computed analytics snapshots for dashboard load speed
Security Considerations
- Row-level security at the database layer as the primary isolation control
- JWT with tenant context and server-side validation on every request
- RBAC per tenant with role inheritance
- Audit logging for all cross-tenant admin actions
- Input validation and parameterized queries throughout
Scalability Planning
Shared database handles current scale. Can migrate to database-per-tenant for large pharmacies. Analytics snapshots can move to a columnar store. Billing workers scale horizontally via queue.
Deployment Strategy
Dockerized Django backend and React frontend deployed via CI/CD. Database migrations include row-level security policy updates. Blue-green deployments to avoid disrupting active pharmacy sessions.
Lessons Learned
- Tenant isolation must be enforced at the database level, not just the application level
- Subscription billing edge cases deserve their own module
- Feature flags tied to subscription plans need a clear source of truth
- Row-level security is powerful but makes migrations significantly harder
Future Improvements
- White-label theming per tenant
- Marketplace for pharmacy-specific integrations
- AI-assisted drug interaction checking
- Mobile app for pharmacists on the floor
Final Business Outcome
A live multi-tenant SaaS platform serving 20+ pharmacies with zero data leaks, automated subscription billing, and per-tenant analytics — reducing onboarding from weeks to 10 minutes.
Technologies
Architecture
- Django backend with multi-tenant middleware and row-level isolation
- React SPA frontend with tenant-aware state management
- PostgreSQL with tenant ID on every table and row-level security
- Subscription billing engine with plan-based feature gating
- RBAC across pharmacy owner, pharmacist, and staff roles
- Centralized analytics with per-tenant data partitioning