Skip to content

feat(admin): activation-funnel analytics endpoint (Wave 0, #661) - #666

Merged
lilyshen0722 merged 1 commit into
mainfrom
feat/admin-activation-funnel
Jul 10, 2026
Merged

feat(admin): activation-funnel analytics endpoint (Wave 0, #661)#666
lilyshen0722 merged 1 commit into
mainfrom
feat/admin-activation-funnel

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

First item of the Wave 0 — See & Hear milestone: we can finally answer "of the people who signed up, how many attached an agent, sent a message, and came back?"

What

GET /api/admin/analytics/funnel?days=N (admin-only, rate-limited, days clamped 7–90): daily signup cohorts × {signups, attachedAgent, sentMessage, returnedD1, returnedD7} + totals with rates. Every day in range renders (zeros, not gaps).

Design choices

  • Derived, not tracked: computed from User/AgentInstallation/PG-messages. No new instrumentation, no third-party analytics, nothing leaves the instance — the privacy stance for an OSS product.
  • PG is the message source of truth — the Mongo Message collection is a fallback path (~3 rows in the last 7 days in prod) and would undercount everything. (Separate issue incoming: /api/stats/public currently reads Mongo for messageCount24h and has this exact bug.)
  • Honest proxies, documented in-code: D1/D7 'returned' uses lastActive >= createdAt + N days — a floor-accurate proxy, not event-grade cohorting.

Tests

4-case unit spec: cohort/total/rate math, bot-exclusion in the query, PG queried with cohort ids (and skipped for empty cohorts), non-admin 403.

Next up in the milestone: #662 (admin dashboard tab rendering this endpoint).

🤖 Generated with Claude Code

https://claude.ai/code/session_01MnRCAFgjrrGZxo9VRCmCm9

GET /api/admin/analytics/funnel?days=N — daily signup cohorts with attached-
agent, sent-message, and D1/D7-return counts + totals/rates. Fully derived
from existing data (User, AgentInstallation, PG messages): no new tracking,
no third-party analytics, nothing leaves the instance. Bot User rows excluded.

Honest approximations documented in-code: D1/D7 return is a lastActive proxy;
sentMessage reads PostgreSQL (the primary store — the Mongo Message collection
is a fallback path with ~3 rows/week and would undercount everything).

auth + adminAuth + IP rate limit (test-skipped) per the admin-route pattern.
4-case unit spec: cohort math, bot-exclusion query shape, PG called with the
cohort ids (and skipped when empty), non-admin 403.

Closes #661

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MnRCAFgjrrGZxo9VRCmCm9
@lilyshen0722
lilyshen0722 merged commit 101ae4d into main Jul 10, 2026
10 checks passed
@lilyshen0722
lilyshen0722 deleted the feat/admin-activation-funnel branch July 10, 2026 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant