Skip to content
Currently BuildingFull-Stack SaaS

OpsPilot

Field-service operations, organized from request to payment.

Technologies

  • Next.js
  • React
  • TypeScript
  • NestJS
  • PostgreSQL
  • Drizzle ORM
  • Better Auth
  • Turborepo
  • Bun
  • Tailwind CSS
  • shadcn/ui
  • Swagger

01 — Problem

Operations scattered across tools

Small field-service businesses — HVAC, plumbing, electrical, appliance repair, and similar trades — often run on WhatsApp, phone calls, paper notes, spreadsheets, calendars, and separate invoicing tools.

That fragmentation creates real operational failure modes: customer records live in one place and requests in another; jobs lose context when they are scheduled; technicians lack the latest details; completion does not reliably produce an invoice; payments slip; follow-ups never happen.

  • Customer management without a single source of truth
  • Requests that get lost between channels
  • Jobs disconnected from intake context
  • Scheduling that fights calendars and chat threads
  • Technician coordination by verbal handoff
  • Work tracking that stops at “done” in a message
  • Completion without a clean handoff to billing
  • Invoices delayed or rebuilt from memory
  • Payments forgotten or hard to reconcile
  • Follow-ups that depend on someone remembering

02 — Solution

One operational lifecycle

OpsPilot connects the full loop so a customer request can become a scheduled job, executed work, an invoice, a payment, and a follow-up — inside one multi-tenant system.

  1. Customer
  2. Request
  3. Job
  4. Schedule
  5. Technician
  6. Work
  7. Completion
  8. Invoice
  9. Payment
  10. Follow-up

03 — Features

What exists in the repository

Feature claims below are grounded in the current NestJS modules, Drizzle schema, and Next.js surfaces. Product vision items that are not shipped yet are listed separately.

Implemented

  • Authentication

    Email/password auth via Better Auth on the NestJS API, with login and signup UI in the Next.js app.

  • Authorization

    Organization-scoped membership with OWNER, ADMIN, DISPATCHER, and TECHNICIAN roles enforced in API services.

  • Organizations & team invites

    Multi-tenant organizations, member management, and invitation accept flow.

  • Customers

    CRUD APIs for organization-owned customer records (contact, address, status).

  • Requests

    Service-request intake with priority, source, preferred timing, and review statuses.

  • Jobs

    Jobs created from accepted requests, with status lifecycle from draft through completion or cancellation.

  • Scheduling

    Schedule and reschedule endpoints set scheduled windows and location on jobs (API-first; no calendar UI yet).

  • Technicians

    Technician profiles and job assignment / reassignment with overlap checks.

  • Work & completion

    Progress updates, notes, photo uploads (local disk storage), activity timeline, and job completion summaries.

  • Invoices

    Invoice creation from completed work, line items, send, and void flows.

  • Payments

    Payment recording against invoices, including refund handling (online gateway success not accepted from the client alone).

  • Follow-ups

    Feedback and maintenance-reminder follow-ups with due dates and status tracking.

  • Dashboard shell

    Authenticated dashboard layout, organization switching, role-aware sidebar, and placeholder operational overview.

  • Automation, analytics & audit

    Rule-based automation engine, analytics endpoints, customer notifications, and audit logging APIs.

Planned / still building

  • Full CRUD screens for jobs, customers, requests, invoices, and related modules (sidebar routes exist; pages are still being built)
  • Calendar / dispatch board UI for scheduling
  • Google OAuth (button present, marked coming soon)
  • Payment gateway–backed online checkout
  • AI request intake, AI scheduling assistance, and operations assistant from the product vision
  • Channels such as WhatsApp / SMS automation beyond the current notification model

04 — Architecture

