Storage is Supabase (database and auth, eu-west-1 Ireland) unless stated. "RLS owner-only" means database row-level security restricts reads and writes to your own account. "Encrypted beyond operator reach" means AES-256-GCM under per-user derived keys (or, for couple content, a key derivable only by the two linked partners' sessions); the operator sees only ciphertext and cannot decrypt. "Cascade on deletion" means the data is destroyed when you delete your account.
| Category | Examples | Purpose | Storage and access | Encryption | Retention | Processor(s) |
|---|---|---|---|---|---|---|
| Authentication | anonymous user ID, email (once added), password hash, session tokens | sign-in, session persistence | Supabase Auth; admin sees only a yes/no "has email" flag | provider infrastructure; password hashed | until account deletion; abandoned anonymous accounts (no email, onboarding never completed, inactive 30+ days) auto-deleted | Supabase |
| Onboarding self-reports | pathway, readiness stage, triggers, gender, crisis-entry flag, ToS acceptance | tailor the experience you asked for; record consent | RLS owner-only; enum/state values, no free text; not on any admin surface | structured data (no free text exists here) | cascade on deletion | Supabase |
| Optional demographics | age band, prior recovery engagement ("declined" stored distinctly) | age-appropriate defaults, personalisation | same as above | structured data | cascade on deletion | Supabase |
| Journal | journal entries | your private writing space | you only; never read by the coach or any profiling | encrypted beyond operator reach | cascade on deletion (destroyed) | Supabase (ciphertext) |
| Why statements | dated archive of your Why | your anchor, surfaced only to you | you only | encrypted beyond operator reach | cascade on deletion | Supabase (ciphertext) |
| Difficult-day and setback notes | optional free-text notes on logs | your own record | you only | encrypted beyond operator reach | cascade on deletion | Supabase (ciphertext) |
| Foundation content | identity statement, Ulysses commitment, trusted contact name and phone | features you set up yourself; trusted contact opens your own phone's SMS/call app only, nothing passes through Resolut and the contact is never made aware | you only | encrypted beyond operator reach | cascade on deletion | Supabase (ciphertext) |
| Check-in and state logs | session-gate state (okay / hard day / struggling / setback), urge outcomes, mission completions, mode changes, softening-window state, risk window, mode preference | drive the app's supportive behaviour | RLS owner-only; no admin query path | structured data (enum/number, no free text) | cascade on deletion | Supabase |
| User-authored missions | custom missions a user writes themselves | personal goals the user sets alongside the app's suggested missions | RLS owner-only; you only | encrypted beyond operator reach (per-user key) | cascade on deletion | Supabase (ciphertext) |
| Behavioural counters | intercept, setback, difficult-day counts with timestamps | progress and cadence logic | RLS owner-only | structured data | cascade on deletion | Supabase |
| Internal profile classification | dominant type, confidence state and score | invisible content ordering; the score is never shown to anyone | RLS owner-only; read server-side by the coach route; not on any admin surface | structured data | cascade on deletion | Supabase |
| Coach operational data | rate-limit counter, recent app-generated responses | rate limiting, anti-repetition | RLS owner-only | app-generated text, not yours | cascade on deletion | Supabase |
| Coach generation payload | moment type, app-day integer, fixed check-in label, fixed variant, bounded counter, up to 120 chars of our own mission copy | generate the coach message | sent transiently to Google Gemini; no user free text or identifiers ever included | in transit (TLS) | not stored by us beyond the anti-repetition table | Google Gemini |
| Product analytics | fixed-enum events (session start, article opened, coach message count, account deleted marker) with an internal user reference | count feature usage; the table has no free-text or JSON column and cannot hold content | write-only for users; readable only by an allowlisted admin with two-factor auth, in aggregate | structurally content-free | survives account deletion; retained indefinitely in v1 (no purge job) | Supabase (first party; no third-party analytics) |
| Feedback | your submitted feedback text | improve the app | encrypted under a separate operator key; readable by the operator by design behind allowlist + two-factor auth; you cannot re-read it | AES-256-GCM (operator-decryptable exception) | survives account deletion | Supabase |
| Payments | plan, status, period dates, amount (USD), provider IDs, webhook events | grant and manage access; idempotency; records | RLS select-own; writes server-side; admin sees subscription status only | structured data; no card, phone, or M-Pesa data is ever stored by us | cascade on deletion for our rows; processor keeps its own records; financial records may be retained as required by law | Supabase, IntaSend (Paddle dormant, not live) |
| Checkout data at the payment provider | your phone number / M-Pesa / card details | taking your payment | entered on the provider's hosted page; never touches our servers | provider's own | per the provider's retention policy | IntaSend |
| Founding counter | aggregate count of founding members | enforce the 150 cap | single aggregate row, identifies no one | n/a | permanent; never decremented | Supabase |
| Waitlist | email (pre-launch signups) | launch notification | deleted on account deletion by your own email | none | until launch cleanup or your deletion | Supabase |
| Couple data (only if you link) | link record, check-in facts (date only, no mood), shared goals, shared messages (≤500 chars) | the couple features you both opted into; the app's only user-to-user communication | visible only to the two linked partners; a partner has no path to your individual recovery data; either partner can sever the space at any time | goals and messages encrypted beyond operator reach (couple-shared key); link/check-in records are structured data | shared content deleted when either account is deleted; link severed | Supabase |
| Push subscription | device endpoint, keys | deliver the one opted-in reminder (risk window) | stored per device; notification body may include your own identity statement | endpoint/keys structured; content in transit via the push service | cascade on deletion; revoked when you opt out | browser push services (e.g. FCM, Mozilla) |
| Cookies | Supabase sb-* session cookies | keep you signed in (essential) | your browser | n/a | cleared on logout; short-lived tokens with rotation | Supabase (via our domain) |
| localStorage / sessionStorage | buffered onboarding answers (cleared after commit), card-dismissal and cadence flags, personalisation settings, once-per-open gate flag, legacy journal/Why keys (cleared after server migration) | app state on your device | your device only | n/a | until cleared by app logic or by you | none |
| Server logs | request/error logs possibly containing user IDs and payment references (never recovery content or secrets) | operations, debugging, webhook audit | hosting and database platforms | provider infrastructure | Vercel runtime logs ~30 minutes (current plan); Supabase logs 24 hours; platform-managed | Vercel (iad1, USA), Supabase (eu-west-1, Ireland) |
| Transactional email | your email address, message content (welcome, receipts, subscription, password reset) | account and payment communications; sender noreply@resolut.site | sent to your own address only | in transit (TLS) | per Resend's retention | Resend |
| Crisis link | outbound link to findahelpline.com | crisis resource access | plain link; no data passes, no parameters, no API call | n/a | n/a | none |
| Under-18 redirect | nothing | age gating | the age gate runs before any account creation; a redirected minor leaves zero records of any kind | n/a | n/a | none |