Platform admin, moderation, analytics

Platform admin (/admin)

Only users with is_platform_admin = 1 can open /admin. Grant it with:

php bin/make-admin [email protected]          # grant
php bin/make-admin [email protected] --revoke

Emails listed in PLATFORM_ADMIN_EMAILS are promoted automatically by the scheduler task admin.sync_platform_admins (every 5 minutes, needs php bin/worker running or cron php bin/worker --once).

PageWhat it does
/adminTenants, users, MRR estimate (active subscriptions × monthly price), orders today, failed jobs, webhook errors, open reports, live streams / players
/admin/tenantsSearch, change plan (rewrites plan limits), suspend / reactivate, *Open dashboard* (impersonate: sets your session's active tenant)
/admin/usersSearch, platform-wide ban / unban (kills sessions, writes a bans row with tenant_id 0), grant / revoke platform admin
/admin/refundsOrders in refunded / disputed state across all tenants
/admin/auditGlobal audit log with action / tenant / user filters
/admin/flagsFeature flags (feature_flags table). Convention: social.<provider> gates providers that need app review or paid tiers; ai.copilot gates AI features
/admin/jobsQueue overview, failed jobs with *Retry*, registered handlers and scheduler tasks
/admin/webhooksInbound webhook events (Stripe, verification…) with errors; *Reprocess* re-queues <provider>.process_event

Every admin mutation is written to audit_logs with tenant_id = 0.

Moderation (/dashboard/moderation, role ≥ moderator)

  • Anyone signed in can report a profile, community, post, user or server (POST /report). Pages can embed the button with $__view->partial('moderation::report-button', ['type' => 'profile', 'id' => $id]).
  • Reports are routed to the tenant that owns the target; owners/admins get a notification.
  • Moderators resolve / dismiss reports and ban users from one community or the whole workspace (with optional expiry). Banning removes community memberships; banned users get 403 when joining. Bans can be lifted.
  • Moderators cannot ban owners/admins.

Analytics (/dashboard/analytics, role ≥ staff)

KPI tiles (revenue with period-over-period delta, orders + AOV, subscribers with new/churned, members), inline SVG charts (revenue and orders by day, subscribers vs churn per week, server population), top products, per-product order counts, audience (follower counts per connected account) and post performance (from post_targets.metrics). Range 7 / 30 / 90 days, CSV export at /dashboard/analytics/export.csv?range=30.

Conversion is currently *orders per product*: product-view tracking is not wired into the store yet, so view→order conversion cannot be computed.

The scheduler task analytics.rollup (hourly) writes per-tenant daily metrics into analytics_daily (revenue_cents, orders, new_members, players_peak, posts_published, active_subs), which the public API exposes at GET /api/v1/analytics/summary.

Notifications

$app->make('notify')->send($userId, $type, $title, $body, $link, $tenantId) stores an in-app notification and emails the user when they have a verified email and email notifications on. Per-type preferences (orders, security, social, servers, automations, system) live in users.privacy.notify and are managed at /dashboard/notification-settings; security alerts cannot be muted. owners($tenantId, …) notifies every owner/admin of a tenant.