Skip to content

fix(analytics): make follow logging idempotent and prevent duplicate follow events#532

Open
Ridanshi wants to merge 3 commits into
Dev-Card:mainfrom
Ridanshi:fix/follow-log-analytics-poisoning
Open

fix(analytics): make follow logging idempotent and prevent duplicate follow events#532
Ridanshi wants to merge 3 commits into
Dev-Card:mainfrom
Ridanshi:fix/follow-log-analytics-poisoning

Conversation

@Ridanshi

@Ridanshi Ridanshi commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Closes #484

Summary

This PR fixes an analytics integrity issue where repeated follow requests could generate duplicate follow log records and inflate engagement metrics.

The follow operation itself was effectively idempotent, but follow-event logging was not.

Changes

  • Added database-level uniqueness guarantees for follow logs
  • Introduced idempotent follow logging using upsert semantics
  • Prevented duplicate follow events from retries, refreshes, and double-click submissions
  • Added migration to safely handle existing duplicate records before applying uniqueness constraints
  • Preserved existing follow and unfollow functionality

Test Coverage

Added/updated tests covering:

  • Initial follow creation
  • Repeated follow requests
  • Retry scenarios
  • Double-click submissions
  • Concurrent follow attempts
  • Analytics count correctness
  • Different users following the same target
  • Different targets generating independent records

Result

Follow analytics now accurately represent real follow relationships and cannot be inflated through duplicate requests or retries.

Ridanshi added 3 commits June 10, 2026 01:05
… logs

POST /:platform/:targetUsername/log accepted free-form `status` and
`layer` values and wrote them directly to followLog without validation.
Both fields feed analytics counters (totalFollows) and the
follower-state dashboard via `status: 'success'` queries, so an
authenticated user could fabricate successful follow events, inflate
engagement metrics, and manipulate the dashboard.

Fix:
- Add `followLogSchema` (Zod) in validations/follow.validation.ts with
  strict enum allowlists:
    status  → 'success' | 'failed' | 'pending'
    layer   → 'foreground' | 'background'
- Validate request body with safeParse before any database write;
  invalid payloads return 400 without touching followLog.create()
- Remove unsafe free-form defaults ('success' / 'webview') that
  silently accepted omitted fields
- Response body on validation failure contains only { error } —
  no Zod internals, paths, or stack traces are exposed

Layer 1 (API follow) writes status/layer internally and is unaffected.

Tests: 22 cases covering all valid enum combinations, all rejection
paths, DB-not-called guarantee on failure, correct payload written to
DB, and opaque error responses.

Closes Dev-Card#301
FollowLog had no unique constraint, so repeated follow requests (retries,
double-taps, concurrent clicks) each appended a new row — inflating the
totalFollows counter displayed in the analytics dashboard.

Changes:
- schema: add @@unique([followerId, targetUsername, platform]) to FollowLog
- schema: add updatedAt field (required by Prisma upsert)
- migration: deduplicates existing rows (keeps most-recent per group) before
  creating the unique index — safe on a populated database
- routes/follow.ts: replace followLog.create() with followLog.upsert() in
  both the Layer-1 API path and the Layer-2/3/4 manual-log path
- tests: update mocks to upsert; add three idempotency tests verifying the
  correct composite where-key, update/create shape, and multi-target isolation
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

@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.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Hi @Ridanshi,

Thanks for opening this pull request.

This PR has been automatically classified based on the files modified.

Applied Labels

  • backend

Primary Review Area

  • backend

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!

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

CI — All Checks Passed

Backend — PASS

Check Result
Lint PASS
Test PASS
Typecheck PASS

Mobile — SKIP

Check Result
Lint -
Test -

Web — SKIP

Check Result
Check -
Build -

Last updated: Tue, 09 Jun 2026 19:53:20 GMT

@Harxhit Harxhit added critical Includes schema, architecture, or other critical core functionality changes. gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking. labels Jun 10, 2026
@ShantKhatri ShantKhatri requested a review from Harxhit June 13, 2026 07:07
@Harxhit

Harxhit commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

@ShantKhatri She didn't address the changes I asked for.

@ShantKhatri

Copy link
Copy Markdown
Contributor

@ShantKhatri She didn't address the changes I asked for.

Let's discuss all the issues created by @Ridanshi in this week's community call, as I'm not able to understand these issues. Requesting @Ridanshi to please have a short demo on issue reproduction steps.

@Ridanshi

Copy link
Copy Markdown
Contributor Author

@Harxhit @ShantKhatri
Thanks for the feedback. I want to make sure I address exactly what you're looking for, could you point me to the specific comments from your earlier review that I missed? I may have focused too narrowly on the issue description.

If it would help, I'm happy to put together a reproduction script showing the duplicate follow events before and after the fix, or walk through any part of the implementation. Just let me know what would be most useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend critical Includes schema, architecture, or other critical core functionality changes. gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow logging is not idempotent and allows duplicate follow events to inflate analytics

3 participants