Babysitters are expensive and scarce. Other parents are neither — they are just hard to coordinate with. PlayDateNight is the coordination layer: a closed ring of families who watch each other's kids and keep a shared ledger of who owes whom.
Watch another family's kids for an evening, earn a watch. Spend a watch when you want an evening of your own. That is the whole mechanic.
The design decisions that matter
The family is the identity, not the person. One parent or two, it does not matter — the family is what earns credits, spends them, and shows up in the ring. One auth user maps to exactly one family, and every access rule in the database is built on top of that mapping.
Balances can go negative. This is deliberate, and it is the only enforcement mechanism in the system. There is no payment, no penalty, and no lockout. Your balance is visible to your ring, and being the family at −4 is uncomfortable enough. Social pressure scales better than rules do.
Rings, not a global pool. You only see and trade with families you share a ring with. There is no discovery, no directory, no strangers. Growth happens by invitation, from someone already inside.
How it is built
React on the front, Supabase — Postgres, Auth, Realtime — behind it. Two constraints shape the whole codebase:
src/db.jsis the only file that touches Supabase. Components import functions from it and never see the client. One file to audit when a query looks wrong.- Every table has Row Level Security on. The browser holds a real Postgres connection with the user's own privileges, so the database — not the UI — is where authorization lives. A malicious client gets exactly as far as its policies allow.
Anything that must be atomic or must bypass RLS — credit transfer, invite
redemption, match confirmation, leaving a ring — goes through a
SECURITY DEFINER PL/pgSQL function. Clients have no EXECUTE permission on
the credit functions at all, so credits, total_earned, and total_spent
are simply not writable from the browser. The column-level UPDATE grant on
families stops at cosmetic fields.
-- every policy in the schema is rooted in this one helper
create function my_family_id() returns uuid
language sql security definer stable as $$
select id from families where auth_user_id = auth.uid()
$$;
src/dataModel.js documents every entity as JSDoc typedefs. It is never
imported by runtime code — it exists so that one file explains what the data is.
Status
Working, and in use by a small group of families. It is not open to the public yet, and there is a short list of things that must land before it is:
- Invites are bearer tokens today — anyone with the link can redeem one. They need to be bound to a specific recipient email.
- Dev-admin operations are single-factor. They need an AAL2 / MFA check before strangers are in the system.
Both are fine for a friend-group beta where everyone knows everyone. Neither is fine for a public launch, so the public launch waits.