Jagdeep Singh

Available

Projects

Tebani Craft

A multi-tenant SaaS for house builders: seed a house’s jobs from a template, and durations plus dependencies compute the finish date.

www.tebanicraft.comSource private

The problem

A residential builder running several houses at once keeps the schedule in their head and a spreadsheet. The question they actually need answered — if the frame slips a week, when does this house finish, and who needs telling — takes an afternoon to answer by hand, so it gets answered by guess. Tebani Craft stores the durations and the dependencies and derives the date instead.

How it works

A house is seeded from a template into ordered phases, each holding jobs with a duration and dependencies. The scheduler runs a forward pass over that graph — a topological sort with cycle detection, then working-day arithmetic — to give every job a date and the house a finish date. Nothing about the schedule is stored: phase dates and the house finish are derived on read, so there is no cached date that can drift from the graph that produced it. Three surfaces sit over one domain core — a Filament admin panel for the builder, a React and Inertia app for tradies on their phones, and a token-secured JSON API — and each is a different way into the same actions.

Builder panelFilament v5, Builder is the tenant
Domain coreactions, typed payloads, one set of rules
Postgresone database, every row scoped by builder
Schedulertopological sort, working days, derived dates
Tradie app + APIReact and Inertia, separate guard

Stack

  • Laravel
  • Filament
  • React
  • Inertia
  • Postgres
  • TypeScript

Decisions and trade-offs

Phases are first-class, and their dependencies are soft

Builders think in stages, so phases are real objects rather than labels, and a phase-level gate says “frame waits for foundation” once instead of wiring every cross-phase edge by hand. But the gate is only a default: a job with its own dependencies uses those and ignores the phase, so a job whose real predecessors are done can start early. The cost is two layers that can contradict each other, resolved by one deterministic rule — explicit job dependencies win.

One database, rows scoped by tenant

Every builder is an isolated tenant, but they share one Postgres database with a builder key on every owned table and a global scope over every query. Database-per-tenant was rejected on a specific capability: a tradie works for several builders, and their job list has to stay one indexed query rather than a fan-out. The tradie is the deliberate exception to the scoping — one global account, linked to each builder by a connection record.

The schedule is derived, never stored

The graph is built, read and thrown away on each computation. That keeps a stored date from ever disagreeing with the dependencies that imply it, at the cost of recomputation — which runs on a queue worker per house. It also means the engine’s real interface is a migrated database, so its cycle detection and working-day arithmetic are covered by database-backed tests rather than unit tests.

The org is the billed party, and the plan gate outranks every policy

The subscription sits on the builder org, not on the user who happened to sign up — otherwise deactivating a colleague who left would take the company’s plan with them. And when a plan lapses the org keeps everything and may change nothing: that is a property of the tenant rather than of any record or role, so it runs as a gate ahead of every policy instead of a line repeated inside each of the eight. Read access is answered from rows, so no network call ever stands between a builder and their own build.

Next project: Site Hero CheckAll projects