SJD YAG × ASCEND
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, never innerHTML)
  • 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."