Explanation

How privacy works

Tenancy enforced in the database, a fixed media region, metadata stripped from uploads, expiring links, AI switches with an audit log, export and delete.

Updated

Private is a structure, not a setting. This page explains the structure in plain terms; the public privacy and security pages state the promises.

A tenant in the database#

Every row of family data carries a family id, and the database itself refuses to return rows for another family. The API runs as a database role that cannot switch that check off. Background jobs run per family with the same check. Foreign keys are composite, so a row cannot be re-pointed at another family by changing one field. An application bug cannot leak across families because the database will not let it.

A grandparent's highlight link runs in a second, narrower mode: writes are blocked entirely, and reads are limited to the exact rows the link lists, across five tables. Everything else returns nothing.

Media#

Uploads are verified (size, real file type, checksum), re-encoded to 1600 px and a thumbnail, stripped of EXIF, IPTC, and XMP metadata (including GPS), and the original is deleted. Files live in Singapore in a bucket that only the app can read, and are served through short-lived signed links. An EU bucket exists for families who ask before their family is created; the region is fixed at creation.

Sign-in without passwords#

Adults sign in with an emailed link that lasts 15 minutes and works once. A password is optional. Day-to-day adults and grandparents join with a one-tap link that creates a 90-day session on that device. Sessions are per device and can be revoked. Requests that change data must come from the app's own origin.

Roles#

The smallest role that works: Account owner, Full access, Day-to-day, Highlights. A Day-to-day adult's view is one rule applied everywhere including offline sync: their own entries, today's entries, starred entries. Viewers never enter the app.

AI#

Seven features (translate, detect language, book prompts, coaching point, coach chat, weekly suggestions, evidence answers), each behind a switch, with a master switch for the coach. Turning the coach off deletes stored chats and suggestions. Before any text leaves the server, the child's name and every adult's name are replaced with placeholders. Blocked terms (diagnoses, rewards, punishments) trigger a regeneration and then a refusal. Every call writes an audit row with feature, model, byte counts, who, and when, and never the text. The provider is Anthropic; the models are Claude.

Export and delete#

Export is JSON for everything, CSV for the diary, PDF for the portfolio, any time. Deletion is owner-only, requires typing the family name, waits a grace period every adult can see, then removes files, calendar events, rows, and orphaned accounts, and writes a tombstone.

What is not collected#

No third-party analytics on child content, no ads, no data sales. Weather feeds receive a location, not family data. The marketing site is a separate origin with no session cookie.

Two honest limits#

The media region cannot be changed after creation, and push keys and Telegram chat ids are stored in plain text (excluded from exports, but not encrypted at rest). Google Calendar tokens are encrypted.