Skip to main content

Itinera — Architecture Reference

Last updated: February 26, 2026 — Phase 2 complete; nuqs URL filters added

Developer reference for file structure, API endpoints, environment variables, domain setup, and deployment. Stable — changes infrequently.


File Structure

# Base path: /Users/cernenchii/Documents/Itinera
/src
├── proxy.ts # CSRF origin check + 2FA enforcement (renamed from middleware.ts in Next.js 16)
├── app/
│ ├── page.tsx # Landing page (unauthenticated)
│ ├── layout.tsx # Root layout
│ ├── not-found.tsx # Custom 404 page
│ ├── (auth)/
│ │ ├── layout.tsx # Auth layout wrapper
│ │ ├── login/ # Login page
│ │ ├── two-factor/ # 2FA verification page (shown during login)
│ │ ├── invite/[code]/ # Invite registration page
│ │ └── change-password/ # Forced password change page
│ ├── (legal)/
│ │ ├── layout.tsx # Shared legal layout
│ │ ├── privacy/ # Privacy Policy
│ │ ├── terms/ # Terms of Service
│ │ └── support/ # Support page (FAQ, contact)
│ ├── (dashboard)/
│ │ ├── layout.tsx # Sidebar + top-nav shell
│ │ ├── dashboard/ # Main dashboard
│ │ ├── routes/
│ │ │ ├── page.tsx # Routes list
│ │ │ ├── new/ # Create route
│ │ │ └── [id]/ # Route detail
│ │ ├── fleet/ # Fleet management + live map
│ │ ├── analytics/
│ │ │ ├── page.tsx # Fleet fuel analytics
│ │ │ └── [truckId]/ # Per-truck drill-down
│ │ ├── notifications/ # Notification center
│ │ ├── reports/ # Reports page (5 types)
│ │ ├── settings/ # App settings + team + invites
│ │ └── profile/ # User profile (includes 2FA setup)
│ └── api/
│ ├── auth/ # NextAuth + register + invite + 2FA validate
│ ├── routes/ # Route CRUD + waypoints + generate + deviations
│ ├── fleet/ # Samsara vehicles/drivers/locations/status
│ ├── users/ # User management (admin)
│ ├── profile/ # Profile + password + 2FA setup/verify/disable
│ ├── invites/ # Invite generation + listing
│ ├── settings/ # App settings + stats + test connections
│ ├── fuel-prices/ # Fuel price store + near-route query
│ ├── uploads/ # File uploads (Excel)
│ ├── geocode/ # Location search
│ ├── notifications/ # Notification list + read tracking + delete
│ ├── reports/ # Route/activity/deviation/fuel-stop exports
│ └── cron/ # Deviation + fuel alert cron endpoint
├── components/
│ ├── dashboard/
│ │ ├── fuel-price-upload.tsx # Excel fuel price uploader
│ │ └── low-fuel-alerts.tsx # Fuel alert widget
│ ├── routes/
│ │ ├── route-editor.tsx # Waypoint management sidebar
│ │ ├── route-detail-panel.tsx # Route info display
│ │ ├── assignment-card.tsx # Driver/vehicle assignment
│ │ ├── deviations-card.tsx # Deviation history display
│ │ ├── fuel-stops-card.tsx # Nearby fuel stops with prices
│ │ └── google-maps-import.tsx # Google Maps URL import
│ ├── maps/
│ │ ├── google-route-map.tsx # Interactive map with draggable polyline
│ │ └── index.ts # Map component exports
│ ├── profile/
│ │ └── TwoFactorSetupCard.tsx # 2FA enable/disable/setup UI
│ ├── layout/
│ │ ├── sidebar.tsx # Navigation sidebar
│ │ ├── top-nav.tsx # Header navigation
│ │ └── notification-bell.tsx # Notification indicator with per-user unread count
│ ├── providers/
│ │ └── auth-provider.tsx # NextAuth session provider
│ ├── theme-provider.tsx # Theme context (system/light/dark)
│ ├── theme-toggle.tsx # Theme toggle dropdown
│ └── ui/ # Radix-based UI primitives (shadcn)
├── lib/
│ ├── auth.ts # NextAuth config + login rate limiting + 2FA JWT flow
│ ├── prisma.ts # Prisma client singleton
│ ├── rate-limit.ts # In-memory rate limiter (→ rate-limiter-flexible in Phase 1)
│ ├── totp.ts # TOTP implementation (RFC 6238/4226)
│ ├── two-factor-store.ts # In-memory 2FA verification proof store
│ ├── validation.ts # Shared input validation (email, name, password, role)
│ ├── samsara.ts # Samsara API helpers
│ ├── report-utils.ts # Shared report helpers (CSV/XLSX export, CSV injection prevention)
│ ├── notifications.ts # Notification service (createFuelAlert, createDeviationAlert, etc.)
│ ├── telegram.ts # Telegram Bot API helper
│ ├── route-utils.ts # Polyline decode + haversine distance calculations
│ └── utils.ts # General utilities (cn, etc.)
├── types/
│ └── next-auth.d.ts # Auth type extensions (mustChangePassword, twoFactorPending)
└── prisma/
└── schema.prisma # Database schema

