PaulRentACar Docs

System Architecture

High-level system design and technical architecture

This page describes the technical architecture of the PaulRentACar CRM — the technology stack, frontend and backend design, multi-tenant model, workflow engine, and data flow patterns.


Architecture Overview

PaulRentACar CRM follows a modern three-tier architecture with clear separation of concerns: a Next.js frontend, a Python FastAPI backend, and a PostgreSQL database. The system is designed for multi-tenant isolation, horizontal scaling, and enterprise-grade security.

High-level architecture — frontend communicates with the backend API, which enforces business rules and persists data to PostgreSQL.

Technology Stack

LayerTechnologyPurpose
FrontendNext.js 16 (React 19)Server-rendered React application with App Router
UI FrameworkTypeScript, Tailwind CSSType safety and utility-first styling
DocumentationFumadocsMDX-based documentation site (this site)
Backend APIPython 3.12+ / FastAPIAsync REST API with automatic OpenAPI docs
ORMSQLAlchemy 2.0Database models, relationships, and query building
ValidationPydantic v2Request/response schemas and data validation
DatabasePostgreSQL 16Primary data store with JSONB support
MigrationsAlembicVersion-controlled database schema migrations
AuthenticationJWT (HS256)Access tokens (60 min) + refresh tokens (7 days)
Password HashingbcryptSecure one-way password hashing
UUIDsuuid4Primary keys for all business entities
ContainerizationDocker ComposeLocal development and deployment orchestration

Frontend Architecture

The frontend is a Next.js 16 application using the App Router, TypeScript, and a feature-based folder structure.

App Router Structure

DirectoryPurpose
app/Route pages organized by module (login, dashboard, customers, vehicles, etc.)
app/login/Login page and authentication flow
app/dashboard/Main dashboard with KPIs and widgets
app/customers/Customer list, detail, create, and edit pages
app/vehicles/Vehicle list, detail, status, and maintenance pages
app/reservations/Reservation list, create, confirm, and manage pages
app/contracts/Contract checkout, active, check-in, and history pages
app/billing/Invoices, payments, deposits, and credit notes
app/complaints/Complaint intake, tracking, and resolution pages
app/compliance/Compliance tasks, legal cases, and corporate accounts
app/admin/Users, roles, permissions, tenants, branches, workflows, pricing

Component Architecture

DirectoryPurpose
components/ui/Base UI primitives — buttons, inputs, modals, badges, cards, tables
components/layout/App shell — sidebar, header, content area, breadcrumbs
components/forms/Form builders for customer, vehicle, reservation, contract, and billing forms
components/tables/Reusable data tables with sorting, filtering, pagination, and row actions
components/workflow/Workflow status badges, action buttons, timeline, task inbox, approval panel
components/audit/Audit log timeline and change history displays
features/Domain feature modules — auth, customers, vehicles, reservations, contracts, billing, admin
lib/Shared utilities — API client, auth helpers, permission checks, constants
hooks/Custom React hooks for data fetching, form handling, and permission checks
types/TypeScript type definitions for all API entities

Frontend Design Principles

  • Server components for static content and data fetching where possible
  • Client components for forms, tables, modals, and interactive elements
  • Permission-aware rendering — UI elements are hidden based on the user's role permissions
  • Central API client — all HTTP calls go through a single configured client with auth headers
  • Automatic token refresh — expired access tokens are refreshed transparently
  • Responsive layout — works on desktop (1920px) and tablet (768px) with mobile card views

Backend Architecture

The backend follows a layered service pattern with clear boundaries between concerns:

Request → Route → Dependency Injection → Service → Repository → Model → Database

Backend Layer Responsibilities

