# Tarivo Technical Architecture

Document status: Active architecture baseline
Version: 2.0
Primary runtime: Laravel API and Next.js web application

## 1. Executive Summary

Tarivo uses a separated frontend and backend architecture. The Laravel backend is
the system of record for identity, authorization, rides, trips, payments,
notifications, uploads, AI results, offline sync and audit logs. The Next.js
frontend is a presentation and interaction layer. It never owns canonical
business state.

This design exists so the same backend can serve the web application today and
native mobile applications later without rewriting the domain.

## 2. System Context

Clients:

- Next.js web app
- Future passenger mobile app
- Future driver mobile app
- Future partner/admin clients

Backend services:

- Laravel REST API under `/api/v1`
- Laravel Sanctum for API authentication
- Laravel Reverb for realtime events
- Queue workers for AI, uploads, notifications, webhooks and slow jobs
- Scheduler for cleanup, expiry and operational tasks

Data and infrastructure:

- MySQL 8 as system of record
- Redis for cache, queues, rate limiting and realtime support
- Laravel Storage for files
- External providers for maps, payments, AI, email and SMS

## 3. Architecture Decisions

### ADR-001: API-first Backend

Decision: all business capabilities are exposed through versioned Laravel APIs.

Reason: web and future mobile apps must share the same rules and workflows.

Consequence: no database access from frontend code, no business decisions in UI
components and no frontend-only permissions.

### ADR-002: Event-driven Realtime

Decision: realtime behavior uses Laravel Reverb with private and presence
channels.

Reason: ride alerts, location, chat, calls and notifications require immediate
delivery without polling.

Consequence: every realtime channel must be authorized and every broadcast event
must contain only sanitized data.

### ADR-003: Persist Critical Notifications

Decision: critical operational alerts are stored before being broadcast.

Reason: a driver or passenger must not lose important state because a browser
tab refreshed or a websocket dropped.

Consequence: notifications have priority, persistence, read, acted and expiry
fields.

### ADR-004: WebRTC Calls with Backend-controlled Signaling

Decision: audio and video calls use WebRTC-compatible signaling through
authorized backend channels. The backend persists call sessions but does not
store media.

Reason: call state must be auditable while media should remain peer-to-peer or
provider-managed.

Consequence: signaling messages are short-lived, authorized and scoped to a call
session.

### ADR-005: Offline Sync Through Idempotent Actions

Decision: eligible offline actions are sent as sync actions with idempotency
keys.

Reason: unstable connectivity must not duplicate trip starts, completions,
messages or location events.

Consequence: backend revalidates state transitions and returns clear conflicts.

### ADR-006: External APIs Behind Services

Decision: Google Maps, Stripe, OpenAI, email and SMS are accessed only through
backend integration services when secrets, billing-sensitive logic or business
state are involved.

Reason: provider changes, failures and secrets must be isolated from domain
logic and frontend code.

Consequence: integrations are logged, retried where safe and configured by
environment variables.

## 4. Backend Module Boundaries

Required Laravel modules:

- Identity: auth, users, roles, permissions, verification
- Driver: onboarding, availability, documents, vehicles
- Ride: requests, matching, trip lifecycle, cancellation
- Tracking: location ingestion, route, ETA and broadcasting
- Communication: conversations, messages, read receipts, calls and signaling
- Notifications: persistent alerts, sound keys, read and acted state
- Uploads: file validation, storage, ownership and lifecycle
- AI: OCR, image analysis, document validation and support summaries
- Payments: cash, wallet, Stripe, webhooks and invoices
- Sync: offline action intake, idempotency and conflict handling
- Support: tickets, complaint context and admin intervention
- Audit: important user, admin, ride, payment and security events
- Integrations: provider clients and external API logs

Controllers must remain thin. Services own business rules. Form Requests own
validation. Policies own authorization. API Resources own response formatting.
Jobs own slow or retryable work. Events own realtime broadcasts and domain
notifications.

## 5. Frontend Module Boundaries

Required Next.js modules:

- Auth and session
- Dashboard shell
- Passenger ride booking
- Driver console
- Active trip map
- Notification center and persistent alert surface
- Chat and call interface
- Upload and document status
- Wallet and payment status
- Offline queue and sync status
- Support center
- Admin operations

Frontend rules:

