← BACK
03
SaaS Platform — In Development
2025Phase 1 complete
SOURCE CODE ↗

Designing a production-grade SaaS for medical transport operations

This case study shows how I architected a modular platform with a deterministic pricing engine, 146 automated tests, and domain-driven boundaries — built for the Moroccan medical transport market.

SaaS ArchitecturePricing EngineDomain ModulesTest Coverage
5
Problems
7
Decisions
5
Results
coreNext.js 14TypeScript (strict)
backendPostgreSQLPrisma 5ZodNextAuth
features7-Step Pricing EngineImmutable SnapshotsDomain Modules@react-pdf/renderer
systemTailwind CSSRechartsVercel
testingVitest@vitest/coverage-v8
01
THE PROBLEM

What was actually broken

5 pain points identified before writing a single line of code

01

Medical transport operators in Morocco manage scheduling, pricing, and invoicing through disconnected spreadsheets and manual processes

02

No unified system exists for ambulance dispatch, nursing visits, and home care coordination

03

Pricing involves complex rules: urgency levels, staff types, distance zones, time-of-day modifiers, and holidays

04

Invoice generation and payment tracking are manual — reconciliation is error-prone

05

No audit trail or role-based access control for sensitive patient and financial data

02
BUSINESS IMPACT

What this was costing the business

Real cost — not hypothetical risk

01

Pricing errors due to manual calculation of complex modifier stacks (night, weekend, holiday)

02

Lost revenue from untracked services and inconsistent invoicing

03

No visibility into business performance — revenue, collection rates, service distribution

04

Compliance risk from missing audit trails on sensitive medical operations

05

Operator burnout from repetitive admin tasks that could be automated

03
STRUCTURAL DECISIONS

Why these choices — not others

7 deliberate trade-offs

01

Modular DDD-style architecture: each module follows schema → types → repository → service → actions

02

Server Actions for all mutations — no REST API routes for CRUD operations

03

Deterministic pricing engine with 7 explicit steps and immutable snapshot persistence

04

Vitest test suite from Phase 0 — pricing engine at 100% coverage before any UI was built

05

RBAC with admin/assistant roles enforced at every server action boundary

06

Professional PDF invoice engine with @react-pdf/renderer (11 modular components)

07

Layered security: middleware → requireSession → requireAdmin → Zod validation → audit log

04
ARCHITECTURE

How the system is structured

The blueprint that holds everything together

01

8 business modules (clients, patients, services, invoices, payments, pricing, users, dashboard) each with clear boundaries

02

Pricing engine resolves in 7 steps: catalog lookup → base price → distance fees → modifiers → manual override → VAT → snapshot

03

All pricing snapshots are immutable — past invoices always reflect the rules active at service time

04

Custom Design System with 10+ reusable components, consistent tokens, and layout system

05

PostgreSQL with Prisma ORM — 11 tables, relational integrity, and selective queries to prevent over-fetching

05
RESULTS

What changed after shipping

5 measurable improvements

146 automated tests across 9 test files — pricing engine at 100% coverage

128+ source files organized across 8 business modules with clean boundaries

10 development phases completed with full documentation at each stage

Dashboard loads 15 queries concurrently via Promise.all — bundle reduced 96% with dynamic imports

Professional invoice PDFs with itemized lines, pricing breakdown, and status badges

06
ENGINEERING

Technical Deep Dive

How the pricing engine, security model, and module architecture are designed — from schema to deployment.

6.1
DATA MODEL

Data Model

Clientcore

Business or individual client with contact info and billing details

Patientcore

Patient record linked to client — name, condition, transport needs

Servicecore

Scheduled transport or care visit with pricing snapshot

PricingRulecore

Catalog-based pricing rules with urgency and staff type modifiers

Pricing Source of Truth
PricingSnapshotfinancial

Immutable point-in-time capture of pricing calculation

Invoicefinancial

Generated from completed services with itemized lines and PDF export

Paymentfinancial

Multi-method payment record with auto-reconciliation

Useraudit

Admin or assistant with RBAC and session hardening

AuditLogaudit

Automatic logging of all critical operations

Relationships
Client──1 → N──▸Patienthas patients
Patient──1 → N──▸Servicereceives
Service──1 → 1──▸PricingSnapshotcaptures price
Service──N → 1──▸Invoicegenerates
Invoice──1 → N──▸Paymentpaid by
User──1 → N──▸AuditLoglogged by
6.2
ARCHITECTURE

Core Architecture

017-Step Pricing Engine
Medical transport pricing involves complex stacking rules that must be deterministic and auditable
IMPACT: Every service gets a verifiable price trace — no black-box calculations
Step 1: Catalog resolution — match service type, urgency, and staff to pricing rule
Step 2: Base price extraction from matched rule
Step 3: Distance fee calculation by zone (urban, rural, inter-city)
Step 4: Modifier application — night (+%), weekend (+MAD), holiday stacking
Step 5: Manual override check — admin can set fixed price with audit trail
Step 6: VAT calculation on final amount
Step 7: Immutable snapshot creation — persisted alongside the service record
02Modular DDD Architecture
8 business domains must evolve independently without cross-contamination
IMPACT: Adding a new module (e.g. fleet management) follows a known pattern without touching existing code
Each module: schema.ts → types.ts → repository.ts → service.ts → actions.ts
No cross-module imports at the repository level — only through service boundaries
Shared /lib layer for auth, db, audit, validation, and utilities
Server Actions as the only entry point for mutations — typed, validated, audited
03Security Layers
Medical and financial data requires defense in depth — not just login checks
IMPACT: Every request passes through 4 security boundaries before reaching business logic
Layer 1: Next.js middleware — redirect unauthenticated users from /dashboard
Layer 2: requireSession() — validates JWT, checks isActive flag, extracts role
Layer 3: requireAdmin() — blocks assistant users from mutation routes
Layer 4: Zod validation + audit log — every mutation is schema-checked and recorded
04PDF Invoice Engine
Professional invoices are a business requirement — not a nice-to-have
IMPACT: Invoices render server-side with consistent layout, branding, and pricing breakdown
Built with @react-pdf/renderer — 11 modular components
Itemized service lines with per-line pricing breakdown
Status badges (Paid, Partial, Unpaid, Cancelled) embedded in PDF
Auto-generated invoice numbers with company branding
6.3
EXECUTION FLOW

Service Pricing Flow

1
Create service request
Client, patient, service type, urgency, staff type, distance — validated with Zod
2
Resolve pricing rule
Match catalog code + urgency + staff type to active PricingRule
3
Calculate base + distance
Base price from rule + distance fee from zone configuration
4
Apply modifiers
Night auto-detection, weekend check, holiday stacking — each modifier logged
5
Check manual override
Admin can set fixed price — original calculation preserved in snapshot for audit
6
Calculate VAT
Apply configured VAT rate to final amount
7
Persist snapshot
Immutable PricingSnapshot created alongside Service — never modified after creation
NOTEAll 7 pricing steps execute synchronously. The final snapshot is persisted atomically with the service record.
6.4
GUARANTEES

System Guarantees

DATA INTEGRITY
Deterministic Pricing

Same inputs always produce the same price. Every calculation step is logged and snapshot-persisted.

Session Hardening

JWT with 8h maxAge, isActive re-validation on refresh, middleware protection on all dashboard routes.

FINANCIAL ACCURACY
Immutable Price History

PricingSnapshots are never modified. Rule changes don't retroactively alter past service prices.

Payment Reconciliation

Invoice status auto-updates based on payment totals: Unpaid → Partial → Paid. No manual status management.

TRANSACTION SAFETY
Audit Trail

Every create, delete, and cancel operation is logged with userId, role, entity, entityId, and timestamp.

Role Enforcement

RBAC checked at every server action — not just at the UI level. Assistant users cannot access admin mutations.

6.5
DATA FLOW

Data Flow

Pricing Resolution — 7 Steps
11. matchRule(serviceType, urgency, staffType)
22. basePrice = rule.price
33. distanceFee = getZoneRate(zone) × distance
44. modifiers = applyNight() + applyWeekend() + applyHoliday()
55. override? = admin.fixedPrice ?? calculated
66. vat = finalAmount × vatRate
77. snapshot = persist({ steps, total, timestamp })
Module Boundary Pattern
1schema.ts → Zod validation (input/output shapes)
2types.ts → TypeScript interfaces & enums
3repository → Prisma queries (select, create, update)
4service.ts → Business logic + cross-module coordination
5actions.ts → Server Actions (auth + validate + service + audit)
Security Chain
1middleware.ts → redirect if no session cookie
2requireSession() → JWT decode + isActive check
3requireAdmin() → role === 'admin' guard
4zodSchema.parse() → input validation
5auditLog() → { userId, role, action, entity, entityId }
6.6
TRADE-OFFS

Trade-offs

Snapshot-based pricingoverLive rule evaluation

Past invoices always reflect the rules active at service time — rule changes never corrupt history

Server Actions onlyoverREST API routes

Simpler mutation layer with built-in type safety — no API versioning or endpoint management needed

Vitest from Phase 0overTesting after features

Pricing engine was 100% tested before any UI existed — caught 12 edge cases during development

Modular DDD boundariesoverFeature-folder organization

Each module can evolve independently — adding fleet management won't touch pricing or invoicing code

System Principles
01
Deterministic pricingsame inputs always produce the same price, with a full audit trail of each calculation step
02
Immutable snapshotspricing, invoicing, and audit records are never modified after creation
03
Test-first development146 tests existed before the dashboard UI was built
04
Defense in depth4 security layers ensure no unauthorized mutation reaches business logic
What's next?

This is not a tutorial project. It is a production-grade SaaS being built with the same rigor I would apply to a team codebase.

← ALL PROJECTSSTART A CONVERSATION →