Skip to content

fix(trust-safety): referral #891, notifications idempotency, support dedup, collaborator RBAC, legal + DPDP docs - #989

Closed
teetangh wants to merge 2 commits into
devfrom
fix/trust-safety-sweep
Closed

fix(trust-safety): referral #891, notifications idempotency, support dedup, collaborator RBAC, legal + DPDP docs#989
teetangh wants to merge 2 commits into
devfrom
fix/trust-safety-sweep

Conversation

@teetangh

Copy link
Copy Markdown
Contributor

Trust & safety sweep — seven scoped correctness/compliance fixes.

Fixes

  1. Referral stash wipe (bug(referrals): signup wipes a stashed referral code when loaded without ?ref= (#885) #891)app/auth/signup/page.tsx:92. Landing without ?ref= no longer clears a previously stashed referral code; only an explicit different code overwrites it. clearPendingReferral import dropped.
  2. Novu idempotency + fail-loudlib/novu/service.ts. Every trigger now carries a deterministic transactionId derived from workflow + recipient(s) + payload (or an explicit dedupeKey), so app-level retries can't double-notify. Unconfigured Novu in production emits a Sentry captureMessage instead of a silent console.warn. scripts/appointments/send-appointment-reminders.ts passes a per-window dedupeKey so the 1h reminder isn't swallowed as a duplicate of the 24h one.
  3. Support dedup + status CASapp/api/user/support-tickets/route.ts:172 reuses an existing open (status NOT IN RESOLVED/CLOSED) ticket for the same paymentId+user instead of creating a duplicate (runtime check, no schema unique). app/api/staff/support-tickets/[ticketId]/responses/route.ts:70 OPEN→IN_PROGRESS is now a status-guarded updateMany CAS so concurrent staff edits don't clobber.
  4. Collaborator permissions + XOR CHECK — permission booleans are set at invite time from invite input (schemas/collaborators.ts, lib/collaborators/service.ts, both app/api/collaborations/{webinar,class}/[planId]/route.ts). Enforced: canSeeAttendees at the participant-roster GETs (app/api/participants/{webinar,class}/[id]/route.ts) — an accepted collaborator sees the roster only if granted. Set-but-not-enforced (no surface yet, terse TODO): canApprovePayment, canViewAnalytics, canEditEvent. Added the webinar/class XOR to prisma/sql/check-constraints.sql (raw-SQL sidecar, mirrors app-level assertCollaboratorPlanXor).
  5. Legal constants (supersedes fix: Revamp legal pages for Razorpay KYC submission #434)app/(pages)/constants.ts sets name: "Practitionist", removes the [ADDRESS] placeholder and its rendered Registered-Address blocks (about/privacy/terms/contactus/refund; unused MapPin import dropped). email/supportEmail kept as placeholders with a loud // TODO: real contact email before launch.
  6. DPDP doc driftlib/compliance/dpdp.ts header corrected: checkConsent is live fail-closed (not "returns true unconditionally") and recordConsent writes a real SHA-256 artifact.
  7. Phone Zod — investigated. Mitigation already exists at both DB write boundaries (app/form/onboarding/page.tsx trims to undefined; app/api/user/[id]/route.ts uses emptyToUndefined). The shared PersonalInfoAndRoleSchema is unused. No change needed.

Notes

  • prisma/sql/check-constraints.sql needs the central migration apply (npm run db:constraints) after the next push/reset — it does not self-apply.
  • No prisma/schema.prisma change; support dedup is a runtime check by design.
  • Supersedes (does not close) fix: Revamp legal pages for Razorpay KYC submission #434.
  • Type-check via CI (local tsc OOM-contended).

Closes #891

🤖 Generated with Claude Code

…ollaborator perms, legal constants, DPDP docstring

Trust & safety sweep bundling seven correctness/compliance fixes:
- Referral stash no longer wiped when landing without ?ref= (#891).
- Novu triggers carry a deterministic transactionId (dedup) and fail loud
  via Sentry when unconfigured in prod; reminders pass a per-window key.
- Payment-linked support tickets dedup against an open ticket; staff status
  transition is now a status-guarded CAS (updateMany).
- Collaborator permission booleans are set at invite time; canSeeAttendees
  is enforced on the participant-roster endpoints.
- Legal constants set name=Practitionist and drop the [ADDRESS] placeholder
  and its rendered blocks; contact emails kept as loud TODO placeholders.
- DPDP header docstring corrected to describe the live fail-closed behavior.
- Webinar/class XOR added to the check-constraints.sql sidecar.

Closes #891
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@teetangh, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2ad31e9b-f247-4dbb-b9bf-7240177e2c38

📥 Commits

Reviewing files that changed from the base of the PR and between 62a41e1 and 5f5fe88.

📒 Files selected for processing (19)
  • app/(pages)/about/page.tsx
  • app/(pages)/constants.ts
  • app/(pages)/contactus/page.tsx
  • app/(pages)/privacy/page.tsx
  • app/(pages)/refund/page.tsx
  • app/(pages)/terms/page.tsx
  • app/api/collaborations/class/[planId]/route.ts
  • app/api/collaborations/webinar/[planId]/route.ts
  • app/api/participants/class/[classId]/route.ts
  • app/api/participants/webinar/[webinarId]/route.ts
  • app/api/staff/support-tickets/[ticketId]/responses/route.ts
  • app/api/user/support-tickets/route.ts
  • app/auth/signup/page.tsx
  • lib/collaborators/service.ts
  • lib/compliance/dpdp.ts
  • lib/novu/service.ts
  • prisma/sql/check-constraints.sql
  • schemas/collaborators.ts
  • scripts/appointments/send-appointment-reminders.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/trust-safety-sweep

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several updates, including removing company address details from public pages, adding granular collaborator permissions with restricted roster access, implementing status-guarded CAS and deduplication for support tickets, persisting referral codes during signup, and introducing deterministic transaction IDs for Novu notifications to prevent duplicate sends. Feedback on these changes highlights a security concern where internal staff notes are leaked to end-users during support ticket deduplication, which requires filtering the returned responses. Additionally, the use of relation filters inside Prisma's findUnique for participant roster queries will cause TypeScript compilation errors; these queries should be updated to use findFirst instead.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread app/api/user/support-tickets/route.ts Outdated
Comment thread app/api/participants/class/[classId]/route.ts Outdated
Comment thread app/api/participants/webinar/[webinarId]/route.ts Outdated
@netlify

netlify Bot commented Jul 11, 2026

Copy link
Copy Markdown

Deploy Preview for familiarise ready!

Name Link
🔨 Latest commit 5f5fe88
🔍 Latest deploy log https://app.netlify.com/projects/familiarise/deploys/6a52998df0be1e0008e1262d
😎 Deploy Preview https://deploy-preview-989--familiarise.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 79 (🟢 up 18 from production)
Accessibility: 99 (🟢 up 3 from production)
Best Practices: 92 (🟢 up 9 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

…response, findFirst for relation filters

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
8.9% Duplication on New Code (required ≤ 3%)
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

💡 Need a hand with PR review? Try Gitar by Sonar!

@teetangh

Copy link
Copy Markdown
Contributor Author

⏭️ Superseded by #995. This branch has been merged into the consolidated integration PR #995, which is the single PR that goes to dev. Do not merge this PR — it's kept open as a draft for granular per-concern review of this specific change. Its Closes/Part of issue links now live on #995.

@teetangh
teetangh marked this pull request as draft July 11, 2026 20:09
@teetangh

Copy link
Copy Markdown
Contributor Author

Closing as superseded by #995 (the consolidated CTO audit fix wave). All commits from this branch are included in #995, which carries the Closes/Part of issue links and is the single PR that merges to dev. The branch is preserved; reopen if you need the isolated diff.

@teetangh teetangh closed this Jul 11, 2026
@teetangh
teetangh deleted the fix/trust-safety-sweep branch July 30, 2026 15: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.

bug(referrals): signup wipes a stashed referral code when loaded without ?ref= (#885)

1 participant