PROJECTS / #PROJ-005 / BUILDTRACK
DEPLOYED·SAAS PLATFORM·JUL 2026 — PRESENT

One System for Philippine Contractors: Estimating, Tracking, Payroll and Cash

A multi-tenant web app that connects estimating (BOQ and MTO), project tracking, payroll and cash flow, replacing group chats, notebooks and spreadsheets. Built solo with AI assistance.

PLATFORM
Multi-tenant SaaS (web)
STACK
Next.js 14, TypeScript, MUI, Supabase, TanStack Query, Three.js, Anthropic API
ROLE
Solo designer and developer · AI-assisted
URL
BUILT
Jul–Sep 2026 · about 10 weeks to date
SCALE
~44K lines of TypeScript · 102 migrations · ~35 pages · 145 commits
STATUS
Live · with trial contractors
01

The Challenge of Scattered Tools.

Small and mid-size contractors in the Philippines usually keep the estimate in one spreadsheet, expenses in a notebook, payroll worked out by hand and schedules in group chats. BuildTrack is built for owner-operators and small teams who estimate their own jobs and run their own crews, and their estimates follow local reference material such as Fajardo's tables and Philippine pricing conventions. That material shaped the core of the product.

01_RECONCILIATION

Nothing Reconciles

With the estimate, expenses and payroll in separate places, every number has to be re-checked before anyone trusts it.

02_DELAYS

Delays Cascade Quietly

A foundation pour that slips two weeks doesn't look urgent until every phase after it is two weeks late.

03_COST

The Real Cost Surfaces Late

The true cost of a job usually shows up when the client asks for it.

04_LOCAL_REFERENCE

Estimates Must Follow Local Tables

Take-offs have to use Fajardo's published tables and theoretical formulas, priced from the organization's own rates.

05_TRUSTED_NUMBERS

A Wrong Number Looks Fine

In estimating, a value that is wrong but looks plausible is worse than an error.

06_ISOLATION

Many Companies, One System

Every contractor's data must stay isolated from every other, including demo and view-only accounts.

02

THE SOLUTIONS

The product enforces its important rules at the lowest layer that can hold them: the database for isolation and read-only access, a strict parser for input, and additive migrations for live data.

01 / DATABASE-LEVEL ISOLATION

Tenant Isolation Lives in the Database

Every table carries an organization id with row-level security policies, so a bug in a page can't leak another company's data. Demo accounts are read-only through database triggers, not hidden buttons, and paid AI endpoints check the same flag on the server.

ISOLATION.ENFORCEMENT
Signed-in request
↓
Row-level security checks the organization id
↓
Demo accounts: database trigger blocks writes
↓
Only that organization's rows are read or changed
02 / STRICT UNIT PARSER

A Parser That Rejects Instead of Guessing

Dimension fields accept 350cm, 2in or 0.2m and convert to the field's own unit when the user leaves it. An unrecognized unit is rejected with a message, never guessed. One shared component reached 42 fields across two builders, because the forms are schema-driven.

UNIT_PARSER.FLOW
User types 350cm, 2in or 0.2m
↓
Value converts to the field's own unit
↓
Unrecognized unit is rejected with a message
↓
One shared component serves 42 fields
03 / LIVE SCHEMA CHANGES

Changing the Schema Without Losing Data

Moving the Expense Log from one material per expense to multi-material lines meant a new table, a backfill of existing rows and deprecating the old columns instead of dropping them. The same recipe was later applied to equipment lines.

MIGRATION.RECIPE
New table for multi-material lines
↓
Backfill existing rows
↓
Deprecate old columns, don't drop them
↓
Nothing lost on a live database
04 / RUNTIME DEBUGGING

Bugs That Only Show Up at Runtime

A dark-mode refactor passed the type checker and still crashed in the browser, because the theme helper only works inside a live render context. Separately, light-pinned pages such as payslips inherited dark text from the body. Both were found by reproducing them in a running app, then fixed with a pattern that holds across the app.

DEBUGGING.PATH
Refactor passes the type checker
↓
Crashes in the browser at runtime
↓
Reproduced in the running app
↓
Fixed with one pattern across the app
03

