Architecture
The first slice records sanitized SPA page views and provides a workspace administrator overview from the existing chat and Mission Control tables.src/lib/analytics/client.ts is best-effort: analytics failures do not block product actions.
The collector omits query strings and identifier-like path segments, and rejects property names that commonly carry secrets or message content. The overview reads existing product records rather than copying them into a second fact table. It reports chat generations, usage ledger tokens and cost, Mission Control runs, conversations, and explicit analytics events.
Revenue and automations are not reported because a verified workspace-scoped source for those metrics is not wired into this view. Both route authorization and database policies restrict analytics to Orbit staff roles.
Overview metrics and what is not reported
Adding events
1
Add the event name
Add event names to
src/lib/analytics/types.ts.2
Call trackEvent
Call
trackEvent after a successful product action, sending only small, non-sensitive properties.3
Bind workspace context
user_id comes from the authenticated Supabase session. workspace_id must come from the established workspace context.Event catalog
The typed client catalog currently includes page views, conversation and message lifecycle, generation stops, agent and automation lifecycle, project and file actions, and errors. Onlypage_viewed is wired globally today. Other names are an integration contract for product actions; do not claim their charts are populated until their call sites have been connected.
Events use a generated session id scoped to the current browser tab. Supported sources are client, server, api, background, ai, and system. The current browser SDK writes client events.
Database migration and tables
Migration20260926140000_add_workspace_analytics.sql adds the following:
Existing
chat_generations, chat_usage_ledger, chat_threads, and mission_runs remain authoritative for product counts and AI usage.
The overview function is a narrowly scoped SECURITY DEFINER function because the source tables intentionally expose individual rows only to their owners. It checks for an authenticated caller and analytics_is_staff() before aggregating. That helper requires both an existing Orbit staff role and the established @orbitdev.org account domain. Event reads and inserts use the same check. Execute is revoked from PUBLIC and anon and granted to authenticated users; the function itself rejects non-staff callers. It returns aggregate values only. Keep the fixed search path and authorization guard if extending it.
analytics_preferences is workspace scoped; workspace members can read preferences and administrators can change them. The client collector stops recording if analytics or usage tracking is disabled. Preference-management controls remain a follow-up UI integration.
Security and privacy
- Analytics navigation and route access require the existing Orbit staff guard.
- Event reads, event inserts, and aggregate queries independently require an Orbit staff role and an
@orbitdev.orgaccount in the database. - Event inserts bind the actor to
auth.uid(). Staff can read analytics across workspaces; non-staff callers cannot use the aggregate function or read event rows. - The overview returns aggregates and does not expose message contents, stacks, or identifiers for individual users.
- The browser collector strips query strings and masks identifier-like path components. It filters common secret or content property names and bounds string length.
- The event table is append-only for authenticated clients: no update or delete grants are issued.
- Do not introduce a service-role key into the client or use caller-supplied user ids as authorization.
Not-yet-implemented items
The following items have not been implemented in this initial slice:- Larger role permission set (
analytics.view,analytics.ai, and related grants) - Export endpoints
- Event explorer
- Per-user analytics
- Preference-management UI integration