Files
hope-events/SETTINGS.md
joshuaandClaude Opus 5.5 f2b51dbd88 PayFast provider, Pay online page, amount checks on payments
- PayFast (custom integration): signed form (PHP-style encoding, checked
  against a real sandbox), ITN checks (signature over all posted fields,
  PayFast host, VALID from /eng/query/validate, amount vs checkout).
- ProviderCheckout records every checkout (amount, metadata, request);
  webhooks match payments to it and hold a different amount for review
  (ProviderTransaction.note).
- /pay/<id>: payers choose a provider when several are on, and the
  browser posts PayFast's form from there, so payment links work for
  every provider.
- Site settings → Payments: PayFast card (merchant ID/key, encrypted
  passphrase, sandbox/live) while PayFast is enabled.
- Payer-facing wording no longer names Yoco; legal pages name both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 14:25:49 +02:00

8.8 KiB

Site Settings — Defaults Reference

Every setting below is stored as a row in the AppSetting key-value table and is editable at runtime via Admin → Site Settings (or, for the first few, the /setup wizard on a fresh install). None of them are required — this page documents exactly what happens when a given key has never been saved.

Settings changes take effect within 60 seconds everywhere (the backend's in-process settings cache TTL) without a server restart.

Organisation

Setting Default when unset Notes
org_name "Cross Code" Falls back to ORG_NAME env var first, then this hardcoded default (the platform vendor's name, used as a neutral placeholder — org_name is a required field in the setup wizard, so this fallback is practically unreachable once a site has been set up). Shown in the navbar, email headers/subjects, and WhatsApp messages.
org_tagline "Connecting community through events" Falls back to ORG_TAGLINE env var first. Shown under the org name in the email header.
org_email (blank) No fallback in most places. Exception: the Terms of Use / Privacy Policy pages default to privacy@example.com (an obvious placeholder) if unset — see the Legal section below.
org_phone / org_address (blank) No fallback — simply omitted wherever shown if unset.
app_base_url APP_BASE_URL or FRONTEND_URL env var, else http://localhost:3001 Used to build links in emails (password reset, ticket delivery, etc.). Should always be set in production.

Branding

Setting Default when unset Notes
primary_color Legacy accent_color value if present, else #4F46E5 (indigo) on the website / #1e3a5f (navy) in emails See Two different fallbacks below — this is the one setting with a genuine inconsistency worth knowing about. Drives buttons, links, nav highlights, and the email header/CTA.
secondary_color 210 40% 96.1% background / near-black text (light gray "wash", shadcn's stock theme) The Branding tab's color picker pre-fills #8B5CF6 as a suggested starting point, but that's only a UI default — if you never hit Save, the actual site uses the light-gray fallback, not violet.
accent_color 210 40% 96.1% background / near-black text (same light gray as Secondary) Same story as Secondary — the picker pre-fills #EC4899 (pink) as a suggestion only.
logo_url Bundled logo (frontend/src/app/church_logo.jpg) Shown in the navbar. This is still the original Hope Family Church artwork checked into the repo — swap the file (or upload a real logo via the Branding tab) before deploying for a different organisation.
favicon_url frontend/public/favicon.ico (the site's original generic favicon) Shown in the browser tab.

Two different fallbacks for primary_color

If primary_color has never been saved (no admin has ever used the new 3-color Branding tab) and there's no legacy accent_color value either, the website and outgoing emails currently disagree on what "no color" means:

  • Website (globals.css / tailwind.config.js static defaults): #4F46E5, a bright indigo.
  • Emails (backend/src/utils/email.js getOrg()): #1e3a5f, a dark navy — unless overridden by the EMAIL_HEADER_COLOR env var.

In practice this only matters on a brand-new install before the setup wizard or Branding tab has been saved even once — the wizard always writes primary_color, so this gap closes itself the moment setup completes.

Notifications

Setting Default when unset Notes
reg_notification_emails REGISTRATIONS_EMAIL env var, else (blank) If truly blank, no internal notification email is sent for new registrations/payments/donations — it's silently skipped, not an error.

Email delivery (SMTP)

Setting Default when unset Notes
smtp_host SMTP_HOST/EMAIL_HOST env var, else (blank) If blank, the app does not send real email — it uses nodemailer's jsonTransport, which just logs the would-be email to the console. This is the single biggest "nothing is configured" gotcha — ticket/payment/password-reset emails silently don't go anywhere until SMTP is set up.
smtp_port 587
smtp_secure false
smtp_user / smtp_pass (blank) Stored AES-256-GCM encrypted (key derived from JWT_SECRET).
smtp_from (blank) If blank, outgoing mail's From: address falls back to the literal no-reply@crosscode.local.

Payments

Managed in the Payments tab (through /api/payments/providers/settings and /api/yoco, not the generic settings endpoints).

Setting Default when unset Notes
payfast_merchant_id / payfast_merchant_key PAYFAST_MERCHANT_ID / PAYFAST_MERCHANT_KEY env vars, else (blank) From the PayFast (or Sandbox) dashboard. Both are needed before PayFast can take payments. The key isn't secret (it's in the payment form), so it's shown in full. Managed through /api/payfast.
payfast_passphrase PAYFAST_PASSPHRASE env var, else (blank) Stored encrypted. Must match the dashboard's salt passphrase exactly, or PayFast refuses payments ("signature does not match").
payfast_mode PAYFAST_MODE env var, else sandbox sandbox or live: where payers are sent and where notifications are confirmed.
payment_providers Yoco enabled JSON { order: [...], enabled: { yoco: true } }: which online payment providers are on, and their order (the first one enabled and set up is the default). Providers not listed yet come last, switched off (Yoco on, as it was the only provider). If none is on and set up, online payments are off.
yoco_secret_key YOCO_SECRET_KEY env var, else (blank) Stored AES-256-GCM encrypted. If blank, online checkouts and sponsorships fail with "online payments are not configured".
yoco_webhook_secret YOCO_WEBHOOK_SECRET env var, else (blank) Stored encrypted. If blank, Yoco webhooks are rejected, so payments aren't confirmed automatically.
yoco_webhook_id (blank) The Yoco webhook whose secret is stored, set when it's generated from the tab. Used to mark it "Active" and to clear the secret when it's deleted.
Setting Default when unset Notes
legal_operator_name "[operator details not yet configured]" Deliberately a generic, obviously-incomplete placeholder rather than any real person's or organisation's name. Unlike org_name, these legal fields are optional and can realistically stay unset on a live site — defaulting them to Cross Code's (or anyone else's) real identity would misrepresent who's legally responsible for that deployment.
legal_io_name "[not yet configured]" Same reasoning as legal_operator_name.
legal_io_email "io@example.com" Rendered as a mailto: link, so the placeholder stays a syntactically valid address on the IANA-reserved example.com domain rather than a bracketed non-email string that would break the link.
legal_website_url "example.com" Same reasoning — used to build an https:// link.
legal_effective_date "[not yet set]" Plain text only, no link — a bracketed placeholder is fine here.
notify_user_on_impersonation "false" When "true", a user is emailed (with the reason) whenever an admin views their account with Impersonate. Set under Site Settings → Legal → Support access.
consent_medical_retention_days 30 Youth events: medical and emergency details from parental consent forms are deleted this many days after the event ends (daily 09:00 job). The consent record itself — who agreed, when, to which text — is kept. Set under Site Settings → Legal.
org_email (as used on legal pages specifically) "privacy@example.com" Different fallback than org_email's general default (blank) — also rendered as a mailto: link, so it needs to stay a valid-looking address.

WhatsApp

Setting Default when unset Notes
WAWP_ACCESS_TOKEN / WAWP_INSTANCE_ID WAWP_ACCESS_TOKEN/WAWP_INSTANCE_ID env vars, else (blank) No hardcoded default — WhatsApp sending is simply unavailable until both are configured (Admin → Site Settings → WhatsApp).

Backups

Setting Default when unset Notes
backup_retain_count 14 How many nightly backups to keep on disk (oldest deleted beyond this count). Editable at Admin → Site Settings → Backups. See BACKUP_ENABLED (env var) to turn the nightly job off entirely.

Setup state

Setting Default when unset Notes
setup_complete false (treated as "not true") Controls whether /setup redirects to /login or runs the first-time wizard. Set to "true" automatically when the wizard finishes.