Admin panel
The admin area lives under /admin/*. Only users with is_admin = 1 can see and reach it.
Dashboard
/admin/dashboard. Two tabs:
- Overview · KPIs (users, paying subscribers, MRR, ARR, items, documents, storage, scans this month, active sessions, emergency contacts), subscribers per plan, recent activity, "Run cron now" button.
- Analytics · if Google Analytics (gtag.js) or GTM is configured in the General settings tab, this surfaces the detected ID and shortcuts to open the property. Otherwise it reminds you where to add the snippet.
Users
/admin/users. Paginated list with search, filters, per-user detail, quick edit (role, status, plan). Per-user actions: view activity, force global logout, assign plan, toggle admin flag, suspend, unblock.
Plans & features
/admin/plans. Drag to reorder (affects the public home). Create/edit plans with:
- Slug (internal).
- Name, description, currency.
- Prices: monthly, annual, lifetime (one-off).
- Trial days.
- Visual flags:
enabled,visible,is_highlighted,is_default. - Quantitative limits:
max_items_per_type,max_storage_mb,max_scans_per_month,max_emergency_contacts,max_devices. - Binary features:
scan_history_visible,breach_alerts_basic,breach_alerts_realtime,monthly_summary_email. - Visible features (the bullet list shown on
/pricingwith emojis/icons).
Deleting a plan: if it has subscribers, all of them are moved to Free instantly. It does not cancel recurring subscriptions on Stripe/PayPal — cancel them manually from the provider's panel first, or you'll have phantom charges.
General settings
/admin/settings#general. Global config:
- App name.
- Public URL (no trailing slash).
- Version (asset cache buster).
- Default theme (dark/light). Changing it bumps
default_theme_set_at, which makes users with no explicit preference receive the new default. - Timezone.
- Default billing currency.
- Custom JavaScript: textarea to inject scripts (gtag.js, GTM, Plausible, etc.) on every page (public + app). No sanitisation — the admin owns what they paste.
Branding
/admin/settings#branding. Upload PNG/SVG/WEBP/JPG logos for dark/light theme, favicon, primary and secondary accent colors. Old assets are deleted from disk automatically when a new one is uploaded.
Email (SMTP/native + templates)
/admin/settings#email. Configure:
- Sending method: native (
mail()) or SMTP (host, port, secure, user, password). - Sender: email and name.
- Test: send a test email to the admin to verify the config.
/admin/settings#templates. Per-email editor with subject + HTML body + preview with dark/light toggle. Each template has its placeholder list. "Restore default" reloads the HTML from app/email_defaults/<name>.body.html.
Editable email types: login, login code, reset PIN, custom breach alert, basic breach digest, monthly summary, emergency (invite / request / granted / denied).
Payments
/admin/settings#payments. Each provider has its own config:
- Stripe · mode (test/live), publishable key, secret key, webhook secret. Supports card, Apple Pay, Google Pay, SEPA.
- PayPal · client ID, secret, mode. Subscriptions managed from PayPal.
- Coinbase Commerce · API key, webhook secret. No auto-renewal: the user has to renew each period.
- Bank transfer · IBAN, BIC, instructions. The admin activates the plan manually after confirming the deposit from
/admin/users#pending-payments.
Visible order in /pricing and /billing/change-plan is configurable by drag & drop. Each provider can be disabled independently.
PWA
/admin/settings#pwa. Enable/disable toggle. Configure name, short name, logo (192/512), theme color (linked to the Branding accent), background color. Logo upload accepts PNG, WebP and JPEG (JPEG is transcoded to PNG via GD on upload).
When enabled, FortPass serves a dynamic /manifest.json and registers a service worker that caches the shell with a version-keyed cache name. The "Install" button surfaces only on browsers/platforms that expose the prompt or have rich install instructions per platform.
FAQ & public testimonials
/admin/settings#faq. List of Q&A with drag & drop. Appears on the public home (/#faq) and below the public generator (/password-generator for anonymous visitors).
/admin/settings#testimonials. CRUD of testimonials with name + role, circular avatar (upload image — falls back to default_user.png), testimonial text, star rating (1–5), visible/hidden toggle, drag-to-reorder.
Maintenance mode
/admin/settings#maintenance. Global toggle. While active:
- Every visitor (except admins) sees a maintenance page with HTTP 503 and
Retry-After. - Exceptions:
/auth,/logoutand/admin/*routes keep working so admins can operate.
Fields: title, message, optional ETA ("in 30 min", "17:00 CET"…).
Demo mode
$config['DEMO'] in config.php. While true:
- A sticky top banner is rendered on every page (text + URL configurable via
DEMO_TEXT+DEMO_URL). - Every write action is blocked: AJAX returns a "Demo mode is active" error; page-level POSTs are rejected.
- Read-only operations (pagination, listing, search) still work via a whitelist of safe AJAX actions.
Custom JavaScript · GA / GTM
The General textarea is where you paste the Google Analytics (gtag.js) / GTM / Plausible snippet. It is injected as-is at the end of <body> on every page (public + inside the app).
Note: internal app URLs can contain item IDs (e.g. /accounts?focus=123). If you care about user privacy, configure your GA property to anonymise paths before pasting the snippet.
The Dashboard's Analytics tab auto-detects G-XXXXXXX (GA4) or GTM-XXXXXX via regex and surfaces the "connected" panel.
License & updates
/admin/license is the recovery and updates panel. See License & updates for the full pipeline.