How we protect you
Security Measures
We take security seriously because you're trusting us with personal, spiritual content. Here's exactly what protects you — every layer, in plain English. You can verify all of this in our open source code.
Your account
- Username + password (no email required)
- Passwords hashed by Supabase Auth with bcrypt (never stored in plaintext)
- Minimum password strength enforced using zxcvbn
- Account lockout after 5 failed attempts in 10 minutes
- Generic error messages (no username enumeration)
- Forgot your password? Message Alex — he can reset it from the Supabase admin dashboard. Your journal entries stay tied to your account through the reset.
How journal & intentions privacy works
- Journal entries, talk notes, and private intentions are stored in Supabase Postgres tables.
- Row-Level Security (RLS) on every table restricts reads/writes to
auth.uid() = user_id— through the app, nobody else in the group can see your entries. - HTTPS-only transport encryption between your browser and Supabase, and encryption at rest on the underlying AWS storage.
- The database admin (Alex) has technical access to the underlying tables and could read content with effort. The trust commitment in Privacy is that he won't — and every admin action is logged in an immutable audit table you can review.
How photos work
- All photos are uploaded to the shared group gallery. There is no private-photo mode.
- Photos are stored in Supabase Storage. The bucket is private; the app generates short-lived signed URLs (1 hour) for authenticated members to view photos.
- If you don't want a photo seen by the rest of the group, don't upload it here.
Bot & abuse protection
- Cloudflare Turnstile (privacy-friendly human verification)
- Honeypot field on signup (invisible to real humans)
- Cloudflare Bot Fight Mode at network edge
- Rate limiting: max 10 auth requests per minute per IP
Database security (Supabase)
- Row-Level Security (RLS) on every table
- RLS policies:
auth.uid() = user_id(you can only see your own data) - Only anon key in client code (safe to expose); service role key never in codebase
- Database hosted by Supabase on AWS with encryption at rest and in transit
Network security
- All traffic HTTPS only
- Strict security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, CSP)
- Cloudflare WAF, DNSSEC, DDoS protection
Input sanitization
- All user content rendered as plain text (
textContent, neverinnerHTML) - All database queries use parameterized SDK calls (SQL injection impossible)
- Honeypot traps silently reject bot submissions
Audit logging
- Every admin action automatically logged to immutable audit table
- Records: who, when, on whom, what
- You can view your own audit log in Account Settings
Soft delete & recovery
- Account deletion = 7-day scheduled deletion
- During grace period, log in to cancel
- After 7 days, permanently deleted (all related rows cascade-deleted)
- Full export offered before deletion
What we deliberately chose NOT to do
- No 2FA (adds friction for a group reluctant about email)
- No full security team (built by one person for a small group)
- No client-side encryption — privacy on personal content is enforced by row-level security, not by a key only you hold
- No private-photo mode — everything in the gallery is shared with the group
Found a security issue?
Email alex@sjdyoungadults.com directly.
Verify it yourself
All verifiable in source code: github.com/ragerbanjoo/ascend
Files to check:
- script.js — auth flow, signed-URL handling, rate limiting
- supabase/migrations/*.sql — RLS policies (see migration 013 for the journal-plaintext switch)
- _headers — security headers
- hub.html — how user input is rendered (plain text only)
"We don't ask you to trust us. We give you everything you need to verify us."