LayerDirectoryResponsibility
Routesbackend/app/api/routes/Thin HTTP handlers — parse request, call service, return response. No business logic here.
Dependenciesbackend/app/api/deps.pyReusable FastAPI dependencies — get current user, check permissions, verify tenant access
Servicesbackend/app/services/Business logic and orchestration — validate rules, execute workflows, coordinate transactions
Repositoriesbackend/app/repositories/Database access layer — query construction, filtering, pagination, bulk operations
Modelsbackend/app/models/SQLAlchemy ORM models — table definitions, relationships, indexes, constraints
Schemasbackend/app/schemas/Pydantic request/response models — validation rules, field types, nested structures
Securitybackend/app/security/JWT generation/validation, password hashing, permission checking
Corebackend/app/core/Configuration, logging, error handling, constants
Databasebackend/app/db/Session management, base model, migration support

API Design Pattern

All endpoints follow a consistent REST design with a standard response envelope:

{
  "success": true,
  "data": { ... },
  "message": "Operation completed",
  "errors": []
}

Paginated responses include:

{
  "success": true,
  "data": {
    "items": [],
    "page": 1,
    "page_size": 20,
    "total": 0
  }
}

Route Naming Convention

MethodPatternExample
GET/api/{resource}GET /api/customers — list customers
POST/api/{resource}POST /api/customers — create customer
GET/api/{resource}/{id}GET /api/customers/{id} — get customer detail
PUT/api/{resource}/{id}PUT /api/customers/{id} — update customer
DELETE/api/{resource}/{id}DELETE /api/customers/{id} — soft-delete customer
POST/api/{resource}/{id}/{action}POST /api/reservations/{id}/confirm — confirm reservation

Multi-Tenant Model

PaulRentACar CRM is multi-tenant by design. Every business entity includes a tenant_id foreign key, ensuring complete data isolation between tenants.

Tenant Isolation Hierarchy

Tenant
  └── Business Unit
        └── Branch
              └── Users (with explicit access grants)
              └── Vehicles, Customers, Contracts, etc.

Access Control Tables

TablePurpose
tenantsTop-level tenant configuration and settings
business_unitsOrganizational divisions within a tenant (e.g., regions)
branchesPhysical locations within a business unit
usersUser accounts with credentials and profile
rolesNamed role definitions (Branch Manager, Front Desk, etc.)
permissionsGranular permission strings (e.g., reservation:create)
user_rolesMany-to-many: users to roles
role_permissionsMany-to-many: roles to permissions
user_tenant_accessExplicit tenant-level access grants
user_business_unit_accessExplicit business unit-level access grants
user_branch_accessExplicit branch-level access grants

Authorization Flow

Every API request is authorized through this chain:

  1. JWT validation — token is valid and not expired
  2. Token not revoked — token has not been logged out or blacklisted
  3. User exists — the user ID in the token corresponds to an active user
  4. Tenant access — the user has access to the tenant_id in the request
  5. Branch access — the user has access to the branch_id in the request (where applicable)
  6. Permission check — the user has the required permission string (e.g., reservation:create)
  7. Record ownership — the requested record belongs to an allowed tenant/branch

Frontend permission checks are for UI convenience only. Backend authorization is always the source of truth. Never rely solely on hiding buttons in the frontend to prevent unauthorized actions.


Workflow Engine

The platform includes a lightweight, domain-specific workflow engine that manages state transitions, task assignment, approvals, SLA tracking, and audit logging for every major business entity.

Workflow-Managed Entities

EntityTypical Stages
ReservationDraft → Quoted → Pending Confirmation → Confirmed → Converted to Contract / Cancelled / No Show
Rental ContractDraft → Checkout Pending → Active → Extension Requested → Return Pending → Damage Review → Billing Review → Closed / Cancelled
LeadNew → Contacted → Qualified → Converted / Lost
QuoteDraft → Submitted → Approved → Converted / Expired
ComplaintOpen → Assigned → In Progress → Waiting Customer / Escalated → Resolved → Closed
Legal CaseOpen → Under Review → Filed → Hearing Scheduled → Resolved / Closed
Damage AssessmentReported → Assessed → Approved → Repaired / Billed
InvoiceDraft → Issued → Partially Paid → Paid → Overdue / Written Off
Security DepositCollected → Held → Released / Forfeited / Adjusted
RefundRequested → Approved → Paid → Completed
Traffic FineReceived → Charged to Customer → Paid / Disputed
Salik ChargeRecorded → Charged to Customer → Paid
Maintenance RequestSubmitted → Approved → In Workshop → Completed → Vehicle Available
Compliance TaskCreated → Assigned → In Progress → Completed / Overdue
Customer/Driver DocumentUploaded → Under Review → Verified / Rejected

