Skip to content

~/projects

Exequtech OS

Multi-tenant field-service SaaS — job cards, quoting, billing and assets in a windowed desktop-OS browser interface. Co-founded; I lead the web platform.

role
Co-founder · Web platform lead
status
live
date
2025 — present
links
live ↗
  • React 19
  • TypeScript
  • Apollo
  • Vite
  • Go
  • GraphQL
  • PostgreSQL
  • Docker
~/projects/exequtech-os/architecture.txt
the operator app is a desktop: windows, taskbar, start menu — one Go API behind it
commits · web platform
561
clients · one API
3

The product

Exequtech OS is the field-service management platform my company builds for South African trade businesses — electricians, plumbers, HVAC and solar installers. Job cards flow into quotations and invoices; technicians clock time and log trips; stock and assets are tracked across sites. One Go API serves three clients: the operator web app, a marketing/auth console, and the Exequ-Jobs Android app.

The interface is an operating system

The operator app doesn't use the usual sidebar-and-tables SaaS layout. It is a desktop: draggable, resizable, snapping windows; a taskbar; a start-menu app grid — a pattern I first built for CogniFlight's ground station. Billing, Jobs, Assets, Contacts, Reports and Settings are "apps" you open side by side — because a dispatcher genuinely works that way, quoting in one window while checking a technician's clock-ins in another.

Under the hood it's React 19 + TypeScript (strict) with the React Compiler, Apollo Client with full codegen typing against the GraphQL schema, virtualized data grids for large tenants, in-browser PDF generation and barcode scanning. A Playwright-based profiling harness tracks heap, CPU and leak baselines so the window manager stays fast as the platform grows.

Tenant isolation at the database layer

Multi-tenancy is enforced where it can't be forgotten: in PostgreSQL itself. This is Brian Felgate's design — he leads our Go backend — and living with it has permanently changed how I think about isolation. Every request opens a transaction and stamps it with the caller's identity via set_config; row-level-security policies and audit triggers then scope every query and record every change.

// Every transaction is stamped with the caller's tenant before any query
// runs; RLS policies enforce isolation below the application layer.
func setAuditContext(ctx context.Context, tx pgx.Tx, data *Ctx) error {
    if data.Tenant != nil {
        if _, err := tx.Exec(ctx,
            "SELECT set_config('audit.tenant_id', $1, true)",
            data.Tenant.ID.String(),
        ); err != nil {
            return fmt.Errorf("failed to set audit.tenant_id: %w", err)
        }
    }
    // member_id, request_id and reason follow the same pattern,
    // feeding the trigger-based audit trail.
    return nil
}

A forgotten WHERE tenant_id = ? in application code therefore leaks nothing — the database refuses to return foreign rows. The same session variables drive an immutable, trigger-based audit log tied to request identity.

Other pieces of what we've built

  • Schema-first GraphQL with two surfaces — a console API for account/tenant management and a tenant API for the business domain, both generated with gqlgen from 18 schema files.
  • A server-side document engine that renders quotations, invoices and job-card reports to PDF through a themeable template system.
  • An MCP server wrapping the API, so AI agents can operate the platform through the same permission model as humans.

My role

I co-founded Exequtech and lead the product's web side: the operator app and the console are primarily my commits (561 on the web platform), and I built the Android client, AI-assisted. Hosting and deployment are Brian's domain — he manages the production environment hands-on and double-checks the security himself, which is deliberate: it's how we keep the risk managed while working with AI this heavily. We build Exequtech in our free time — a small crew testing our limits — but the users are real, so the standards are too. I work with Claude Code daily; the deal is simple: it types fast, I review, decide, and answer for what I ship.