dhaga. blog · Engineering
Deep dives on the hardest problems we solved building Dhaga — rendering a 21k-node graph in the browser, keeping an AI product's unit economics alive, isolating tenants on serverless Postgres. Executive summary up top, full engineering detail below.
Tenant isolation is one indexable equality on every table, and that uniformity is the whole value. Widening it with an OR so colleagues can share records gives away every column on the row, costs you the index on your hottest predicate, and ships a change no feature flag can hold back. Publish a projection instead.
Light mode was audited to WCAG AA and the palette itself turned out to be the bug. On a light ground a colour's contrast as a fill and its contrast as text multiply to a fixed constant — ours is 16.78 — so no single value can clear 4.5:1 at both jobs. Why every accent in the system is now a pair.
Duplicate detection collapsed unrelated people into one contact. The helper it called was not buggy — it was a community-tag suggester that groups by surname on purpose, and it is still shipping unchanged. Why the types could never have caught this, and why making the shared helper smarter was the wrong fix.
Business-card scans were coming back confident, well-formed and wrong. The obvious fix was more pixels. The same 408px image read perfectly on a stronger model — so the fix was the model, and upscaling would have cost more to change nothing.
We rebuilt our public build timeline by summarising 847 commits with language models, then audited every line against git and the live code. The audit turned up no invented features — and a worse failure underneath: sentences that were true when written, and a code path described as shipped that no user could reach.
The rule that should have stopped it — one message goes in exactly one place — existed only as a sentence in the prompt. Nothing in code checked it. On the fix we rejected, why a Zod refinement was the wrong lever, and why we repair a bad plan instead of failing it.
A capture came back four fifths shorter than what was sent, and nothing reported it. It wasn't a token limit and it wasn't summarisation — the model was filtering to fit the schema. Why a structured-output schema is a filter as much as a contract.
Six keyword sources under one Promise.all, each awaiting its own scoped tenant connection, against a pool of three. Search returned HTTP 500 with a single user on it. Why Promise.all is a concurrency multiplier, not a performance tool, when every read checks out a connection.
A checked-in rulebook the AI must obey, hooks that gate every single edit, and a persistent memory that survives across sessions. Our AI-assisted engineering workflow — the practices that make an agent a reliable contributor instead of a fast intern who forgets everything.
Row-level security is easy to turn on and easy to get catastrophically wrong. How a connection pooler almost leaked one customer's data into another's in Dhaga Cloud, and the transaction-scoped design that makes it impossible on either pooling mode.
In an AI product, infrastructure is a rounding error and inference is the P&L. How we found the real cost driver in Dhaga, and the guardrails that keep a heavy user from costing us $7,200 a month.
Our documented escape hatch for a native dependency didn't work — the app crashed on deploy anyway. A short war story about how `import` runs before your code does, and why a feature flag can't gate a static import.
No migration tool, no migration files, and a 15-second sign-in. How a single content hash turned a full schema replay on every serverless cold start into a no-op — while keeping the zero-config, self-healing setup that makes a Dhaga instance trivial to stand up.
63,000 edges, 60fps pans, and a laptop with integrated graphics — without a graph database, a server-side render farm, or a spinner that never ends. How Dhaga renders a whole knowledge graph client-side.