The url renders to members as a clickable href. https was enforced only
in the admin Zod action, but RLS lets an admin/board write the row
directly via PostgREST, bypassing Zod, with no DB constraint -- a
malicious admin could store a javascript: URL and XSS members who click.
- Migration 050: CHECK (url ~* '^https://') so the DB is the source of
truth; integration-tested that the service path cannot store
javascript:/http:.
- Member-read action filters with isSafeDuesUrl (defense-in-depth).
- dues_payment_methods RLS: member read, admin-only write, cross-space
denial, 046 unverified-admin status gate (4 cases).
- notification dispatcher: a muted category becomes 'skipped' while
billing always sends; no pref row sends (default on). First real
exercise of the skip path (cron is gated off in prod).
- Fix integration/db.ts rowsAsUser: the SELECT must be the last psql -c
statement or its output is swallowed (it was never used before).
- Dues card: hide "No active dues subscription" for spaces without
Stripe, where it read as confusing.