Touch all files in a group when working on that system.

Deviation & Fuel Alert Monitoring (Cron)

  • src/app/api/cron/check-deviations/route.ts — cron entry point
  • src/lib/notifications.ts — single source of truth for FUEL_LOW and ROUTE_DEVIATION
  • src/lib/telegram.ts — Telegram Bot API
  • src/lib/route-utils.ts — polyline decoding, haversine distance, off-route detection
  • src/lib/samsara.ts — Samsara API helpers
  • prisma/schema.prisma — Notification, RouteDeviation, AppSettings models
  • docs/CRON_SETUP.md — production cron configuration

Notification System (UI)

  • src/app/api/notifications/route.ts — list + mark all read
  • src/app/api/notifications/[id]/route.ts — mark single read (PATCH), delete (DELETE admin)
  • src/app/(dashboard)/notifications/page.tsx — notification center UI
  • src/components/layout/notification-bell.tsx — bell icon with per-user unread count
  • src/components/dashboard/low-fuel-alerts.tsx — fuel alert banner on dashboard
  • prisma/schema.prisma — Notification, NotificationRead models

2FA Flow

  • src/proxy.ts — enforces 2FA pending state, CSRF on /api/auth/two-factor/
  • src/lib/auth.ts — issues JWT with twoFactorPending: true
  • src/lib/totp.ts — TOTP implementation
  • src/lib/two-factor-store.ts — in-memory verification proof store
  • src/lib/rate-limit.ts — rate limiter (5 attempts/15 min on all 2FA endpoints)
  • src/app/api/auth/two-factor/validate/route.ts — validates TOTP/recovery during login
  • src/app/api/profile/two-factor/setup/route.ts — generates secret + QR (password-gated)
  • src/app/api/profile/two-factor/verify/route.ts — verifies code, enables 2FA, returns recovery codes
  • src/app/api/profile/two-factor/disable/route.ts — disables 2FA (password-gated)
  • src/app/(auth)/two-factor/page.tsx — 2FA verification page shown mid-login
  • src/components/profile/TwoFactorSetupCard.tsx — step-based setup UI on profile page
  • src/types/next-auth.d.ts — JWT/session type extensions

Route Management

  • src/app/(dashboard)/routes/new/page.tsx — create route form
  • src/app/(dashboard)/routes/[id]/page.tsx — route detail page
  • src/app/api/routes/route.ts — list + create
  • src/app/api/routes/[id]/route.ts — get, update, delete
  • src/app/api/routes/[id]/waypoints/route.ts — list + add waypoints
  • src/app/api/routes/[id]/waypoints/[waypointId]/route.ts — update/delete single waypoint
  • src/app/api/routes/[id]/waypoints/reorder/route.ts — reorder waypoints
  • src/app/api/routes/[id]/generate/route.ts — generate Google Maps URL + activate
  • src/app/api/routes/[id]/fuel-alert/route.ts — manual fuel low alert trigger
  • src/components/routes/route-editor.tsx — waypoint management sidebar
  • src/components/routes/assignment-card.tsx — driver/vehicle assignment
  • src/components/routes/fuel-stops-card.tsx — nearby fuel stops with prices
  • src/components/maps/google-route-map.tsx — interactive map
  • src/lib/route-utils.ts — polyline decode + distance calculations

Fuel Prices

  • src/app/api/fuel-prices/route.ts — store (POST) + list (GET)
  • src/app/api/fuel-prices/near-route/route.ts — find stations near a route
  • src/components/dashboard/fuel-price-upload.tsx — Excel upload widget
  • src/components/routes/fuel-stops-card.tsx — displays stations on route detail

Authentication & Session

  • src/lib/auth.ts — NextAuth config, login rate limiting, session/JWT callbacks, 2FA pending flow
  • src/proxy.ts — CSRF protection, 2FA enforcement, route protection
  • src/lib/validation.ts — shared input validation
  • src/lib/rate-limit.ts — PostgreSQL-backed rate limiter (Prisma RateLimit model)
  • src/types/next-auth.d.ts — session/JWT type extensions