Workflow Engine Components

ComponentPurpose
WorkflowDefinitionNamed workflow type (e.g., "Reservation Workflow")
WorkflowVersionVersioned definition — stages and transitions for a specific version
WorkflowStageNamed state in the workflow (e.g., "Confirmed", "Active")
WorkflowTransitionAllowed move from one stage to another, with action code, required permission, and validation rule
WorkflowInstanceRunning instance — tracks current stage for a specific business entity
WorkflowTaskActionable task created by the workflow (e.g., "Review complaint", "Approve refund")
WorkflowApprovalRequestApproval gate — requires designated approver before transition completes
WorkflowSlaRuleSLA deadline definition — due time per stage, warning thresholds
WorkflowActionLogImmutable audit log — every transition, actor, timestamp, comment, old/new values

Transition Execution Pattern

Every workflow action follows this sequence:

  1. Load the workflow instance for the target entity
  2. Verify tenant and branch access for the current user
  3. Load the current active workflow version
  4. Find the transition matching the current stage and requested action
  5. Check the required permission against the user's role
  6. Run the validation rule (e.g., "can this contract be checked in?")
  7. If approval is required, create an approval request and stop
  8. Execute the status update and workflow instance update in one transaction
  9. Create a workflow action log entry
  10. Create or complete tasks as needed
  11. Calculate the next SLA deadline
  12. Trigger a notification event
  13. Return the updated entity, available actions, and timeline

The workflow engine never silently drops events. Every transition is logged, every approval is recorded, and every SLA breach is captured. This ensures full auditability for compliance and dispute resolution.

Workflow API Endpoints

MethodEndpointPurpose
GET/api/workflows/definitionsList all workflow definitions
GET/api/workflows/instances/{entity_type}/{entity_id}Get workflow instance for a business entity
GET/api/workflows/instances/{id}/timelineGet full timeline of transitions for an entity
GET/api/workflows/instances/{id}/actionsGet available actions for the current stage
POST/api/workflows/instances/{id}/actions/{action_code}Execute a workflow action
GET/api/workflow-tasks/myGet tasks assigned to the current user
POST/api/workflow-tasks/{id}/completeMark a task as complete
GET/api/workflow-approvals/pendingGet approvals pending for the current user
POST/api/workflow-approvals/{id}/approveApprove a workflow request
POST/api/workflow-approvals/{id}/rejectReject a workflow request

Data Flow Diagram

The following describes the end-to-end data flow for a typical rental transaction:

Customer walks in / books online


  ┌─────────────┐
  │   Lead       │  Capture interest, source, assigned agent
  └──────┬──────┘
         │  Convert

  ┌─────────────┐
  │   Quote      │  Pricing engine calculates rates, discounts, extras
  └──────┬──────┘
         │  Accept

  ┌─────────────┐
  │ Reservation  │  Vehicle held, confirmation sent, SLA starts
  └──────┬──────┘
         │  Checkout

  ┌─────────────┐
  │   Contract   │  Vehicle condition recorded, mileage, fuel, signature
  └──────┬──────┘
         │  Active rental period

  ┌─────────────┐
  │  Check-in    │  Return inspection, damage assessment, final mileage
  └──────┬──────┘
         │  Billing

  ┌─────────────┐
  │   Invoice    │  Line items: rental, extras, fines, damage, Salik
  └──────┬──────┘
         │  Payment

  ┌─────────────┐
  │   Payment    │  Allocation across invoices, deposit release
  └──────┬──────┘
         │  Accounting

  ┌─────────────────────┐
  │ Accounting Subledger │  Journal entries, posting batches, export to ERP
  └─────────────────────┘

