Skip to main content
The Fleet Management System is a monorepo with three packages. A Node.js/Express backend serves a REST API that both client apps consume over HTTP using JWT authentication.
packages/
  backend/    # REST API — Node.js + Express + Sequelize + PostgreSQL
  mobile/     # Technician app — React Native + Expo
  desktop/    # Admin app — Electron + React (Vite)

System components

Backend API

Node.js + Express + SequelizeHandles all business logic, authentication, file uploads, PDF generation, and email delivery. Exposes a REST API under /api. Connects to PostgreSQL for persistence and Nodemailer (SMTP) for outbound email.Runs on port 3001 by default.

Mobile app

React Native + ExpoUsed by field technicians to view their assigned vehicle, capture the four required inspection photos (front, rear, left, right), record mileage and damage notes, and submit inspection reports.Communicates with the backend exclusively over the REST API.

Desktop app

Electron + React + ViteUsed by fleet administrators to manage fleets, vehicles, technician accounts, assignments, and maintenance schedules. Admins also receive inspection PDF reports by email when a technician submits an inspection.Runs as a native desktop window; the renderer loads from a Vite dev server (port 5174) during development.

How the apps communicate

Both client apps talk to the backend using standard HTTP requests. There is no WebSocket layer or shared database access from the clients — all data flows through the REST API.

Authentication

Every protected endpoint requires a Bearer token in the Authorization header. Tokens are issued on login, expire after 8 hours, and are signed using JWT_SECRET from the backend environment.
Authorization: Bearer <token>
File uploads (inspection photos) are sent as multipart/form-data. Uploaded files are served statically from /uploads.

User roles

There are two roles in the system. Role is stored on the Users table and checked by the backend on every protected request.
RoleAccess
AdminFull CRUD on fleets, vehicles, technicians, assignments, maintenance types, and vehicle maintenance records. Can view all inspections across all fleets. Can also log in to the mobile app with elevated access.
TechnicianRead access to their own assignment and assigned vehicle. Can submit inspections and mark maintenance as complete on their assigned vehicle only.

Database schema

PostgreSQL is used for all persistence. Sequelize manages the models and associations. The key tables are:
TableDescription
UsersAll accounts (admins and technicians). Stores email, hashed password, full name, role (admin | technician), and active status.
FleetsNamed groups of vehicles. Belong to a specific admin user.
VehiclesIndividual vehicles in a fleet. Stores license plate, brand, model, year, odometer unit, insurance and license expiry dates, and document file paths.
AssignmentsLinks a technician to a vehicle for a date range. Enforces one active assignment per vehicle and one per technician at any time.
InspectionsInspection reports submitted by technicians. Stores mileage, damage notes, photo file paths (front, rear, left, right), and a generated PDF path.
MaintenanceTypesDefines reusable maintenance categories (e.g., oil change) with a service interval in kilometers or days and a flag marking it as mandatory.
VehicleMaintenanceTracks maintenance events for a specific vehicle: which type, date performed, next due date, and completion status. Mandatory overdue records block new inspections.

Key data flows

Technician login and inspection

1

Login

The technician submits their email and password to POST /api/auth/login. The backend verifies the bcrypt-hashed password, generates a JWT, and returns it.
2

Fetch assignment

The mobile app calls GET /api/technician/assigned-vehicle with the JWT. The backend returns the technician’s active assignment and the associated vehicle record.
3

Submit inspection

The technician captures four photos, records the odometer reading and any damage notes, and posts the form to POST /api/inspections as multipart/form-data.Before accepting the submission, the backend checks that no mandatory maintenance is overdue for the vehicle. If overdue maintenance exists, the submission is rejected with a 409 Conflict error.
4

PDF generation and email

On a successful submission, the backend generates a PDF report using PDFKit (including the inspection data and photo thumbnails) and emails it to the fleet admin via Nodemailer. The PDF is also saved to disk and the path stored on the inspection record.

Admin fleet management

Administrators use the desktop app to manage the full lifecycle of fleet resources:
  • Create and edit fleets and assign vehicles to them.
  • Register vehicles and upload registration and insurance documents.
  • Create technician accounts and create assignments linking a technician to a vehicle.
  • Define maintenance types and view per-vehicle maintenance history.
  • View all inspection reports and download the generated PDFs.
All of these operations are CRUD endpoints on the REST API, authorized with the admin’s JWT.
You can use the Mailpit web UI at http://localhost:8025 during local development to inspect all outbound emails, including inspection PDF attachments.

Build docs developers (and LLMs) love