# API Architecture and Route Design

This document explains how the API is structured today, how requests move through the stack, and what each route group is responsible for.

Source of truth for the runtime wiring:

- `apps/api/src/app.ts`
- `apps/api/src/modules/*`
- `apps/api/src/middleware/*`
- `apps/api/src/swagger/openapi.ts`

## Runtime Overview

The API is an Express application mounted under `/api/v1` with a few non-versioned utility endpoints:

- `GET /health` returns process health.
- `GET /docs` serves Swagger UI.
- `GET /api/v1/openapi.json` returns the generated OpenAPI document.
- `/storage/*` serves uploaded assets such as logos, hero images, vehicle photos, and reservation/customer documents.

The app boot sequence in `apps/api/src/app.ts` is intentionally ordered:

1. CORS is applied first.
2. storage guards are applied before static serving so private customer license files are never anonymously retrievable.
3. Swagger UI is mounted before Helmet so the UI assets are not blocked by CSP.
4. webhook routes that require raw payload handling are mounted before `express.json()`.
5. Helmet, request logging, JSON parsing, and the module routers are mounted.
6. the centralized error middleware converts validation, Prisma, and application errors into consistent JSON responses.

## Request Lifecycle

Most internal company routes follow the same pattern:

1. Express router receives the request.
2. Zod schemas validate `req.params`, `req.query`, and `req.body` through `parseParams`, `parseQuery`, and `parseBody`.
3. auth middleware resolves the caller identity.
4. tenant middleware resolves the company record.
5. subscription middleware blocks suspended or pending companies where required.
6. role middleware enforces employee or admin permissions.
7. the route handler calls a service function.
8. the service applies business rules and calls a repo or Prisma directly.
9. a presenter may normalize the payload for frontend consumption.
10. `ok()` or `created()` wraps successful responses in `{ "data": ... }`.

Common exceptions:

- `GET /health` and `GET /api/v1/docs` return raw JSON, not the `{ data }` envelope.
- webhook endpoints return minimal receipt payloads.
- some public endpoints return graceful fallback responses if the database is unavailable.

## Security and Access Model

There are four main access patterns.

### Employee JWT

`requireCompanyAuth` validates a Bearer token with `type === "employee"`, loads the employee, and attaches:

- `req.employee`
- `req.company`
- `req.companyId`

This is the default for dashboard/company management routes.

### Tenant Resolution

`requireTenant` reloads the company from `req.companyId` and guarantees the tenant context exists. Company-scoped modules then query by `companyId`.

### Subscription Guard

`requireSubscription` blocks company routes when the company status is `PENDING` or `SUSPENDED`. Public site and marketplace routes are intentionally not behind this guard.

### Role-Based Access Control

Employee roles are hierarchical:

- `OWNER`
- `MANAGER`
- `AGENT`

Admin roles are hierarchical:

- `SUPER_ADMIN`
- `ADMIN`
- `SUPPORT`
- `FINANCE`
- `VIEWER`

### Renter JWT

`requireRenterAuth` validates a Bearer token with `type === "renter"` and attaches `req.renterId`.

`optionalRenterAuth` is used on marketplace routes so public reads still work without a token.

### API Key

`requireApiKey` accepts a company public API key in `x-api-key`. This is the low-friction integration path for public company-site style calls.

## Implementation Pattern

The API codebase is organized per module. The most common pattern is:

- `*.routes.ts`: route definitions and middleware composition
- `*.schemas.ts`: Zod input validation
- `*.service.ts`: business rules and orchestration
- `*.repo.ts`: Prisma access helpers
- `*.presenter.ts`: response shaping

The `vehicles` module is representative:

- `vehicle.routes.ts` mounts auth, tenant, and subscription guards once for the router.
- route handlers validate input and call service functions.
- `vehicle.service.ts` contains business rules such as publish-state normalization and availability calculation.
- `vehicle.repo.ts` owns the Prisma queries and enforces tenant filters in reads.
- `vehicle.presenter.ts` shapes the response returned to clients.

Some modules split specialized workflows into additional services instead of one large file. The reservations module is the clearest example:

- `reservation.service.ts` handles CRUD and list behavior
- `reservation.lifecycle.service.ts` handles confirm/checkin/checkout/close/extend/cancel transitions
- `reservation.inspection.service.ts` handles pickup/dropoff inspections
- `reservation.additional-driver.service.ts` handles approval workflows
- `reservation.photo.service.ts` handles pickup/dropoff photo uploads
- `reservation.document.service.ts` generates contract and billing payloads