- Use App Router and TypeScript strict mode.
- Prefer Server Components for read-only screens.
- Use Client Components only for interactive state, realtime subscriptions,
  maps, calls, upload progress and offline queue behavior.
- Server state belongs in API service functions and TanStack Query when useful.
- Shared UI belongs in reusable components, not page-level duplication.
- UI components may show state but must not decide business outcomes.

## 6. Critical Runtime Flows

### Ride Request

Passenger creates ride request. Backend validates city, pickup, destination,
vehicle type and payment method. Eligible drivers receive persistent realtime
notifications. The first valid driver acceptance creates a trip and updates
driver availability.

### Realtime Tracking

Driver sends location updates to the API. Backend authenticates, authorizes,
rate limits, stores recent points and broadcasts sanitized location events to
authorized trip participants.

### Chat and Calls

Messages are persisted before broadcast. Calls create a call session, send a
persistent ringing notification, then exchange WebRTC signaling through a
presence channel scoped to the call session.

### Upload and AI

Files are validated and stored privately where appropriate. AI jobs are queued.
Results are stored as structured records and can be reviewed by admins before
changing sensitive driver status.

### Offline Sync

Frontend stores offline-capable actions locally with an idempotency key. When
network returns, actions are submitted in order. Backend checks duplicate keys,
validates the current domain state and applies, rejects or marks conflict.

### Payment Callback

Stripe sends a webhook. Backend verifies signature, stores the event ID, applies
payment state changes idempotently, updates wallet or transaction records,
generates invoice where valid and notifies the user.

## 7. Security Baseline

- Every protected endpoint requires authentication.
- Every domain mutation requires authorization.
- Every request body is validated through Form Requests.
- Sensitive endpoints are rate limited.
- Uploads are validated by type, size and MIME.
- External API keys stay in environment variables.
- Raw provider errors are logged internally and translated to safe API errors.
- Audit logs record important ride, payment, role, document and admin actions.
- Broadcast payloads contain only the fields required by the client workflow.

## 8. Observability Baseline

The platform must log:

- Authentication events
- Ride lifecycle changes
- Driver availability changes
- Payment and webhook state changes
- Upload and AI processing failures
- Offline sync conflicts
- External API failures
- Admin role and settings changes

Logs must contain correlation identifiers when available and must not contain
secrets, tokens, passwords, raw card data or full payment provider payloads
unless explicitly required for secure webhook audit storage.

## 9. Runtime Processes

Production requires these independently supervised processes:

- PHP-FPM or equivalent PHP runtime for Laravel
- Web server or reverse proxy with TLS termination
- Laravel queue worker for default jobs
- Laravel queue worker for payment and webhook jobs
- Laravel queue worker for AI and upload jobs
- Laravel scheduler
- Laravel Reverb websocket process
- Next.js production server or static/standalone deployment, depending on the
  chosen hosting model

Long-running workers must be restartable without losing idempotency. Failed jobs
must be inspectable and retryable where safe.

## 10. Environment Configuration

Required environment groups:

- App: `APP_ENV`, `APP_KEY`, `APP_URL`, `FRONTEND_URL`
- Database: `DB_CONNECTION`, `DB_HOST`, `DB_DATABASE`, `DB_USERNAME`,
  `DB_PASSWORD`
- Redis and queues: `REDIS_HOST`, `REDIS_PASSWORD`, `QUEUE_CONNECTION`
- Realtime: `REVERB_APP_ID`, `REVERB_APP_KEY`, `REVERB_APP_SECRET`,
  `REVERB_HOST`, `REVERB_PORT`, `REVERB_SCHEME`
- Mail and SMS: provider keys and sender configuration
- Maps: Google Maps server key and optional browser-restricted frontend key
- Payments: Stripe secret key, publishable key and webhook secret
- AI: OpenAI API key and model configuration
- Storage: private disk path, public disk path and optional object storage

No secret may be committed. `.env.example` files must document names and safe
placeholder values only.

## 11. Deployment Shape

The backend must be deployable independently from the frontend.

Production deployment must include:

- Dependency installation without dev secrets
- Database migration step with rollback plan
- Queue restart after deployment
- Reverb restart after deployment
- Scheduler verification
- Health check for API, database, Redis, queues and Reverb
- Backup strategy for database and private files
- Log retention and audit retention policy

Static build artifacts are deployment outputs, not the source of truth for the
application. They should not replace the real `backend/` and `frontend/` source
trees.
