entering the universe
v
Videet
back to the lab
Product2026 — NowDesigner · Engineer

Family Tree

A private, invite-only app where my family builds our own tree — modelling marriages, adoptions and unknown ancestors honestly instead of forcing them into a neat binary shape.

Invite-gated
Auth
Postgres DAG
Graph
RLS-first
Policies
Deterministic
Layout
stack
Next.js 15Supabase PostgresRow Level SecurityReact FlowTypeScript

Most family-tree software assumes a family shape that doesn't exist. It wants a father and a mother, one marriage each, no adoptions, and dates you actually know. Real families — certainly mine, tracing back through Nagpur and Amravati into the 1800s — are messier than that. Someone's second marriage produced half of the cousins. Someone's mother is simply unrecorded. Someone was raised by an uncle and everyone politely calls him a brother.

So I built our own.

Modelling a family without lying about it

The interesting decisions were all in the schema. Three that mattered:

Marriages are a first-class table, descent is a separate edge table. The obvious design — father_id and mother_id columns on a person — collapses the moment you have an adoption plus a step-parent, because a child can legitimately have four parents. The next-most-obvious design, a generic relationships(from, to, type) table, gives a marriage no identity to hang a date or a divorce on. So marriages get their own row with their own attributes, and parent→child is a separate edge with its own relation_type.

A single parent is not an error state. The GEDCOM-derived approach hangs children off marriages only, which means every unknown ancestor spouse needs a phantom person invented to have something to attach to. For a tree reaching back two centuries, "spouse unknown" is the common case. Descent edges stand alone.

Nothing is stored as coordinates. Node positions are a pure function of the graph, computed identically on every device. This deletes an entire category of bug where two relatives drag the same node somewhere different.

There's also a small, slightly grim detail I'm fond of: every date has a precision alongside it — day, year, decade, approx — plus a free-text note. So a birthday can be recorded as "the monsoon of '47" without pretending to a precision nobody has.

Keeping it genuinely private

The whole thing lives inside this portfolio, which is otherwise a fully static site. That's a slightly unusual constraint: the marketing pages must stay prerendered and CDN-cached while one route becomes a stateful, authenticated app.

Access is invite-only, and the check runs in the database at account-creation time rather than in application code — so an uninvited person never gets an account at all, rather than getting one that's later filtered out. Row Level Security is the real authorization boundary; the middleware and the server-side gate above it exist for the user experience, not for security. Column-level grants handle the thing RLS can't: a relative can edit their own profile without being able to promote themselves to admin.

Still to come

Photographs with face tagging. A hereditary-health view — the genuinely useful reason a family app might hold medical information, kept in separate tables with consent recorded per person and access logged, because that data deserves more care than a birth year does. And eventually a wedding-invitation tool, which is why marriages are first-class: a guest list attaches to a marriage, not to a person.

The app itself is private. The engineering is what's on display here.