- 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>
104 lines
8.8 KiB
Markdown
104 lines
8.8 KiB
Markdown
# 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](#two-different-fallbacks-for-primary_color) 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. |
|
|
|
|
## Legal (Terms of Use / Privacy Policy)
|
|
|
|
| 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. |
|