Skip to content

URL: https://mkdocs.justinsforge.com/memory/general/reference_creatortrack_admin_analytics/

CreatorTrack /admin analytics

Owner-gated platform analytics surface at app.creatortrack.ai/admin (dev on the worktree's port). Shows platform-wide and per-user stats built entirely on CreatorTrack's own Postgres. Branch feat/admin-analytics-dashboard (built 2026-07-07); plan at forge/memory/plans/admin-analytics-dashboard-2026-07-07.md.

What it shows

  • Platform tab: total users / workspaces / memberships, DAU / WAU / MAU, signups-per-day and active-users-per-day trend bars, and platform content totals (nodes, finance transactions, campaign emails, CRM contacts, CRM deals).
  • Users tab: every user with last-seen, windowed events / pageviews, nodes created, workspace count. Row click opens the per-user drill-down.
  • User drill-down (/admin/users/[id]): last seen, approx sessions (30-min gap heuristic), nodes created, workspaces (with role), activity + pageviews per-day trends, app usage (by node type, event-weighted), and content created by type.

The owner-gated read path (the load-bearing detail)

RLS split discovered during build: - app.activity / app.page_views policies are core.is_owner() OR membership, so the owner identity already sees ALL rows. - core.users / core.memberships / core.workspaces / app.nodes are self/membership-scoped with NO owner bypass, so a plain asUser() read as owner sees only Justin's own rows.

Fix: dedicated owner-gated SECURITY DEFINER functions (migration db/migrations/20260707T214130_..._admin_analytics_owner_gated_read_functions.sql), NOT a widening of RLS (which would change what the owner sees everywhere in the app): - core.admin_platform_overview(days) -> json - core.admin_list_users(days) -> table - core.admin_user_detail(user, days) -> json

They're owned by lifeos_admin (BYPASSRLS) so they read across core/app/finance/campaigns/crm, and EACH starts with if not core.is_owner() then raise ... 42501. The app still connects as the RLS-bound lifeos_app; only these functions cross the boundary. Same pattern as core.list_workspace_members / core.login.

Gate is defense-in-depth: app/(suite)/admin/layout.tsx also notFound()s non-owners via isPersonalAppsOwner(me) (email-based, stronger than raw is_owner), and each page re-checks.

Files

  • Read-model: lib/admin-analytics.ts (types + getPlatformOverview / listUsers / getUserDetail, all via asUser).
  • Route: app/(suite)/admin/ (layout.tsx gate + tabs, page.tsx platform, users/page.tsx, users/[id]/page.tsx), presentational parts in app/(suite)/admin/_components/parts.tsx, styles app/(suite)/admin/admin.css (reuses workspace design tokens, theme-aware).
  • Nav: owner-only "Admin" button in components/workspace/WorkspaceShell.tsx toprow (grid icon).
  • No standalone /api/admin/* routes: pages are Server Components reading the model directly (single source; add JSON endpoints only when the PostHog-embed phase needs client fetches).

Phase 2: PostHog CLOUD (self-host abandoned 2026-07-07)

Self-host attempt on CT 114 forge-posthog failed and the container was DESTROYED. Root cause (proven, do not retry blindly): PostHog has no versioned releases anymore, and master cannot fresh-install because its ClickHouse users.xml needs NEW ClickHouse (enable_materialized_cte) while its from-0001 migrations break on new ClickHouse (KafkaEngine MATERIALIZED removal, projection-mode throw). Only self-host path = pin a months-old commit, no upgrade path. Decision: PostHog Cloud US (free tier 1M events + 5K replays/mo covers the 6-user scale at $0). Setup + instrumentation plan: creatortrack/docs/admin-posthog-phase2.md.

LIVE 2026-07-07: posthog-js in the (suite) layout, gated on runtime POSTHOG_KEY (in ~/.forge-secrets/creatortrack-auth.env, no NEXT_PUBLIC_ inlining). distinct_id = internal user id; workspace = group; env prop separates prod/dev; replay on with all inputs masked; bot traffic auto-dropped by PostHog. Project id 502421 ("Creator Track", US Cloud). Dashboard "CreatorTrack Overview" (8 tiles, env=prod filtered): https://us.posthog.com/project/502421/dashboard/1813862 , also the /admin "Behavior" tab target. Personal API key (insight/dashboard CRUD): ~/.forge-secrets/posthog.env. PostHog counts only users SEEN since 2026-07-07; registered-user truth stays in /admin.

  • [[reference_creatortrack_dev_testing]] (WORKSPACE_DEV_AUTH=1 gives the dev owner session)
  • [[reference_creatortrack_finance_module]] (finance.* content counts)
  • [[reference_forge_data_lifeos_spine]] (the shared Postgres + RLS model)