THE IMPLEMENTATION

BuildTrack covers the whole job from estimate to cash position, in one system and one set of numbers, from a phone on site or from a desk. It was built solo with AI assistance.

SYSTEM_01

Estimate

A Material Take-Off engine across 13+ construction divisions (concrete, rebar, masonry, roofing, plumbing and more). It uses Fajardo's published tables and theoretical formulas, feeds a BOQ priced from the organization's own rate library, and syncs quantities across.

MTO ENGINEBOQRATE LIBRARY
SYSTEM_02

Structural Builder & AI Fill

The Structural Builder adds marks, an interactive 3D preview and printable summaries. AI Fill turns a plain-language description into a line item that the user reviews before applying. Paid AI endpoints are guarded on the server, so view-only accounts can't use up quota.

THREE.JSANTHROPIC APISCHEMA-DRIVEN FORMS
SYSTEM_03

Track

Phases with cascading-delay detection, budget vs. actual, change orders, a materials log with low-stock flags, an expense log and a daily work log.

PHASESCHANGE ORDERSMATERIALS LOG
SYSTEM_04

Pay

Time logs turn into payroll: daily and hourly rates, overtime, deductions and cash advances. Payslips are printable, and the payout flows into cash flow.

PAYROLLPAYSLIPSOVERTIME
SYSTEM_05

Cash

Multiple bank accounts, with every expense automatically creating its matching cash-out entry.

BANK ACCOUNTSAUTO CASH-OUT
SYSTEM_06

Platform

Multi-tenant SaaS with roles and team invites, trial and subscription gating, a view-only demo mode, light and dark themes driven by CSS variables, product tours, print reports and a full data export.

SUPABASE RLSTANSTACK QUERYZUSTANDVITEST
BuildTrack · PlatformSAMPLE DATA
Multi-tenant · organization-scoped
Roles and team invites
Trial and subscription gating
View-only demo · read-only by DB trigger
Light and dark themes
Print reports and payslips
Full data export
04

KEY DESIGN DECISIONS

DATABASE AS THE BOUNDARY

Isolation and read-only access are enforced where they can't be bypassed, not by hiding things in the UI.

ERROR OVER GUESS

An unrecognized unit is rejected with a message. A value that is wrong but looks fine is worse than an error.

SOURCED NUMBERS ONLY

Many formulas rest on metric-only empirical tables, so results are not converted to imperial. That would mean inventing numbers with no source.

ADD, BACKFILL, DEPRECATE

Live schema changes add and backfill first and deprecate old columns, so nothing is lost on a live database.

05

WHAT I CHOSE NOT TO BUILD

01_MULTI-LINE

Multi-Line Entry on Every Expense Category

It only makes sense where a catalog sits behind each line (materials, equipment). For Meals or Office it would be one more blank amount field, so I explained that instead of shipping empty UI.

02_SAME-UNIT RESULTS

Results in the Unit the User Typed

Feet in, feet out would mean converting metric-only empirical tables and inventing numbers with no source. I shipped the input flexibility and left the calculated side alone.

03_MANUAL CASH OUT

Removing Manual Cash Out

I traced a hidden dependency first: it was the only way to attach a receipt photo to an outflow. I shipped the removal only after extending receipt upload to auto-generated entries, so nothing was lost.

06

THE IMPACT

BuildTrack is live with trial contractors. It is about 44K lines of TypeScript with 102 database migrations and around 35 pages, built solo with AI assistance over roughly 10 weeks (first commit 2026-07-11). This page reports no user, retention or revenue figures. Next: test coverage is thin today, so unit tests for the calculation engine come first, followed by an audit trail of who logged what, which is deliberately deferred, and area unit conversion with an optional display-unit setting for results.

→Estimating, tracking, payroll and cash flow in one system
→Take-off engine across 13+ construction divisions
→Tenant isolation enforced in the database with RLS
→One strict unit parser across 42 fields
→Backward-compatible live migrations (102 in total)
→Next: unit tests for the calculation engine