Fleet (Samsara)

  • src/lib/samsara.ts — Samsara API helpers
  • src/app/api/fleet/vehicles/route.ts — vehicle list
  • src/app/api/fleet/drivers/route.ts — driver list
  • src/app/api/fleet/locations/route.ts — live GPS positions
  • src/app/api/fleet/status/route.ts — connection status
  • src/app/(dashboard)/fleet/page.tsx — fleet management + live map UI

Reports

  • src/app/(dashboard)/reports/page.tsx — reports UI
  • src/app/api/reports/routes/route.ts — route summary + detail export
  • src/app/api/reports/activity/route.ts — activity log export
  • src/app/api/reports/deviations/route.ts — deviation report export
  • src/app/api/reports/fuel-stops/route.ts — fuel stop usage export
  • src/lib/report-utils.ts — date validation, CSV/XLSX generation, CSV injection prevention

Settings

  • src/app/api/settings/route.ts — get/update company name, Samsara key, Telegram chat ID
  • src/app/api/settings/stats/route.ts — data overview counts
  • src/app/api/settings/test-samsara/route.ts — test Samsara connection
  • src/app/api/settings/test-telegram/route.ts — test Telegram bot
  • src/app/api/users/route.ts + [id]/route.ts — user management (admin)
  • src/app/api/invites/route.ts — invite generation + listing
  • src/app/(dashboard)/settings/page.tsx — settings UI

API Endpoints

Authentication

MethodEndpointDescription
POST/api/auth/[...nextauth]NextAuth handlers
POST/api/auth/registerRegister with invite code (rate limited)
GET/api/auth/invite/[code]Validate invite code
POST/api/auth/two-factor/validateValidate TOTP/recovery code during login

Invites

MethodEndpointDescription
GET/api/invitesList all invites with status
POST/api/invitesGenerate new invite link

Routes

MethodEndpointDescription
GET/api/routesList all routes
POST/api/routesCreate new route
GET/api/routes/[id]Get route details
PATCH/api/routes/[id]Update route
DELETE/api/routes/[id]Delete route (admin only)
POST/api/routes/[id]/generateGenerate Google Maps URL + activate
GET/POST/api/routes/[id]/waypointsManage waypoints
PATCH/DELETE/api/routes/[id]/waypoints/[waypointId]Update/delete waypoint
POST/api/routes/[id]/waypoints/reorderReorder waypoints
GET/api/routes/[id]/deviationsRoute deviation history
POST/api/routes/[id]/fuel-alertTrigger fuel low alert

Fleet (Samsara)

MethodEndpointDescription
GET/api/fleet/statusSamsara connection status
GET/api/fleet/vehiclesVehicle list
GET/api/fleet/driversDriver list
GET/api/fleet/locationsLive GPS positions

Users & Profile

MethodEndpointDescription
GET/api/usersList users (admin)
POST/api/usersCreate user (admin)
PATCH/api/users/[id]Update user / reset password (admin)
DELETE/api/users/[id]Delete user (admin)
GET/PATCH/api/profileUser profile
POST/api/profile/passwordChange password
POST/api/profile/two-factor/setupGenerate 2FA secret + QR (password-gated)
POST/api/profile/two-factor/verifyVerify TOTP, enable 2FA, return recovery codes
POST/api/profile/two-factor/disableDisable 2FA (password-gated)

Reports

MethodEndpointDescription
GET/api/reports/routesRoute summary or detail (JSON/CSV/XLSX)
GET/api/reports/activityActivity log (JSON/CSV/XLSX)
GET/api/reports/deviationsDeviation report (JSON/CSV/XLSX)
GET/api/reports/fuel-stopsFuel stop usage (JSON/CSV/XLSX)

Other

MethodEndpointDescription
GET/POST/api/settingsApp settings
GET/api/settings/statsData overview counts
POST/api/settings/test-samsaraTest Samsara connection
POST/api/settings/test-telegramTest Telegram bot
GET/POST/api/fuel-pricesFuel price data
POST/api/uploadsFile uploads (Excel)
GET/api/geocode/searchLocation search
GET/api/notificationsNotification list (per-user read status)
POST/api/notificationsMark all read (per-user)
PATCH/api/notifications/[id]Mark single notification read
DELETE/api/notifications/[id]Delete notification (admin only)
POST/api/cron/check-deviationsDeviation + fuel alert cron job

Environment Variables

# Database
DATABASE_URL="postgresql://..."

# NextAuth
NEXTAUTH_SECRET="..."
NEXTAUTH_URL="https://app.getitinera.com"

