Exequtech OS
Multi-tenant field-service SaaS — job cards, quoting, billing and assets in a windowed desktop-OS browser interface. Part of the team; I lead the web platform.
- role
- Web platform lead
- status
- live
- date
- 2025 — present
- links
- live ↗
- React 19
- TypeScript
- Apollo
- Vite
- Go
- GraphQL
- PostgreSQL
- Docker
┌─ jobs ───┐┌─ billing ─┐ │ ▪▪▪ #142 ││ R 12 400 │ └──────────┘└───────────┘ ┌─ clocking ───────────┐ │ 08:42 ▶ on site │ └──────────────────────┘ [start] 1:jobs 2:billing
- commits · web platform
- 561
- clients · one API
- 3
The product
Exequtech OS is the field service management (FSM) 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'm part of the Exequtech team 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. Gerhard van Staden builds on the web platform with me — and with years of web development and client consulting behind him, he's also the one who mentors me in both. 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're 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.