Not released yet. PeltyCMS is under development and not released yet; these docs describe the upcoming release and may change.
PeltyCMS Developer docs
User docsDevelopers
v0.1.0

Developer docs/Platform reference

Database migrations

104 migrations in migrations/, applied in order by pelty-server migrate (and on serve). The summary is the file's leading comment.

FileSummary
0001_init.sqlPeltyCMS initial schema: identity, sessions, RBAC, audit, settings.
0002_extensions.sqlPlugins, payment gateways, webhook deduplication, minimal payments ledger.
0003_perf_indexes.sqlMatch the admin user list ordering exactly (created_at DESC, id) so the page is an index scan with no sort.
0004_billing.sqlMilestone 2: billing core. All money is NUMERIC(19,4) + ISO currency; the currency's exponent decides rounding. Never floats.
0005_dashboard_indexes.sqlPartial indexes backing the dashboard aggregates.
0006_clear_dummy_bank_text.sql0002 seeded a placeholder IBAN into the manual gateway. Bank details now live in system_settings (billing.bank_transfer); drop the placeholder only if the operator never changed it.
0007_email.sqlEmail: operator-editable templates, password resets, email verification.
0008_mfa.sqlTOTP two-factor auth. Secrets are AES-256-GCM sealed by the app (PELTY_ENCRYPTION_KEY); backup codes and challenge tokens are SHA-256 only.
0009_avatars.sqlProfile pictures, re-encoded server-side to PNG (256px and 64px squares).
0010_tickets.sqlSupport tickets.
0011_ticket_attachments.sqlTicket attachments. Uploaded first (pending, owned by the uploader), then linked to a message when the reply/ticket is posted. Bytes live in the DB so there is no filesystem path handling; served only as downloads.
0030_addons_custom_fields.sqlProduct addons (sold alongside a product) and custom order fields.
0040_coupons.sqlCoupons / promo codes. Discounts are applied as a negative invoice line and, for recurring coupons, persisted on the service's recurring amount.
0050_affiliates.sqlAffiliates: referral codes, attribution by tracking cookie at signup, commissions accrued (exact decimals) when a referred customer's invoice is paid, and payout requests against the available balance.
0051_quotes.sqlQuotes / proposals. Accepting a sent, unexpired quote turns it into a finalized invoice exactly once (quote row locked, invoice_id set).
0052_downloads.sqlDownloads area: files stored in the database (no filesystem paths), gated by owning an active service of one of the linked products. No linked products = available to every signed-in customer.
0090_content.sqlKnowledge base and announcements. Content is per-locale; locale NULL means "all languages". Only published rows are visible publicly.
0091_client_groups.sqlClient groups (WHMCS "Client Groups"): label colour, a percentage discount applied by pricing code that opts in, and an optional "exempt from late fees" flag.
0092_api_keys.sqlPersonal API keys. Only the SHA-256 of the secret is stored; prefix is the public, non-secret part shown in the UI. A key's effective permissions are its scopes intersected with its owner's current permissions.
0095_import_map.sqlIdempotent importer bookkeeping: one row per imported source record.
0096_tax.sqlTax engine: rules per country/region, inclusive/exclusive pricing (global setting billing.tax), compound taxes, EU VAT reverse charge.
0100_provisioning.sqlProvisioning: panel servers, product → server binding, per-service remote state.
0101_api_keys_admin.sqlAdmins can list and revoke any user's API keys.
0102_reports.sqlFinancial reports (revenue, MRR, churn). Admin and staff can read.
0103_gdpr.sqlGDPR: data-subject erasure requests (export is on demand, nothing stored).
0104_fraud.sqlFraud screening results for client orders (built-in rules + plugin hooks).
0110_service_changes.sqlPlan changes (upgrade/downgrade with proration) and cancellation requests.
0120_support_suite.sqlSupport suite: canned replies, tags, ratings, SLA first response, merge, escalation rules and inbound e-mail piping.
0121_overdue.sqlOverdue automation: one row per (invoice, action) so reminders, late fees and suspensions happen exactly once even if the daily job runs twice.
0122_credit.sqlCustomer credit balance as an append-only ledger (per currency). The balance is the sum of entries; it never goes below zero (checked under a row lock on the customer).
0130_domains.sqlDomains: TLD price list, registered/transferred domains and renewals.
0160_config_option_types.sqlConfigurable option types (WHMCS: dropdown, radio, quantity, yes/no). quantity: the single choice's price is per unit; yesno: the single choice is "yes" (absent = no).
0161_network_issues.sqlNetwork / service status issues (WHMCS "Network Issues"), public page + admin.
0162_client_notes_fields_todos.sqlStaff notes on clients (multiple, sticky), custom client fields and the admin to-do list.
0163_billable_items.sqlPer-product invoice generation lead time (NULL = global default) and billable items: one-off or recurring charges billed to a client.
0170_plugin_webhooks.sqlDurable, HMAC-signed event delivery to external plugin webhook URLs.
0171_usage_billing.sqlMetered / usage billing: per-product metrics, raw usage records grouped into per-service periods that are invoiced when the period (cycle) ends.
0180_login_lockout.sqlPer-account login backoff: after LOCK_AFTER consecutive failures the account is locked for an exponentially growing window (capped).
0181_refunds.sqlRefunds against individual payments (partial or full), executed through the payment gateway. Each successful refund issues a credit note.
0185_currency_rates.sqlExchange rates (relative to the default currency, which has rate 1), display prefix/suffix and a single default currency.
0186_staff_roles.sqlStaff role editor: builtin roles cannot be deleted/renamed; admin keeps all permissions.
0187_mail_campaigns.sqlMass mail campaigns to client segments, sent by the job queue.
0190_sso_tokens.sqlOne-time client SSO tokens. The token itself is signed (HMAC under the server API key) and never stored; only its nonce, to burn it on use.
0191_bundles.sqlProduct bundles (fixed set of products at a cycle, % off the first invoice) and per-product upsell / cross-sell recommendations.
0192_ticket_statuses.sqlCustom ticket statuses. Built-in ones keep their workflow meaning (replies move tickets between open/answered/customer_reply/closed); custom ones are set manually by staff.
0193_ticket_rated_at.sqlWhen a customer rated a ticket (satisfaction report period filter).
0195_gateway_deliveries.sqlWebhook delivery log per gateway (admin troubleshooting). Bodies are not stored (may contain personal data); only outcome metadata.
0200_storefront.sqlPublic storefront carts (keyed by an unguessable client token), customer contacts / sub-accounts, email preferences and admin order notes.
0201_autopay.sqlSaved payment methods (provider tokens only, never card data), auto-pay opt-in per customer and the off-session charge attempts with retries.
0202_invoice_tools_order_approval.sqlPre-due invoice reminders (one mail per invoice and threshold).
0210_legal_entities.sqlLegal entities (selling companies): per-entity bank details, footer/terms, due-date terms and per-year gapless numbering. Without any entity the legacy global INV-/CN- sequence is used unchanged.
0211_gateway_rules.sqlPer-gateway processing fees, amount limits and currency restrictions.
0220_addons.sqlAddon registry: provisioning modules, payment gateways, themes and plugins must be installed (and enabled) before they can run. See docs/ADDONS.md.
0221_site_pages.sqlPublic website CMS pages built from declarative blocks (docs/DESIGN_LAGOM_STYLE.md).
0222_site_legal_pages.sqlDefault pages linked from the public footer (Company / Legal). Admins edit them in Website > Pages.
0240_admin_tools.sqlAdmin productivity: personal "My Notes" and outbound staff notification rules (Slack / Discord / Teams / generic webhook), WHMCS "Configure Notifications".
0247_billing_wave2.sqlBilling wave 2: full ISO 4217 currency list, currency display format, automatic exchange-rate updates (configurable source + markup), invoice merge/split bookkeeping and gift cards / prepaid credit codes.
0261_admin_ops.sqlAdmin ops: per-staff dashboard/quick-link prefs, DB backups, custom code permission.
0262_campaign_schedule.sqlMass mail scheduling: a campaign can wait in 'scheduled' until scheduled_at.
0263_affiliate_extras.sqlAffiliate extras (WHMCS parity): per-product commission overrides, referral count tiers and promotional materials. Product-rated invoice lines replace their share of the base commission.
0265_registrar_addons_domains_ext.sqlRegistrars become addons (kind 'registrar'); domain pricing gets grace / redemption fees and add-on prices; DNS records and domain lifecycle states.
0266_support_ext.sqlSupport extensions (WHMCS parity): department auto-reply and mailbox piping (IMAP/POP3), spam control, canned categories, time tracking, KB tags and contact form messages.
0270_security_suite.sqlSecurity / accounts suite: captcha nonces, social login (OAuth2/OIDC), IP rules, admin impersonation, WHMCS-compatible API credentials, versioned terms of service, client close/merge.
0271_refund_to_credit.sqlRefund a gateway payment to the customer's account credit instead of back through the gateway (WHMCS "Add to client's credit balance").
0272_add_funds.sqlAdd funds: the client pays an invoice and the amount lands in their credit balance exactly once (trigger on the paid transition, same transaction).
0273_client_group_rules.sqlAutomatic client-group assignment rules. Evaluated in priority order; the first matching rule decides the group. Applied on demand by an admin (dry-run first) and only to customers without a group unless overwrite.
0275_ticket_watchers.sqlExtra staff who follow a ticket and get its notifications.
0276_promos_free_domain_order_forms.sqlPromotions: addons/domains scope, recurring for N cycles, per-client/group.
0277_subaccount_perms.sqlSub-account permissions gain "orders" and "domains" (WHMCS Users & Accounts).
0278_notify_channels_webhooks.sqlTelegram, SMS (HTTP gateway or email-to-SMS) notification channels, HMAC signed generic webhooks with a per-attempt delivery log.
0279_server_groups.sqlServer groups: products bound to a group get a server picked automatically (per module, enabled, under max_services) by the group's strategy.
0280_product_stock.sqlProduct stock control: optional quantity limit with optional backorders.
0281_module_checkout_fields.sqlCheckout fields declared by a product's provisioning module are synced into product_custom_fields and tagged with the module's field key.
0285_oauth_provider.sqlPeltyCMS as an OAuth 2.0 / OpenID Connect provider.
0286_live_chat.sqlSimple live chat: anonymous visitor sessions (bearer token, hashed) and staff replies, polled by both sides.
0287_debit_notes.sqlDebit notes: an extra charge issued against an existing invoice (the counterpart of a credit note). Linked via credit_for (= "related invoice").
0288_module_log_health.sqlServer health (last connection test) and a log of every module call.
0289_saml.sqlSAML 2.0 Service Provider: identity providers, pending AuthnRequests, and the assertion replay cache.
0290_addon_kv.sqlAddon-private key/value store for WASM addons (host kv-* imports). Values are sealed with the app encryption key when one is configured.
0291_admin_security.sqlAdmin account security: step-up re-authentication, password age, login alerts.
0292_fk_indexes.sqlIndexes on foreign keys that are filtered by or checked on delete (ON DELETE RESTRICT / CASCADE scans) on the customer, invoice, order, ticket and session paths. Found with a pg_constraint/pg_index scan; see docs/PERFORMANCE.md.
0293_email_log.sqlWHMCS "Email Message Log": every transactional mail the worker delivered (or failed to), viewable per client and resendable by staff.
0294_card_expiry_banned_emails.sqlWHMCS "Credit Card Expiry Notices": one notice per saved card.
0295_fixed_term.sqlFixed-term products: terminate a service N days after activation (WHMCS "Auto Terminate").
0296_ssl_checks.sqlSSL certificate monitoring for client domains (WHMCS "SSL Sync" / SSL status in client area).
0297_ticket_message_edit.sqlStaff can edit or delete ticket replies (WHMCS UpdateTicketReply / DeleteTicketReply).
0298_proforma_invoices.sqlProforma invoices: an issued invoice may stay unnumbered until it is paid.
0299_staff_noticeboard.sqlStaff noticeboard (WHMCS "Staff Noticeboard" addon): short notices shown to all staff.
0300_security_questions.sqlWHMCS security questions: staff-defined questions; each user may store one hashed answer, which staff can check when verifying a caller by phone.
0301_link_tracking.sqlWHMCS-style link tracking: short redirect links that count clicks.
0302_payment_reversals.sqlPayment reversals (chargebacks): money already taken back by the bank or gateway. Settled like a refund (credit note, payment/invoice status) but without calling the gateway.
0303_inactive_clients.sqlLast login, kept even after sessions are purged; used by the inactive-client retention job.
0304_projects.sqlProject management (WHMCS Project Management addon): projects linked to a client, tickets and invoices, with tasks and time tracking billed as invoice lines.
0305_domain_pricing_extras.sqlRegistrar cost sync + margin rules, premium domains, per-TLD custom fields.
0306_overage_import.sqlOverage billing from server-module usage + server account import.
0307_kyc.sqlKYC: identity documents uploaded by customers, reviewed by staff.
0308_api_gaps.sqlWHMCS API gaps: UpdateTransaction (staff note on a payment).
0309_vendor_catalog.sqlMarketConnect-style vendor resale: catalog synced from a vendor server.
0310_passkeys.sqlPasskeys (WebAuthn). The credential is the serialized webauthn-rs Passkey (public key + counter only; no secret material).
0311_passkey_discoverable.sqlUsernameless (discoverable credential) passkey sign-in ceremonies.
0312_tld_field_key_case.sqlRegistrar parameter names are case-sensitive (RegistrantNexus, X-CA-LEGALTYPE, contactRegistrant.nexusCategory): keep the key exactly as typed, but two keys differing only in case are still one field.
0313_registrant_verification.sqlICANN Registrar Accreditation Agreement (WHOIS accuracy program): the registrant's e-mail must be verified within 15 days of a registration, transfer or registrant e-mail change. One row per domain (latest request).
0314_translation_overrides.sqlTranslation editor: admin overrides on top of the shipped locale files.
0315_duo.sqlDuo Universal Prompt: OIDC state between redirect and callback.