Stack from the codebase

  • Turborepo + Bun

    Workspace orchestration for apps/* and packages/* with cached lint, typecheck, test, and build pipelines.

  • Next.js web

    App Router frontend with Tailwind CSS and shadcn/ui. Auth UI, onboarding, invitations, and dashboard shell are in place.

  • NestJS API

    Modular Nest controllers/services for customers, service requests, jobs, technicians, invoices, payments, notifications, automation, analytics, and audit.

  • PostgreSQL + Drizzle ORM

    Hosted Supabase PostgreSQL with Drizzle schemas, RLS-enabled tables, and committed SQL migrations. The web app does not connect to the database.

  • Authentication

    Better Auth with Drizzle adapter; Nest integration via @thallesp/nestjs-better-auth session guards.

  • Authorization

    x-organization-id scoped requests plus membership/role checks in services (managers vs technicians, etc.).

  • APIs & docs

    REST endpoints with class-validator DTOs and Swagger documentation for the operational surface area.

  • Background work & storage

    In-process automation scheduler (no BullMQ). Job photos use a swappable FileStorage abstraction with local disk today.

05 — Monorepo

Shared code, clear boundaries

OpsPilot is a Bun + Turborepo workspace. Applications own runtime concerns; packages own shared UI and tooling. That split keeps the API and web app independently deployable while sharing types, lint rules, and components as the product scales.

  • apps/web

    Next.js App Router UI — auth, onboarding, dashboard shell, design system

  • apps/api

    NestJS HTTP API — domain modules, Drizzle schema/migrations, Better Auth, Swagger

  • packages/ui

    Shared React primitives consumed by the web app

  • packages/eslint-config

    Shared ESLint configuration for web packages

  • packages/typescript-config

    Shared TypeScript bases across the workspace

06 — Domain Model

Entities that exist in schema

The Drizzle schema models a multi-tenant operational graph. Users authenticate, belong to organizations, and operate on customers through service requests, jobs, assignments, invoices, payments, and follow-ups. Supporting tables cover notes, photos, activity, notifications, automation, and audit logs.

  1. User
  2. Organization
  3. Customer
  4. Service Request
  5. Job
  6. Schedule
  7. Technician
  8. Work
  9. Completion
  10. Invoice
  11. Payment
  12. Follow-up

Schedule is represented on the job (scheduledStart / scheduledEnd). Technicians connect through job_assignment. Work artifacts live in notes, photos, and activity rows. There is no separate fictional entity invented for this page.

07 — Engineering Decisions

Choices visible in the implementation

  • Monorepo

    Keeps the Nest API and Next UI in one repo so domain types, tooling, and shared UI evolve together as the product grows.

  • NestJS backend

    Module boundaries map cleanly onto operational domains (jobs, invoices, automation) with DI-friendly services and tested controllers.

  • PostgreSQL

    Relational model fits multi-tenant organizations, jobs, assignments, invoices, and payments with strong integrity constraints.

  • Drizzle ORM

    TypeScript-first schema colocated with the API, SQL migrations, and RLS-aware table definitions — the active ORM in the codebase.

  • API-first domain workflow

    Core operational loop is implemented and authorized in the API first; the web UI is catching up with auth/shell screens before full CRUD pages.

  • Better Auth + org roles

    Session auth at the edge of the API, then organization membership and role checks for business actions.

  • Validation & testing

    DTO validation with class-validator; API unit and e2e tests with Jest/Supertest; CI lint/typecheck/test/build via Turborepo and GitHub Actions.

  • Scalability posture

    Tenant isolation by organizationId, indexed operational tables, swappable file storage, and automation designed around persisted executions rather than fire-and-forget side effects.

08 — UI / UX

Auth and shell first

No product screenshots are shown here because the repository does not ship marketing or capture assets for the operational screens yet. Inventing mockups would misrepresent the build.

What is in the web app today: login and signup with a split marketing panel, onboarding for organization setup, invitation acceptance, a role-aware dashboard shell with organization switching, and a design-system showcase. Domain CRUD routes are linked in navigation ahead of their pages — an intentional shell-before-modules approach.

UX priorities so far: clear auth entry, tenant context always visible, and role-filtered navigation so technicians and owners do not see the same control surface.

09 — Design Docs

Documentation in the repository

Links point at existing files in the OpsPilot repository. There is no separate fabricated PRD, database, or API design doc beyond what is checked in.

10 — Currently Building

Active development

OpsPilot is actively being developed. The API already covers the core operational loop; the web experience is expanding from authentication and shell into full operational screens.

Progress is described in terms of shipped modules and open UI work — not invented percentage complete metrics.

11 — What I Learned

Engineering and product lessons

  • Domain modeling

    Field service is a lifecycle, not a flat CRUD list — requests, jobs, assignments, invoices, and follow-ups need explicit relationships.

  • Workflow-driven design

    Status transitions and schedule/assign/complete endpoints encode the real operating loop instead of generic update handlers alone.

  • API architecture

    Modular Nest services with organization scoping keep multi-tenant boundaries enforceable at every write path.

  • Authn / authz

    Session authentication is necessary but not sufficient — membership and role checks decide who can schedule, invoice, or act as a technician.

  • Database design

    Enums, foreign keys, unique job-per-request constraints, and indexes on status/schedule fields mirror how dispatchers actually query work.

  • Monorepo architecture

    Shared tooling and packages reduce friction as the web UI and API ship on different cadences toward the same product.

  • Reusable frontend architecture

    Auth layout, org providers, design-system primitives, and a role-aware shell create a stable base for upcoming operational screens.

  • Product thinking

    Building the operational loop end-to-end in the API first makes the UI work concrete — screens attach to real workflows, not invented dashboards.

From request to payment, still shipping.

Explore the repository for the live schema and API surface, or return to selected work on the portfolio.