# Google Maps (Maps, Geocoding, Directions) — moving to HERE in Phase 4
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY="..."

# Samsara API key — stored in DB via AppSettings (not in env)

# Telegram Bot
TELEGRAM_BOT_TOKEN="..."

# Added in Phase 1:
# SENTRY_DSN="..." — Bugsink self-hosted DSN
# RESEND_API_KEY="..." — Transactional email

# Added in Phase 4:
# HERE_API_KEY="..." — HERE Routing, Geocoding, Fuel Prices APIs

# Added in Phase 6:
# MINIO_ENDPOINT="..."
# MINIO_ACCESS_KEY="..."
# MINIO_SECRET_KEY="..."
# MINIO_BUCKET="itinera"

Domain Architecture

DomainPurposeTunnel →Traefik
getitinera.comPublic landing pageCloudflare Pages (no tunnel)
www.getitinera.comRedirectCloudflare Pages (no tunnel)
app.getitinera.comItinera platform (Next.js)https://localhost:443HTTPS router, Let's Encrypt cert
coolify.getitinera.comCoolify deployment UIhttps://localhost:443HTTPS router, Let's Encrypt cert
secrets.getitinera.comInfisical secret managementhttps://localhost:443HTTPS router, Let's Encrypt cert
status.getitinera.comUptime Kuma status pagehttp://localhost:80HTTP router only
errors.getitinera.comBugsink error trackinghttp://localhost:80HTTP router only
storage.getitinera.comMinio file storageTBD (Phase 6)
workflows.getitinera.comn8n automationTBD (Phase 7)

DNS: All subdomains are CNAMEs → efa99bf0-1a82-43ed-8b32-06e454745179.cfargotunnel.com. Managed in Cloudflare DNS. Droplet has no inbound ports open (SSH only via DigitalOcean firewall).

TLS: Cloudflare handles TLS at the edge for all domains. Internally, traffic flows over HTTP or HTTPS depending on the Coolify domain setting:

Tunnel routing rules

There are two routing patterns and it's important to keep them consistent:

Pattern A — https://localhost:443 with noTLSVerify: true Used for: app, coolify, secrets

  • Coolify domain is set to https:// → Traefik generates both HTTP and HTTPS routers
  • Traefik obtains a Let's Encrypt cert via HTTP-01 challenge
  • The tunnel sends traffic to port 443; noTLSVerify: true skips cert validation since it's an internal cert
  • These domains had their certs issued when port 80 was still open; cert auto-renews via ACME

Pattern B — http://localhost:80 Used for: status, errors

  • Coolify domain is set to http:// → Traefik generates only an HTTP router on port 80
  • No Let's Encrypt cert is issued (HTTP-01 challenge fails — port 80 inbound is blocked by firewall)
  • Cloudflare provides HTTPS to the end user; internally traffic is plain HTTP
  • This is safe because the Cloudflare Tunnel is an encrypted outbound connection

When adding a new subdomain, decide which pattern to use:

  • Use Pattern A if the service was deployed before ports were closed (cert already exists)
  • Use Pattern B for any new service deployed after the firewall was locked down
  • Set the Coolify domain scheme (http:// vs https://) and the tunnel ingress rule to match

Deployment & CI/CD

Current (Phase 1 + 2):

  • Push to master → GitHub Actions builds Docker image on 7GB runner → pushes to ghcr.io/ioncernenchii/itinera:latest
  • Coolify webhook triggered → pulls latest image from ghcr.io → redeploys (seconds, no build)
  • GitHub Actions also runs ESLint + build check (linting step blocks on issues)
  • Rollback: via Coolify UI → Docker Image Tag → select previous :sha-<short> tag

Previous pipeline (pre-Phase 2):

  • Coolify ran multi-stage Dockerfile build locally on droplet (time-consuming, disk overhead)
  • Now: zero builds on droplet, all builds on GitHub Actions 7GB runner (faster, cleaner)

Stack:

  • Hosting: DigitalOcean 4GB droplet, Ubuntu 24.04
  • Orchestration: Coolify v4 with Docker Image build pack
  • Reverse proxy: Cloudflare Tunnel (no exposed ports; Tunnel → Traefik on droplet)
  • Database: PostgreSQL 18 with PostGIS (custom Docker image itinera-postgres:18-postgis; Dockerfile at /data/coolify/databases/pg-postgis/Dockerfile on production droplet; PostGIS 3.6.1 baked in via apk add --no-cache postgis and .so file copying; survives container rebuilds)
  • Registry: GitHub Container Registry (ghcr.io) with pre-built images
  • All env vars: stored in Coolify directly (Infisical as backup/reference only)