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 viaasUser). - Route:
app/(suite)/admin/(layout.tsxgate + tabs,page.tsxplatform,users/page.tsx,users/[id]/page.tsx), presentational parts inapp/(suite)/admin/_components/parts.tsx, stylesapp/(suite)/admin/admin.css(reuses workspace design tokens, theme-aware). - Nav: owner-only "Admin" button in
components/workspace/WorkspaceShell.tsxtoprow (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.
Related¶
- [[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)