## Route Groups

The table below describes the current route groups mounted in `app.ts`.

| Base path | Access | Purpose | Notes |
| --- | --- | --- | --- |
| `/health` | Public | Process health | Non-versioned utility endpoint |
| `/docs` | Public | Swagger UI | Backed by `openapi.ts` |
| `/api/v1/openapi.json` | Public | OpenAPI JSON | Generated from Zod schemas and manual path entries |
| `/api/v1/auth/company` | Public | Company signup | `complete-signup` and `verify-email` now return disabled errors |
| `/api/v1/auth/employee` | Public plus employee JWT | Employee login, password reset, profile, language | Dashboard/staff authentication path |
| `/api/v1/auth/renter` | Renter JWT for profile routes | Renter profile and push token | `signup` and `login` are currently disabled in this codebase |
| `/api/v1/admin` | Admin JWT | Platform operations | Includes company admin, billing, subscriptions, pricing, audit, and admin-user management |
| `/api/v1/marketplace` | Public, optional renter JWT | Marketplace discovery and reservation intake | Designed for discovery and lead capture across companies |
| `/api/v1/site` | Public | White-label company site APIs | Drives each company-branded booking site |
| `/api/v1/subscriptions` | Mixed | Plan listing, webhooks, subscription lifecycle | Public, webhook, and authenticated sub-routers share the same prefix |
| `/api/v1/vehicles` | Employee JWT + tenant + subscription | Fleet management | Includes photos, status, calendar blocks, maintenance, and availability |
| `/api/v1/reservations` | Employee JWT + tenant + subscription | Reservation operations | Central booking lifecycle for internal staff |
| `/api/v1/team` | Employee JWT + tenant + subscription | Employee/team management | Owner-controlled invite, role, activation, removal |
| `/api/v1/customers` | Employee JWT + tenant + subscription | Company CRM and license handling | Includes protected license-image retrieval and approval flows |
| `/api/v1/offers` | Employee JWT + tenant + subscription | Promotional offers | Company marketing and promo codes |
| `/api/v1/analytics` | Employee JWT + tenant + subscription | Dashboard metrics and reports | Includes summary, dashboard, source, and report routes |
| `/api/v1/notifications` | Employee or renter JWT depending on route | Notification inbox and preferences | Separate company and renter surfaces |
| `/api/v1/companies` | Employee JWT + tenant + subscription | Company profile and settings | Brand, domains, contract settings, insurance policies, pricing rules, accounting, API key |
| `/api/v1/payments` | Mixed | Rental payment webhooks and company payment actions | Webhooks are public; operational routes are company-authenticated |
| `/api/v1/reviews` | Employee JWT + tenant + subscription | Review moderation | Company-side review visibility and replies |
| `/api/v1/complaints` | Employee JWT + tenant + subscription | Complaint handling | Internal complaint tracking |
| `/api/v1/webhooks` | Public | External webhook receivers | Currently includes `/clerk` placeholder |

## Functional Breakdown by Module

### Company and employee onboarding

- `POST /api/v1/auth/company/signup` creates the company tenant, owner employee, default subscription state, and related baseline records in one transaction.
- The signup flow generates a unique company slug, hashes the owner password, starts a 90-day trial window, and sends account-created notifications.
- Employee auth supports login, forgot-password, reset-password, profile read, and language updates.

### Company profile and business configuration

The `companies` module owns tenant-level settings:

- company identity
- brand settings and asset upload
- subdomain/custom-domain configuration
- contract settings used by rental documents
- insurance policies
- pricing rules
- accounting settings
- public API key generation/regeneration

This module is where most long-lived company configuration lives.

### Fleet management

The `vehicles` module handles:

- CRUD for vehicles
- publish/unpublish
- explicit status updates
- photo upload and deletion
- availability checks
- monthly vehicle calendar events
- manual calendar blocks
- maintenance logs

Uploads are persisted through the storage service, then surfaced under `/storage/*`.

### Reservations and rental workflow

The reservation aggregate is the center of the operational API.

Important transitions:

1. create draft reservation
2. confirm reservation after license checks
3. check in and move the reservation to `ACTIVE`
4. check out and mark the reservation `COMPLETED`
5. close the reservation operationally after post-rental tasks are done

The lifecycle service also handles:

- extensions with conflict checks
- cancellations
- vehicle status synchronization
- review token generation
- review request email dispatch on close

The reservations module also owns:

- contract and billing payload generation
- pickup/dropoff inspections
- additional-driver approval
- pickup/dropoff photo upload

### Customer CRM and license compliance

Customers are company-scoped CRM records, even when a renter identity also exists. The `customers` module supports:

- customer CRUD
- flag/unflag flows
- license image upload and protected retrieval
- license validation and manager approval

This is intentionally separate from renter identity because one renter may interact with multiple companies while each company still needs its own operational customer record.

### Marketplace and public site

The public surface is split in two modules on purpose.

`marketplace` is the cross-company discovery layer:

- featured/public offers
- marketplace cities
- listed companies
- vehicle search
- marketplace reservation intake
- review submission by token
- company public pages under `/:slug`

`site` is the white-label company booking API:

- company brand payload
- published vehicle catalog
- booking options
- date-range availability
- promo validation
- booking creation
- payment initialization
- booking lookup
- company contact form

Both modules deliberately include graceful degradation paths when the database is unavailable so public pages can fail softer than internal operations.

### Payments

Rental payments are company-side operational payments, distinct from SaaS subscription billing.

The `payments` module handles:

- AmanPay and PayPal rental webhooks
- listing payments by company or reservation
- initializing online charges
- capturing PayPal orders
- recording manual payments
- refunding successful online payments

Payment success updates both the payment record and the reservation paid amount.

### Subscriptions and SaaS billing

The `subscriptions` module owns the platform billing lifecycle:

- public plan/provider/feature listing
- company subscription read endpoints
- trial start
- checkout
- plan changes
- cancellation/resume/reactivation
- provider webhooks
- admin overrides

It also exposes background-job style functions for:

- trial expiration
- payment-pending timeout
- past-due timeout
- suspension timeout
- period-end cancellation

### Notifications

Notifications are multi-channel and multi-audience:

- company inbox
- renter inbox
- unread counts
- preferences per type and channel
- notification history

Templates and preference records live in the database; delivery orchestration lives in `services/notificationService.ts`.

### Admin surface

The admin router is broad because it covers platform operations across multiple domains:

- admin authentication and 2FA
- company listing, inspection, status changes, deletion, impersonation
- renter blocking/unblocking
- platform metrics
- notification inspection
- audit log access
- admin-user and permission management
- billing account and billing invoice operations
- pricing config, plan features, and promotions
- subscription overrides and extensions
- marketplace homepage configuration

This is the only route group allowed to work across tenants.

## Important Workflow Examples

### 1. Company signup

`POST /api/v1/auth/company/signup`

- validates the payload with Zod
- checks for duplicate company and owner email addresses
- generates a unique slug
- hashes the owner password
- creates the tenant, owner employee, and initial subscription state in one transaction
- sends localized account-created notifications

### 2. Public booking from a company site

`POST /api/v1/site/:slug/book`

- resolves the company from the slug
- verifies vehicle availability for the requested date range
- upserts the company-scoped customer record
- computes total days and base rental price
- applies promo code discount if present
- applies pricing rules
- stores a draft reservation
- attaches reservation insurance snapshots and additional-driver snapshots
- triggers license validation flags

Payment is then started with `POST /api/v1/site/:slug/booking/:id/pay`.

### 3. Reservation lifecycle after booking

- reservation starts in `DRAFT`
- staff confirms it after license compliance checks
- vehicle status moves to `RESERVED`
- checkin moves reservation to `ACTIVE` and vehicle to `RENTED`
- checkout moves reservation to `COMPLETED`, records mileage, and generates a review token
- close marks the operational workflow complete and can send the review request email

## Error Handling and Response Shape

The API standardizes error handling in `http/errors/errorMiddleware.ts`.

Special handling exists for:

- Zod validation errors -> `400 validation_error`
- Prisma `P2025` -> `404 not_found`
- Prisma `P2002` -> `409 conflict`
- custom `AppError` subclasses -> explicit status and machine-readable code

Successful route handlers usually return:

```json
{
  "data": {}
}
```

Common deviations:

- `/health`
- `/api/v1/docs`
- webhook receipt payloads
- file downloads such as admin invoice PDFs

## Documentation Artifacts

There are two documentation layers in the codebase:

1. runtime API docs from Swagger/OpenAPI at `/docs` and `/api/v1/openapi.json`
2. this markdown document, which explains design decisions, route grouping, and request flow

The OpenAPI file is useful for request/response contracts, but it is not yet a perfect mirror of every newer route. This document should be updated together with `app.ts`, route files, and the OpenAPI generator whenever route groups change.
