Conversation
📝 WalkthroughWalkthroughThis PR integrates PostHog analytics into the app: adds an analytics library and configuration, wraps the app with ChangesPostHog Analytics Integration
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant Screen
participant useValidationAnalytics
participant PostHog
User->>Screen: complete action (upload/create/generate)
Screen->>useValidationAnalytics: capture(eventName, properties)
useValidationAnalytics->>PostHog: identify(clerkId) if needed
useValidationAnalytics->>PostHog: capture(eventName, definedAnalyticsProperties)
sequenceDiagram
participant RootLayout
participant AnalyticsIdentity
participant ConvexAuth
participant PostHog
RootLayout->>AnalyticsIdentity: mount with auth/onboarding context
AnalyticsIdentity->>ConvexAuth: check auth state, query getMe
ConvexAuth-->>AnalyticsIdentity: user or null
alt user authenticated
AnalyticsIdentity->>PostHog: identify(clerkId, properties)
else no user
AnalyticsIdentity->>PostHog: reset()
end
Possibly related issues
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Superseded by #144, which brings the validation analytics foundation onto the current codebase and completes the broader analytics execution/founder-observability work for #76-#84. Keeping this PR only as historical context while #144 is under review; it should not be merged. Once #144 lands, this PR can be closed as superseded. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/contexts/integrations/CONTEXT.md`:
- Around line 23-26: The note currently reads like the Validation Student Code
already lives only in Dayova data, but the current sync path still pulls
validationStudentCode from Clerk unsafeMetadata and copies it into Convex.
Reword the PostHog/Validation Phase note in CONTEXT.md to clearly distinguish
the target state from the present implementation, or add a brief migration
caveat that mentions the Clerk unsafeMetadata to Convex boundary so readers
understand what is current versus planned.
In `@src/components/analytics-identity.tsx`:
- Around line 35-48: Limit the payload passed to posthog.identify in
analytics-identity.tsx to the stable properties that are actually documented,
keeping clerkId and validationStudentCode in definedAnalyticsProperties and
removing the extra person fields unless there is a documented need for them. If
any additional properties must remain, update the surrounding analytics-identify
logic or integrations guidance to explicitly justify each one and explain how it
is handled.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 70ff7b18-c055-4e50-91c2-d78c59d62441
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (16)
.env.exampleapp.jsonconvex/schema.tsconvex/users.tsdocs/contexts/integrations/CONTEXT.mddocs/contexts/platform/CONTEXT.mddocs/contexts/product/CONTEXT.mdpackage.jsonsrc/app/_layout.tsxsrc/app/entry/new.tsxsrc/app/learning-plans/[planId]/generating.tsxsrc/app/learning-plans/new.tsxsrc/components/analytics-identity.tsxsrc/components/ui/surface.tsxsrc/context/AuthContext.tsxsrc/lib/analytics.ts
💤 Files with no reviewable changes (1)
- src/components/ui/surface.tsx
| ## Notes | ||
|
|
||
| - PostHog identifies validation-phase students with Clerk's stable user ID. The Validation Student Code should live in Dayova data, not Clerk auth metadata, and should be sent to PostHog as a profile property when present. | ||
| - PostHog tracking is identified-only during the Validation Phase. Anonymous pre-auth app activity, autocapture, lifecycle events, and session replay are intentionally out of scope unless login or onboarding becomes a measured blocker. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify how validationStudentCode is sourced and synced.
rg -nC3 'validationStudentCode' src/context/AuthContext.tsx convex/users.ts convex/schema.tsRepository: Dayova/dayova-mvp
Length of output: 3207
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,60p' docs/contexts/integrations/CONTEXT.md | cat -nRepository: Dayova/dayova-mvp
Length of output: 2218
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '330,410p' src/context/AuthContext.tsx | cat -nRepository: Dayova/dayova-mvp
Length of output: 3407
Clarify whether this is the target state or the current sync path. validationStudentCode is still read from Clerk unsafeMetadata and copied into Convex today, so this note reads like a completed state. Add a short migration caveat or reword it to describe the current boundary.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/contexts/integrations/CONTEXT.md` around lines 23 - 26, The note
currently reads like the Validation Student Code already lives only in Dayova
data, but the current sync path still pulls validationStudentCode from Clerk
unsafeMetadata and copies it into Convex. Reword the PostHog/Validation Phase
note in CONTEXT.md to clearly distinguish the target state from the present
implementation, or add a brief migration caveat that mentions the Clerk
unsafeMetadata to Convex boundary so readers understand what is current versus
planned.
| posthog.identify( | ||
| user.clerkId, | ||
| definedAnalyticsProperties({ | ||
| clerk_id: user.clerkId, | ||
| convex_user_id: convexUser?._id, | ||
| email: user.email, | ||
| name: user.name, | ||
| birth_date: user.birthDate, | ||
| grade: user.grade, | ||
| school_type: user.schoolType, | ||
| state: user.state, | ||
| avatar_url: user.avatarUrl, | ||
| validation_student_code: convexUser?.validationStudentCode, | ||
| }), |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if consent or data processing agreements are documented anywhere.
rg -niC2 'consent|gdpr|ccpa|data.process|privacy.policy' docs/ .env.example README.md --type=md || echo "No consent/privacy docs found"Repository: Dayova/dayova-mvp
Length of output: 185
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Files ==\n'
git ls-files | rg 'src/components/analytics-identity\.tsx|integrations|privacy|consent|posthog|analytics' || true
printf '\n== analytics-identity.tsx ==\n'
sed -n '1,220p' src/components/analytics-identity.tsx
printf '\n== docs mentions ==\n'
rg -n -C 3 'posthog|clerk_id|validation_student_code|identify|analytics|person properties|email|birth_date|grade|school_type|state|avatar_url' . --glob '!**/node_modules/**' --glob '!**/.git/**' || trueRepository: Dayova/dayova-mvp
Length of output: 50373
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== File list for docs ==\n'
git ls-files | rg '(^|/)(README|docs|integrations|privacy|policy).*\.(md|txt)$|(^|/)README\.md$' || true
printf '\n== Candidate docs content ==\n'
for f in $(git ls-files | rg '(^|/)(README|docs|integrations|privacy|policy).*\.(md|txt)$|(^|/)README\.md$'); do
echo "--- $f ---"
sed -n '1,220p' "$f"
doneRepository: Dayova/dayova-mvp
Length of output: 23292
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('src/components/analytics-identity.tsx')
print(p.exists(), p)
if p.exists():
text = p.read_text()
for needle in ['posthog.identify', 'definedAnalyticsProperties', 'clerk_id', 'validation_student_code']:
print(f'\n## {needle}')
idx = text.find(needle)
if idx != -1:
start = text.rfind('\n', 0, idx-200)
end = text.find('\n', idx+400)
print(text[max(0, idx-200):idx+500])
PYRepository: Dayova/dayova-mvp
Length of output: 2778
Limit the PostHog identify payload
src/components/analytics-identity.tsx:35 sends email, name, birth_date, grade, school_type, state, and avatar_url, but the integrations doc only calls out clerk_id and validation_student_code. Trim this to the stable identifiers, or add explicit guidance for why each extra person property is needed and how it’s handled.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/analytics-identity.tsx` around lines 35 - 48, Limit the
payload passed to posthog.identify in analytics-identity.tsx to the stable
properties that are actually documented, keeping clerkId and
validationStudentCode in definedAnalyticsProperties and removing the extra
person fields unless there is a documented need for them. If any additional
properties must remain, update the surrounding analytics-identify logic or
integrations guidance to explicitly justify each one and explain how it is
handled.
Summary
Adds validation-phase PostHog analytics for the Expo app and wires identified student profiles through the existing Clerk/Convex identity flow.
Changes include:
EXPO_PUBLIC_POSTHOG_API_KEYis set.validationStudentCodeinto Convex so PostHog profiles can link back to the Confluence validation student table.knipremains green.Related Issues
Foundation for #76.
Related follow-up slices: #77, #78, #79, #80, #81, #82, #83, #84.
This PR intentionally does not close those issues; they cover the remaining execution/recovery tracking work.
Why
The current validation plan needs behavioral data tied to real validation students. This PR establishes the analytics and identity foundation without broadening product scope beyond the Validation Phase.
Validation
pnpm checkpnpm check:unusedgit diff --checkwsl coderabbit doctorwsl coderabbit review --agent --type uncommittedwsl coderabbit review --agent --type committed --base origin/mainCodeRabbit completed with 0 findings for both committed and uncommitted review scopes.
Notes
validationStudentCodeis synced from Clerk unsafe metadata as a temporary analytics join key. It is not used for authorization or permissions.Summary by CodeRabbit
New Features
Bug Fixes
Documentation