fix(analytics): track CardView events on direct card route (closes #495)#622
Open
Ridanshi wants to merge 4 commits into
Open
fix(analytics): track CardView events on direct card route (closes #495)#622Ridanshi wants to merge 4 commits into
Ridanshi wants to merge 4 commits into
Conversation
|
@Ridanshi is attempting to deploy a commit to the Prashantkumar Khatri's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Hi @Ridanshi, Thanks for opening this pull request. This PR has been automatically classified based on the files modified. Applied Labels
Primary Review Area
Reviewer@Harxhit has been identified as the primary reviewer for this pull request. If you have any questions regarding the affected area or implementation details, feel free to reach out to the assigned reviewer. Thank you for your contribution! |
CI — Checks FailedBackend — FAIL
Mobile — SKIP
Web — SKIP
Last updated: |
Replace non-deterministic random suffix generation with sequential numeric candidates (my-team → my-team-1 → my-team-2, capped at 10). Wrap team creation in a bounded retry loop (5 attempts) so P2002 constraint violations from concurrent inserts trigger re-allocation rather than surfacing as a 409. The database-level @unique constraint on Team.slug remains the authoritative guard; application logic now recovers gracefully when it fires. Adds slug utility tests (createSlug, generateUniqueSlug determinism and bounds) and team route tests for retry-on-race-condition and retry-exhaustion paths. Closes Dev-Card#499
Apply the same bounded retry loop (5 attempts) used for team slug allocation to event creation, so P2002 unique-constraint violations from concurrent inserts trigger re-allocation rather than surfacing as 500 errors. Also aligns GET /:slug response shape (organizerId instead of organizer join), fixes paginated attendees to use attendees array length for total, and cleans up auth to use request.jwtVerify() inline — consistent with the team routes approach. Co-Authored-By: Ridanshi <ridanshiagarwal2@gmail.com>
Update imports to use .js extensions for ESM compatibility with the project's module resolution convention. Inline TeamMember type fields to avoid the intersection with PublicProfile which does not resolve cleanly without a built shared package.
The GET /api/u/card/:cardId endpoint fetched card data without recording a CardView, bypassing analytics entirely for share-link access. - publicService.getCardById now accepts viewerId and request params and creates a CardView when an authenticated non-owner requests the card - The /card/:cardId route handler performs soft JWT verification (same pattern as /:username and /:username/card/:cardId) to extract viewerId - Source defaults to link for direct card access, consistent with the profile view path; callers may override via ?source= query param - Owner self-views are excluded to match the existing tracking contract Closes Dev-Card#495
daa37be to
6b44b73
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Direct card views via
GET /api/u/card/:cardIdwere silently bypassing analytics. ThegetCardByIdservice function returned card data without creating aCardViewrecord, and the route handler performed no JWT verification — so even authenticated viewers left no analytics trail. This made share-link access invisible to card owners.Root Cause
Two gaps in the existing implementation:
publicService.getCardByIdaccepted no viewer context and created noCardView/card/:cardIdroute did not attempt soft JWT authentication, soviewerIdwas never available even if the service could have used itThe two other public card access paths (
/:usernameand/:username/card/:cardId) both performed soft auth and recorded views — only the direct-card path was missing this.Fix
apps/backend/src/services/publicService.tsgetCardById(app, cardId, viewerId, request)to accept viewer contextCardViewwhenviewerIdis present and is not the card owner, matching the contract ofgetUserCard"link"(consistent with profile views from share links); overridable via?source=query paramapps/backend/src/routes/public.ts/card/:cardIdhandler (same try/catch pattern as/:usernameand/:username/card/:cardId)viewerIdandrequesttogetCardByIdTests
Six new tests added to
src/__tests__/public.test.tscovering the direct card route:{ error: "Card not found" }cardView.createcalled with correct ownerId, cardId, viewerIdcardView.createnot calledcardView.createnot calledsource: "link"in created record?source=webpropagates to CardViewFull suite results: 213 passing, 1 failing (pre-existing analytics mock failure on main, unrelated to this change).
Analytics Integrity
CardViewrecords are append-only; the direct-card path previously created zero records, so adding one per authenticated non-owner visit is strictly additiveviewerId !== card.user.id) is consistent across all three tracked paths