Each step in this flow is managed by the workflow engine, creating audit log entries and SLA tracking at every transition.


Accounting Subledger

The platform includes a summary journal posting subledger that feeds the tenant's existing accounting/ERP system. This is not a full general ledger — it is an operational subledger that generates balanced journal entries and exports them in CSV, Excel, JSON, or API format.

Accounting Data Flow

Operational Transaction (invoice, payment, deposit, fine, etc.)


  AccountingEvent (immutable record of the financial event)


  AccountingEntry + AccountingEntryLine (debit/credit pairs)


  Subledger Entries (customer, contract, deposit, corporate)


  AccountingPostingBatch (grouped by date, account, cost center)


  Export / Acknowledgement → Tenant's ERP/Accounting System

Posting Batch Lifecycle

StatusDescription
GeneratedBatch created from approved entries
ValidatedDebit/credit balance confirmed, COA mappings verified
Pending ApprovalAwaiting finance approval
ApprovedReady for export
ExportedFile generated or API call made
AcknowledgedExternal system confirmed receipt
FailedExport or validation error — requires retry

Security Architecture

JWT Token Structure

Access Token (expires in 60 minutes):

ClaimPurpose
subUser ID
usernameUser email
display_nameFull name
tenant_idCurrent tenant context
business_unit_idsAllowed business units
branch_idsAllowed branches
rolesAssigned role names
permissionsEffective permission strings
token_type"access"
jtiUnique token ID (for revocation)

Refresh Token (expires in 7 days):

ClaimPurpose
subUser ID
token_type"refresh"
jtiUnique token ID

Security Measures

MeasureImplementation
Password hashingbcrypt with configurable rounds
JWT signingHS256 with configurable secret key
Token revocationRefresh tokens tracked in token_sessions; revoked tokens in revoked_tokens
Tenant isolationEnforced at query level — never trust frontend tenant claims alone
Input validationPydantic schemas validate all incoming data
Audit loggingImmutable log for all critical operations with actor, timestamp, and change summary
Sensitive dataPasswords, tokens, Emirates IDs, passport numbers, and payment card data are never logged
CORSConfigurable allowed origins for frontend-backend communication

Database Design Principles

PrincipleImplementation
Primary keysUUID v4 for all business tables
Audit fieldsEvery table includes created_at, created_by, updated_at, updated_by
Tenant isolationtenant_id on every tenant-owned table
Branch trackingbranch_id on branch-scoped records
Foreign keysEnforced for all business relationships
IndexesOn tenant_id, branch_id, status, date ranges, document numbers, search fields
JSONB usageFlexible metadata and external payloads only — never for core relational data
Status enumsControlled status values via database enums or status tables
History tablesStatus change history for reservations, contracts, vehicles, complaints
MigrationsEvery schema change via Alembic — no manual production edits

Deployment Architecture

Docker Compose (Local Development)

ServicePortPurpose
PostgreSQL5432Primary database
Backend API8000FastAPI application server
Frontend3000Next.js development server

Environment Configuration

VariablePurpose
DATABASE_URLPostgreSQL connection string
JWT_SECRET_KEYSecret key for JWT signing
JWT_ALGORITHMSigning algorithm (HS256)
JWT_ACCESS_TOKEN_EXPIRE_MINUTESAccess token lifetime
JWT_REFRESH_TOKEN_EXPIRE_DAYSRefresh token lifetime
CORS_ALLOWED_ORIGINSAllowed frontend origins
APP_ENVEnvironment name (local, staging, production)

Never commit real secrets or credentials to the repository. Use environment variables and .env files (which are gitignored) for all sensitive configuration.


What's Next?

On this page