Skip to content

fix: anonymized author ids in doubt apis#703

Merged
knoxiboy merged 2 commits into
knoxiboy:mainfrom
madsysharma:bug/auth-id-exposed
Jun 30, 2026
Merged

fix: anonymized author ids in doubt apis#703
knoxiboy merged 2 commits into
knoxiboy:mainfrom
madsysharma:bug/auth-id-exposed

Conversation

@madsysharma

@madsysharma madsysharma commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

User description

Description

Stops the doubt and reply APIs from exposing a post author's real identity to other users. Anonymous doubts/replies now return only an anonymized, non-reversible handle plus a server-computed isOwnPost flag; the author's userEmail (and internal fields like the embedding vector) never leave the server.

Related Issue

Closes #657

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Test addition or update
  • Documentation update

Problem

Both GET /api/doubts and GET /api/doubts/[id] selected ...getTableColumns(doubtsTable) and returned the row verbatim, and GET /api/replies returned full reply rows. That payload includes doubts.userEmail / replies.userEmail: the author's real email. The UI showed a "Student" style label, but the email was sitting in the JSON (and was even rendered directly: DoubtCard displayed userEmail.split('@')[0]). The server-rendered permalink page also passed the full row into a client component, re-leaking it through the RSC payload.

Result: any user (in some paths, even unauthenticated) could read another user's email from the network response despite the "anonymous" presentation: which is an Excessive Data Exposure / Broken Object Property-Level auth issue.

Root cause

No serialization boundary between the DB row and the API response for doubts/replies, so internal/identifying columns flowed straight to clients (the classroom-members endpoint, GET /api/rooms/members, already does this correctly: privileged roles see emails, everyone else gets a Student_<id> handle. This PR brings doubts/replies up to that same standard.)

Fix

A single serialization chokepoint, then route every author-facing response through it.

src/lib/anonymity.ts (new file)

  • getAnonymousHandle(email) -> deterministic, salted, non-reversible Student_XXXXX handle. It is base36(first 40 bits of SHA-256(salt + ":" + email)), salted with ANON_HANDLE_SALT so handles can't be pre-computed from candidate emails. Deterministic so an author reads consistently within a thread; returns "Anonymous" when there is no author.
  • getAnonymousInitial(email) -> avatar letter derived from the handle (never the email).
  • toPublicDoubt / toPublicReply (aliases of toPublicAuthored) -> strip userEmail, embedding, and deletedAt; attach author, authorInitial, and isOwnPost (computed server-side from the session). All other fields (content, tags, likes, hasLiked, replyCount, hasUpvoted, etc.) pass through untouched.

Serialized routes

  • GET /api/doubts (list)
  • GET /api/doubts/[id] (detail)
  • POST /api/doubts (create: author's own; still sanitized, isOwnPost: true)
  • GET /api/replies (list)
  • POST /api/replies (create: author's own; still sanitized)
  • app/doubts/[id]/page.tsx: sanitizes the row before handing it to the client component (RSC props are client-visible). Server-side authorization checks above still use the raw row.

Frontend changes

  • DoubtCard and DoubtRepliesModal now render the author handle / authorInitial and use the server isOwnPost flag for ownership controls and the "(YOU)" indicator, instead of comparing raw emails on the client.
  • Doubt and Reply types gain author?, authorInitial?, isOwnPost?.

Controlled exceptions

The real identity stays available server-side for legitimate use:

  • the author themselves (isOwnPost: true)
  • moderation (the moderation_logs table and admin views: a privileged, authenticated surface, untouched here)
  • notifications / karma / ownership (server-side only, never echoed to a client)
  • classroom member lists, which already gate emails behind privileged roles.

See docs/PRIVACY.md for the full model.

Testing

  • Unit testing: src/__tests__/lib/anonymity.test.ts: handle is deterministic, salted, formatted, case-insensitive, and never contains the email or its local-part; serializer strips userEmail/embedding/deletedAt, sets isOwnPost correctly, preserves other fields, and never serializes the author email anywhere in the output.
  • Integration testing (the issue's A/B scenario): src/__tests__/api/doubts-anonymity.test.ts: User A authors an anonymous community doubt; User B and an anonymous viewer fetch it and receive the handle + isOwnPost: false with no userEmail/email/embedding in the response; the author gets isOwnPost: true but still no raw email.
  • Updated src/__tests__/components/DoubtCard.test.tsx to assert the handle is rendered (not the email local-part).
  • npx tsc --noEmit clean; npm test green (36 suites / 185 tests); eslint clean on changed files.

Edge cases

  • Unauthenticated viewers: isOwnPost is false, handle still shown, no identifiers leak.
  • RSC leak: permalink page sanitizes before crossing to the client; the raw row is only used for server-side auth checks.
  • Own content: create responses and the author's own reads are sanitized too (consistent shape; isOwnPost: true conveys ownership without an email).
  • Embedding bloat: dropping embedding from responses also removes a large internal vector from every doubt payload (a payload-size win).
  • Pseudonymity vs. unlinkability: handles are intentionally stable per author (for thread readability), matching the existing members-list behavior; documented in docs/PRIVACY.md.

Documentation

  • docs/PRIVACY.md: new "Privacy Model" doc (guarantee, exposed vs. hidden fields, handle derivation, enforcement points, ANON_HANDLE_SALT).
  • README.md: "Privacy Model" section under Features.
  • CONTRIBUTING.md: API Response Contract rule: doubt/reply responses must go through toPublicDoubt/toPublicReply; never return raw rows.
  • .env.example: documents ANON_HANDLE_SALT.

Checklist

  • Tested locally; tsc, test, and eslint pass
  • Follows existing code style (TypeScript, no new any)
  • No unrelated changes; no new dependencies; no schema/migration changes
  • Added comments and docs where behavior/contract changed
  • Linked the related issue above

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Doubts and replies now display anonymized author handles and initials.
    • A server-computed “your post” (ownership) indicator is shown consistently across list, detail, and UI components.
  • Bug Fixes

    • API responses and permalink rendering no longer expose private author identifiers or internal author fields.
    • Reply/doubt search behavior avoids using author identity signals to determine results.
  • Documentation

    • Added a Privacy Model doc and expanded README/contribution guidance, including ANON_HANDLE_SALT configuration expectations.
  • Tests

    • Added/updated integration and unit tests to prevent identity leakage and verify anonymization/ownership logic.

CodeAnt-AI Description

Keep doubt and reply authors anonymous in all client-facing views

What Changed

  • Doubt and reply responses now show only an anonymized author handle and a server-set isOwnPost value, instead of the author's email
  • Doubt lists, doubt detail pages, reply lists, and create responses now return the same anonymous author format
  • The doubt card and reply modal now display the anonymized handle and use isOwnPost to mark the current user's own posts
  • Added coverage to block identity leaks in API responses and to verify the anonymous author format
  • Documented the privacy rules and the required environment salt for anonymous handles

Impact

✅ Fewer email leaks in doubts and replies
✅ Safer anonymous posting
✅ Clearer own-post markers for students

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Jun 25, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.

@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

@madsysharma is attempting to deploy a commit to the Karan Mani Tripathi 's projects Team on Vercel.

A member of the Team first needs to authorize it.

@codeant-ai

codeant-ai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@github-actions github-actions Bot added gssoc'26 GSSoC program issue level:critical Critical level task type:bug Bug fix type:docs Documentation update labels Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

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

Next review available in: 50 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fdbc016d-33e5-4e6d-9adb-cc88dc02a55d

📥 Commits

Reviewing files that changed from the base of the PR and between d08dc4e and c1e4390.

📒 Files selected for processing (1)
  • src/__tests__/lib/anonymity.test.ts

Walkthrough

Adds anonymized author serialization for doubts and replies, updates API and page responses to use it, adjusts client components to render public author fields, and documents the privacy model and salt configuration.

Changes

Author Anonymity Privacy Model

Layer / File(s) Summary
Anonymity contract and helpers
/.env.example, src/lib/anonymity.ts, src/types/index.ts, README.md, CONTRIBUTING.md, docs/PRIVACY.md, src/__tests__/lib/anonymity.test.ts
ANON_HANDLE_SALT, anonymization helpers, public doubt/reply fields, privacy docs, and utility tests define the anonymized author contract.
Public API payloads
src/app/api/doubts/[id]/route.ts, src/app/api/doubts/route.ts, src/app/api/replies/route.ts, src/app/doubts/[id]/page.tsx, src/__tests__/api/doubts-anonymity.test.ts
Doubt and reply handlers, plus the permalink page, now serialize records through public helpers before returning JSON or client props; the API test asserts identity fields stay absent.
Client display
src/components/DoubtCard.tsx, src/components/DoubtRepliesModal.tsx, src/components/InfiniteDoubtFeed.tsx, src/__tests__/components/DoubtCard.test.tsx
DoubtCard, DoubtRepliesModal, and InfiniteDoubtFeed now render and derive ownership from author, authorInitial, and isOwnPost, and the card test checks the anonymized handle.
Offline pending payloads
src/lib/offline/syncQueue.ts
Pending offline doubt and reply items now use an author field in place of userEmail.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant DoubtsRoute as src/app/api/doubts/route.ts
  participant RepliesRoute as src/app/api/replies/route.ts
  participant Anonymity as src/lib/anonymity.ts
  Client->>DoubtsRoute: GET /api/doubts
  DoubtsRoute->>Anonymity: toPublicDoubt(doubt, email)
  Anonymity-->>DoubtsRoute: publicDoubts
  DoubtsRoute-->>Client: JSON response with anonymized doubts
  Client->>RepliesRoute: GET /api/replies
  RepliesRoute->>Anonymity: toPublicReply(reply, email)
  Anonymity-->>RepliesRoute: publicReplies
  RepliesRoute-->>Client: JSON response with anonymized replies
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • knoxiboy/DoubtDesk#562: Touches the same doubt/reply identity flow and public author fields used by the anonymization helpers here.
  • knoxiboy/DoubtDesk#581: Modifies the same doubt API response path that this PR now wraps with toPublicDoubt.
  • knoxiboy/DoubtDesk#434: Changes the same doubt/reply route handlers that this PR also updates for response shaping.

Suggested labels

type:security

Suggested reviewers

  • knoxiboy
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title concisely matches the main change: anonymizing author identity in doubt APIs.
Linked Issues check ✅ Passed The PR implements server-side anonymization, isOwnPost, tests, and docs for doubt/reply APIs as requested.
Out of Scope Changes check ✅ Passed All listed changes support the anonymity/privacy model; no clearly unrelated edits stand out.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions

Copy link
Copy Markdown

@coderabbitai review

Comment thread src/lib/anonymity.ts
Comment thread src/lib/anonymity.ts
Comment thread src/app/api/doubts/route.ts Outdated
Comment thread src/components/DoubtCard.tsx Outdated
Comment thread src/components/DoubtRepliesModal.tsx Outdated
@codeant-ai

codeant-ai Bot commented Jun 25, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

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

Actionable comments posted: 8

🧹 Nitpick comments (4)
src/components/DoubtRepliesModal.tsx (1)

439-439: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the ownership/anonymous labels to shared constants.

This adds new inline copy for both the fallback author label and the owner suffix, and it already diverges from DoubtCard's "You" badge. Centralizing these labels keeps the anonymous-author UI consistent and matches the TSX path rule. As per path instructions, **/*.tsx files should have "No hardcoded strings (use constants)".

🤖 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/DoubtRepliesModal.tsx` at line 439, The author display in
DoubtRepliesModal is using inline fallback and owner copy, which should be
centralized to match the shared anonymous/ownership labels used elsewhere.
Update the reply author rendering in the DoubtRepliesModal TSX path to use
shared constants for both the anonymous fallback and the owner suffix, and align
the owner badge text with the existing DoubtCard convention instead of hardcoded
strings.

Source: Path instructions

src/__tests__/components/DoubtCard.test.tsx (1)

47-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Strengthen the privacy assertion.

This only proves the anonymized handle renders. It would still pass if the card also leaked a raw email or ignored isOwnPost. Please add a negative assertion for the email text and a positive case for the owner badge when isOwnPost is true.

🤖 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/__tests__/components/DoubtCard.test.tsx` around lines 47 - 48, The
DoubtCard test only checks that the anonymized handle renders, so strengthen it
by adding a negative assertion that the author’s email never appears and a
positive assertion that the owner badge is shown when `isOwnPost` is true.
Update the existing DoubtCard test case in the `DoubtCard`/`DoubtCard.test.tsx`
assertions to cover both the privacy guarantee and the ownership state.
src/components/DoubtCard.tsx (1)

237-241: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the new author strings into shared constants.

Anonymous and both image alt-text templates are now duplicated inline. That makes the anonymity label easy to drift and violates the TSX rule against hardcoded strings. As per path instructions, **/*.tsx files should have "No hardcoded strings (use constants)".

Also applies to: 331-331, 553-553

🤖 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/DoubtCard.tsx` around lines 237 - 241, The author display text
and image alt-text are hardcoded in DoubtCard and duplicated across multiple TSX
locations, so extract them into shared constants and reuse them in the relevant
render paths. Update the DoubtCard component to reference those constants for
the author fallback label and both alt-text templates, including the other
duplicated spots in the same component, so the anonymity wording stays
consistent and avoids inline strings in TSX.

Source: Path instructions

src/__tests__/api/doubts-anonymity.test.ts (1)

78-133: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Add a list-route regression for author-email search.

These detail tests won’t catch the remaining /api/doubts?search=... authorship side-channel. Add a case proving Bob/anonymous cannot find Alice’s anonymous doubt by searching AUTHOR_EMAIL or its local part.

🤖 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/__tests__/api/doubts-anonymity.test.ts` around lines 78 - 133, The
existing doubt detail anonymity tests cover the detail endpoint but not the
`/api/doubts?search=...` list route, so add a regression in the doubts anonymity
test suite for search-based authorship leakage. Extend the existing setup around
`makeRequest`, `currentUser`, `selectResultQueue`, and `authoredDoubt` to verify
that a different signed-in user and an anonymous viewer do not get Alice’s
anonymous doubt returned when searching by `AUTHOR_EMAIL` or its local part,
while still confirming the author is represented only through
`getAnonymousHandle`.
🤖 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 @.env.example:
- Around line 57-61: The current anonymity salt handling still falls back to a
public default when ANON_HANDLE_SALT is unset, which should not be allowed in
production. Update src/lib/anonymity.ts so the salt-loading logic distinguishes
production from dev/test: keep the deterministic fallback only outside
production, and fail closed in production by throwing or rejecting
startup/requests when the variable is missing. Use the existing anonymity handle
generation path and any environment check already in the module to enforce this
behavior consistently.

In `@CONTRIBUTING.md`:
- Line 242: The anonymity contract text is missing the public `authorInitial`
field even though `toPublicAuthored` and the client components rely on it.
Update the `Author anonymity` rule in CONTRIBUTING to explicitly require
`authorInitial` alongside `author` and `isOwnPost`, while still forbidding raw
doubt/reply rows or `getTableColumns(doubtsTable)` from crossing the API
boundary. This should point future routes to the contract defined by
`toPublicDoubt`, `toPublicReply`, and the updated public payload shape from
`src/lib/anonymity.ts`.

In `@src/app/api/doubts/route.ts`:
- Around line 245-248: The GET handler in route.ts still exposes author identity
through search filtering because it matches against doubtsTable.userEmail before
returning anonymized results. Update the doubts query logic in the public search
path to avoid filtering on userEmail entirely, and keep only the anonymized
fields returned by toPublicDoubt; if author-specific lookup is needed, handle it
separately in an authenticated/private path using the existing route handlers
and symbols like toPublicDoubt, doubtsTable, and the GET search builder.

In `@src/components/DoubtCard.tsx`:
- Around line 84-90: The ownership sync in DoubtCard’s useEffect only ever sets
state to true, so when doubt.isOwnPost changes back to false the component can
keep stale owner-only UI. Update the effect to fully mirror doubt.isOwnPost in
the isOwner state, or derive isOwner directly from the prop, and make sure the
logic in DoubtCard stays correct when the card is reused for different posts.

In `@src/components/DoubtRepliesModal.tsx`:
- Around line 71-75: The DoubtRepliesModal effect only ever sets isDoubtOwner to
true, so the previous thread’s owner state can leak when switching doubts.
Update the useEffect in DoubtRepliesModal to reset isDoubtOwner based on the
current doubt.isOwnPost value whenever the modal/thread changes (including when
it becomes false), and keep the dependency list aligned with the state it
derives from.

In `@src/lib/anonymity.ts`:
- Around line 27-30: handleSalt currently falls back to DEFAULT_HANDLE_SALT
whenever ANON_HANDLE_SALT is missing, which should not happen in production.
Update handleSalt in anonymity.ts so that it fails closed in production by
throwing or otherwise refusing to continue when the env var is absent, while
preserving the current fallback behavior only for non-production environments.
Use the existing handleSalt symbol and the environment check already available
in this module to keep the fix localized.
- Around line 84-118: The serializer chokepoint in toPublicAuthored() only
strips userEmail, embedding, and deletedAt, so any joined aliases like userId,
authorId, clerkId, email, or name can still leak identity. Update
AuthoredRow/PublicAuthored and the destructuring in toPublicAuthored() to remove
all author-identifying aliases before returning the safe object, while still
preserving non-identity content fields and deriving author, authorInitial, and
isOwnPost from the viewer/session data.

In `@src/types/index.ts`:
- Around line 221-226: The `Doubt` and `Reply` types in `src/types/index.ts`
currently blur raw DB rows and sanitized API payloads by still allowing
`userEmail` while leaving `author`, `authorInitial`, and `isOwnPost` optional.
Split these into separate raw and public authored shapes, or add a
`PublicAuthored<T>` alias, so the public API type explicitly omits `userEmail`
and requires the anonymized fields. Update the `Doubt`/`Reply` definitions and
any related authored interfaces to use the new public type, keeping raw row
types distinct so TypeScript catches privacy regressions.

---

Nitpick comments:
In `@src/__tests__/api/doubts-anonymity.test.ts`:
- Around line 78-133: The existing doubt detail anonymity tests cover the detail
endpoint but not the `/api/doubts?search=...` list route, so add a regression in
the doubts anonymity test suite for search-based authorship leakage. Extend the
existing setup around `makeRequest`, `currentUser`, `selectResultQueue`, and
`authoredDoubt` to verify that a different signed-in user and an anonymous
viewer do not get Alice’s anonymous doubt returned when searching by
`AUTHOR_EMAIL` or its local part, while still confirming the author is
represented only through `getAnonymousHandle`.

In `@src/__tests__/components/DoubtCard.test.tsx`:
- Around line 47-48: The DoubtCard test only checks that the anonymized handle
renders, so strengthen it by adding a negative assertion that the author’s email
never appears and a positive assertion that the owner badge is shown when
`isOwnPost` is true. Update the existing DoubtCard test case in the
`DoubtCard`/`DoubtCard.test.tsx` assertions to cover both the privacy guarantee
and the ownership state.

In `@src/components/DoubtCard.tsx`:
- Around line 237-241: The author display text and image alt-text are hardcoded
in DoubtCard and duplicated across multiple TSX locations, so extract them into
shared constants and reuse them in the relevant render paths. Update the
DoubtCard component to reference those constants for the author fallback label
and both alt-text templates, including the other duplicated spots in the same
component, so the anonymity wording stays consistent and avoids inline strings
in TSX.

In `@src/components/DoubtRepliesModal.tsx`:
- Line 439: The author display in DoubtRepliesModal is using inline fallback and
owner copy, which should be centralized to match the shared anonymous/ownership
labels used elsewhere. Update the reply author rendering in the
DoubtRepliesModal TSX path to use shared constants for both the anonymous
fallback and the owner suffix, and align the owner badge text with the existing
DoubtCard convention instead of hardcoded strings.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4597a8e6-8059-4858-81fc-b7404b8982ac

📥 Commits

Reviewing files that changed from the base of the PR and between 4f4a59a and e233341.

📒 Files selected for processing (15)
  • .env.example
  • CONTRIBUTING.md
  • README.md
  • docs/PRIVACY.md
  • src/__tests__/api/doubts-anonymity.test.ts
  • src/__tests__/components/DoubtCard.test.tsx
  • src/__tests__/lib/anonymity.test.ts
  • src/app/api/doubts/[id]/route.ts
  • src/app/api/doubts/route.ts
  • src/app/api/replies/route.ts
  • src/app/doubts/[id]/page.tsx
  • src/components/DoubtCard.tsx
  • src/components/DoubtRepliesModal.tsx
  • src/lib/anonymity.ts
  • src/types/index.ts

Comment thread .env.example
Comment thread CONTRIBUTING.md Outdated
Comment thread src/app/api/doubts/route.ts Outdated
Comment thread src/components/DoubtCard.tsx
Comment thread src/components/DoubtRepliesModal.tsx Outdated
Comment thread src/lib/anonymity.ts
Comment thread src/lib/anonymity.ts Outdated
Comment thread src/types/index.ts Outdated
@madsysharma

Copy link
Copy Markdown
Contributor Author

Hi @knoxiboy , please review this PR. I've raised a PR for issue #658 as well, so I'd suggest that PR be reviewed and merged first, followed by this PR. Thank you.

@knoxiboy knoxiboy added level:advanced Advanced level task and removed level:critical Critical level task labels Jun 27, 2026

@knoxiboy knoxiboy left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Implement suggestions from bots to improve the pr

@codeant-ai

codeant-ai Bot commented Jun 29, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai

codeant-ai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai

codeant-ai Bot commented Jun 29, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/app/api/replies/route.ts (1)

89-100: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Map data and remove the stray catch/return; this route is syntactically broken. The handler builds data, but the response maps repliesWithVotes, and the extra catch/raw return before the final catch leaves invalid control flow in src/app/api/replies/route.ts.

🤖 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/app/api/replies/route.ts` around lines 89 - 100, The replies route has
broken control flow and a data mismatch: the handler should return the mapped
`data`/public replies, but it currently returns `repliesWithVotes` and includes
a stray `return` plus duplicate `catch` block. In
`src/app/api/replies/route.ts`, fix the `GET` handler around
`toPublicReply`/`buildErrorResponse` so there is only one `try/catch`, remove
the extra unreachable `return`, and ensure the JSON response uses the anonymized
mapped result instead of the raw replies.

Source: Linters/SAST tools

src/app/api/doubts/route.ts (1)

436-445: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Move the create response out of the tag loop and remove the stray fallback branch. The current return still sits inside the for loop, so tagged requests can exit early, and the extra catch/raw newDoubt path leaves the handler malformed.

🤖 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/app/api/doubts/route.ts` around lines 436 - 445, The create response in
the doubts route is still nested in the tag-processing flow and there is a
leftover fallback branch that makes the handler malformed. Move the
NextResponse.json(toPublicDoubt({ ...newDoubt, tags: savedTags }, email)) return
so it runs after the tag loop in the create handler, and remove the stray raw
return/catch path that follows it. Use the create handler logic around newDoubt,
savedTags, and buildErrorResponse to keep only one valid success path and one
error path.

Source: Linters/SAST tools

🤖 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 `@src/app/api/doubts/route.ts`:
- Around line 259-288: The doubts endpoint is bypassing the intended flow: GET
should return the anonymized public payload, and POST is returning early before
rate limiting, validation, and create logic. Update the route in
`src/app/api/doubts/route.ts` so `GET` uses the public serializer
(`toPublicDoubt` / `publicDoubts`) before responding, and remove the premature
return from `POST` so it continues into the existing create path after
`currentUser()` and request handling.

In `@src/app/api/replies/route.ts`:
- Around line 270-277: The reply creation handler in the route for replies has a
broken control-flow structure and an unsafe fallback response. Fix the
`createReply`/reply-create logic by properly closing the `if` and `try` blocks
so the code parses correctly, and ensure every successful return uses
`toPublicReply(newReply[0], email)` instead of returning the raw reply object.
Keep the error handling via `buildErrorResponse` intact and remove the stray
`return NextResponse.json(newReply[0])` path so no response leaks `userEmail`.

---

Outside diff comments:
In `@src/app/api/doubts/route.ts`:
- Around line 436-445: The create response in the doubts route is still nested
in the tag-processing flow and there is a leftover fallback branch that makes
the handler malformed. Move the NextResponse.json(toPublicDoubt({ ...newDoubt,
tags: savedTags }, email)) return so it runs after the tag loop in the create
handler, and remove the stray raw return/catch path that follows it. Use the
create handler logic around newDoubt, savedTags, and buildErrorResponse to keep
only one valid success path and one error path.

In `@src/app/api/replies/route.ts`:
- Around line 89-100: The replies route has broken control flow and a data
mismatch: the handler should return the mapped `data`/public replies, but it
currently returns `repliesWithVotes` and includes a stray `return` plus
duplicate `catch` block. In `src/app/api/replies/route.ts`, fix the `GET`
handler around `toPublicReply`/`buildErrorResponse` so there is only one
`try/catch`, remove the extra unreachable `return`, and ensure the JSON response
uses the anonymized mapped result instead of the raw replies.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3d116ad8-aca9-4cfc-b70c-933aa2aeb401

📥 Commits

Reviewing files that changed from the base of the PR and between e233341 and 2a49d44.

📒 Files selected for processing (3)
  • src/app/api/doubts/[id]/route.ts
  • src/app/api/doubts/route.ts
  • src/app/api/replies/route.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/api/doubts/[id]/route.ts

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/app/api/replies/route.ts (1)

89-100: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Map data and remove the stray catch/return; this route is syntactically broken. The handler builds data, but the response maps repliesWithVotes, and the extra catch/raw return before the final catch leaves invalid control flow in src/app/api/replies/route.ts.

🤖 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/app/api/replies/route.ts` around lines 89 - 100, The replies route has
broken control flow and a data mismatch: the handler should return the mapped
`data`/public replies, but it currently returns `repliesWithVotes` and includes
a stray `return` plus duplicate `catch` block. In
`src/app/api/replies/route.ts`, fix the `GET` handler around
`toPublicReply`/`buildErrorResponse` so there is only one `try/catch`, remove
the extra unreachable `return`, and ensure the JSON response uses the anonymized
mapped result instead of the raw replies.

Source: Linters/SAST tools

src/app/api/doubts/route.ts (1)

436-445: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Move the create response out of the tag loop and remove the stray fallback branch. The current return still sits inside the for loop, so tagged requests can exit early, and the extra catch/raw newDoubt path leaves the handler malformed.

🤖 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/app/api/doubts/route.ts` around lines 436 - 445, The create response in
the doubts route is still nested in the tag-processing flow and there is a
leftover fallback branch that makes the handler malformed. Move the
NextResponse.json(toPublicDoubt({ ...newDoubt, tags: savedTags }, email)) return
so it runs after the tag loop in the create handler, and remove the stray raw
return/catch path that follows it. Use the create handler logic around newDoubt,
savedTags, and buildErrorResponse to keep only one valid success path and one
error path.

Source: Linters/SAST tools

🤖 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 `@src/app/api/doubts/route.ts`:
- Around line 259-288: The doubts endpoint is bypassing the intended flow: GET
should return the anonymized public payload, and POST is returning early before
rate limiting, validation, and create logic. Update the route in
`src/app/api/doubts/route.ts` so `GET` uses the public serializer
(`toPublicDoubt` / `publicDoubts`) before responding, and remove the premature
return from `POST` so it continues into the existing create path after
`currentUser()` and request handling.

In `@src/app/api/replies/route.ts`:
- Around line 270-277: The reply creation handler in the route for replies has a
broken control-flow structure and an unsafe fallback response. Fix the
`createReply`/reply-create logic by properly closing the `if` and `try` blocks
so the code parses correctly, and ensure every successful return uses
`toPublicReply(newReply[0], email)` instead of returning the raw reply object.
Keep the error handling via `buildErrorResponse` intact and remove the stray
`return NextResponse.json(newReply[0])` path so no response leaks `userEmail`.

---

Outside diff comments:
In `@src/app/api/doubts/route.ts`:
- Around line 436-445: The create response in the doubts route is still nested
in the tag-processing flow and there is a leftover fallback branch that makes
the handler malformed. Move the NextResponse.json(toPublicDoubt({ ...newDoubt,
tags: savedTags }, email)) return so it runs after the tag loop in the create
handler, and remove the stray raw return/catch path that follows it. Use the
create handler logic around newDoubt, savedTags, and buildErrorResponse to keep
only one valid success path and one error path.

In `@src/app/api/replies/route.ts`:
- Around line 89-100: The replies route has broken control flow and a data
mismatch: the handler should return the mapped `data`/public replies, but it
currently returns `repliesWithVotes` and includes a stray `return` plus
duplicate `catch` block. In `src/app/api/replies/route.ts`, fix the `GET`
handler around `toPublicReply`/`buildErrorResponse` so there is only one
`try/catch`, remove the extra unreachable `return`, and ensure the JSON response
uses the anonymized mapped result instead of the raw replies.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3d116ad8-aca9-4cfc-b70c-933aa2aeb401

📥 Commits

Reviewing files that changed from the base of the PR and between e233341 and 2a49d44.

📒 Files selected for processing (3)
  • src/app/api/doubts/[id]/route.ts
  • src/app/api/doubts/route.ts
  • src/app/api/replies/route.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/api/doubts/[id]/route.ts
🛑 Comments failed to post (2)
src/app/api/doubts/route.ts (1)

259-288: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the serializer is in GET and no GET pagination variables are referenced at the top of POST.
sed -n '250,300p' src/app/api/doubts/route.ts

Repository: knoxiboy/DoubtDesk

Length of output: 1566


🏁 Script executed:

#!/bin/bash
nl -ba src/app/api/doubts/route.ts | sed -n '245,320p'

Repository: knoxiboy/DoubtDesk

Length of output: 192


🏁 Script executed:

#!/bin/bash
sed -n '245,320p' src/app/api/doubts/route.ts | cat -n

Repository: knoxiboy/DoubtDesk

Length of output: 2855


Restore the public serializer in GET and remove the early POST return.
GET still returns raw doubts, and POST exits before rate limiting, validation, and create logic, so the endpoint never creates a doubt.

🤖 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/app/api/doubts/route.ts` around lines 259 - 288, The doubts endpoint is
bypassing the intended flow: GET should return the anonymized public payload,
and POST is returning early before rate limiting, validation, and create logic.
Update the route in `src/app/api/doubts/route.ts` so `GET` uses the public
serializer (`toPublicDoubt` / `publicDoubts`) before responding, and remove the
premature return from `POST` so it continues into the existing create path after
`currentUser()` and request handling.
src/app/api/replies/route.ts (1)

270-277: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect POST response construction and development-branch braces.
sed -n '250,280p' src/app/api/replies/route.ts

Repository: knoxiboy/DoubtDesk

Length of output: 1459


🏁 Script executed:

#!/bin/bash
# Inspect the full reply route around the POST handler to understand control flow and response shaping.
sed -n '1,340p' src/app/api/replies/route.ts

Repository: knoxiboy/DoubtDesk

Length of output: 9862


🏁 Script executed:

#!/bin/bash
# Show exact line numbers around the POST handler tail to resolve the brace and return structure.
nl -ba src/app/api/replies/route.ts | sed -n '240,290p'

Repository: knoxiboy/DoubtDesk

Length of output: 192


🏁 Script executed:

#!/bin/bash
# Get numbered lines with a plain-text fallback to inspect the tail of the POST handler.
python3 - <<'PY'
from pathlib import Path
p = Path('src/app/api/replies/route.ts')
for i, line in enumerate(p.read_text().splitlines(), 1):
    if 245 <= i <= 290:
        print(f"{i:4d}: {line}")
PY

Repository: knoxiboy/DoubtDesk

Length of output: 1807


Fix the reply-create response path. The block here doesn’t parse as written, and the non-development branch still returns raw newReply[0] with userEmail; close the if/try structure and return toPublicReply(newReply[0], email) on every path.

🧰 Tools
🪛 Biome (2.5.0)

[error] 277-277: Expected a statement but instead found 'catch (error)'.

(parse)

🪛 GitHub Check: TypeScript Check

[failure] 277-277:
'try' expected.

🤖 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/app/api/replies/route.ts` around lines 270 - 277, The reply creation
handler in the route for replies has a broken control-flow structure and an
unsafe fallback response. Fix the `createReply`/reply-create logic by properly
closing the `if` and `try` blocks so the code parses correctly, and ensure every
successful return uses `toPublicReply(newReply[0], email)` instead of returning
the raw reply object. Keep the error handling via `buildErrorResponse` intact
and remove the stray `return NextResponse.json(newReply[0])` path so no response
leaks `userEmail`.

Source: Linters/SAST tools

@madsysharma
madsysharma force-pushed the bug/auth-id-exposed branch from 2a49d44 to d08dc4e Compare June 29, 2026 21:54
@github-actions github-actions Bot added size/l and removed size/xl labels Jun 29, 2026
@madsysharma
madsysharma requested a review from knoxiboy June 29, 2026 21:56
@madsysharma

Copy link
Copy Markdown
Contributor Author

Hi @knoxiboy , have included the suggested changes. Please review this PR. (NOTE: the build and TypeScript errors shown were already present prior to my changes). Thanks.

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/offline/syncQueue.ts (1)

171-180: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Return the full public-author shape for pending items.

Line 173 and Line 191 only rename userEmail to author, but the offline payloads still miss the fields the UI now relies on. DoubtCard uses authorInitial and isOwnPost, and DoubtRepliesModal uses isOwnPost for right-side alignment and the (YOU) label. As written, the current user's own pending doubts/replies render like someone else's post.

Suggested fix
 export async function getPendingDoubts(): Promise<any[]> {
     const queue = await getQueue();
     return queue
         .filter(item => item.url === "/api/doubts")
         .map(item => ({
             id: `pending-${item.id}`,
             author: "Pending User",
+            authorInitial: "P",
             subject: item.payload.subject || "Subject",
             content: item.payload.content || "",
             imageUrl: item.payload.imageUrl || "",
             tags: (item.payload.tags || []).map((t: string) => ({ name: t })),
             isSolved: "unsolved",
             createdAt: item.payload.createdAt || new Date(item.timestamp).toISOString(),
+            isOwnPost: true,
             isPendingSync: true
         }));
 }

 export async function getPendingReplies(doubtId: number): Promise<any[]> {
     const queue = await getQueue();
     return queue
         .filter(item => item.url === "/api/replies" && Number(item.payload.doubtId) === Number(doubtId))
         .map(item => ({
             id: `pending-${item.id}`,
             doubtId,
             author: "Pending User",
             type: item.payload.type || "comment",
             content: item.payload.content || "",
             imageUrl: item.payload.imageUrl || "",
             upvotes: 0,
             createdAt: item.payload.createdAt || new Date(item.timestamp).toISOString(),
+            isOwnPost: true,
             isPendingSync: true
         }));
 }

Also applies to: 188-197

🤖 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/lib/offline/syncQueue.ts` around lines 171 - 180, The pending-item
mapping in syncQueue.ts is only renaming userEmail to author, but it still omits
UI-dependent public-author fields. Update the pending doubt/reply objects
created in the offline queue mapping to include the full shape expected by
DoubtCard and DoubtRepliesModal, especially authorInitial and isOwnPost
alongside author. Use the existing pending item data and current user identity
to compute those fields so the user’s own pending posts render with the correct
alignment and “(YOU)” label.
🧹 Nitpick comments (1)
src/components/DoubtCard.tsx (1)

235-239: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the anonymous fallback into a shared constant.

These changed render paths now inline the same "Anonymous" label in three places, which makes the visible name and image alt text easy to drift.

Proposed fix
+const ANONYMOUS_AUTHOR_LABEL = "Anonymous";
+
 export default function DoubtCard({ doubt, onUpdate, onViewAISolution, role, openRepliesOnMount = false, disableModal = false, onCommentClick }: DoubtCardProps) {
+    const authorLabel = doubt.author || ANONYMOUS_AUTHOR_LABEL;
 
@@
-                                {doubt.author || 'Anonymous'}
+                                {authorLabel}
@@
-                                alt={`Doubt image for ${doubt.subject} by ${doubt.author || 'Anonymous'}`}
+                                alt={`Doubt image for ${doubt.subject} by ${authorLabel}`}
@@
-                            alt={`Full view of doubt image for ${doubt.subject} by ${doubt.author || 'Anonymous'}`}
+                            alt={`Full view of doubt image for ${doubt.subject} by ${authorLabel}`}

As per path instructions, **/*.tsx: Review for: - No hardcoded strings (use constants).

Also applies to: 329-329, 551-551

🤖 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/DoubtCard.tsx` around lines 235 - 239, The DoubtCard render
paths are hardcoding the same anonymous fallback label in multiple places, so
extract that value into a shared constant and reuse it for the visible name and
any related alt text. Update the affected JSX in DoubtCard so the fallback for
doubt.author and the other matching render paths all reference the same
constant, keeping the anonymous label consistent across the component.

Source: Path instructions

🤖 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 `@src/__tests__/lib/anonymity.test.ts`:
- Around line 54-57: Restore NODE_ENV to its original unset state in the
anonymity test cleanup: the afterEach block currently assigns
mutableEnv.NODE_ENV = origEnv, which leaves NODE_ENV defined when origEnv was
undefined. Update the cleanup logic in the afterEach callback so it deletes
NODE_ENV when the saved original value is undefined, and only reassigns it when
a real value exists; keep the ANON_HANDLE_SALT restore logic alongside it.

---

Outside diff comments:
In `@src/lib/offline/syncQueue.ts`:
- Around line 171-180: The pending-item mapping in syncQueue.ts is only renaming
userEmail to author, but it still omits UI-dependent public-author fields.
Update the pending doubt/reply objects created in the offline queue mapping to
include the full shape expected by DoubtCard and DoubtRepliesModal, especially
authorInitial and isOwnPost alongside author. Use the existing pending item data
and current user identity to compute those fields so the user’s own pending
posts render with the correct alignment and “(YOU)” label.

---

Nitpick comments:
In `@src/components/DoubtCard.tsx`:
- Around line 235-239: The DoubtCard render paths are hardcoding the same
anonymous fallback label in multiple places, so extract that value into a shared
constant and reuse it for the visible name and any related alt text. Update the
affected JSX in DoubtCard so the fallback for doubt.author and the other
matching render paths all reference the same constant, keeping the anonymous
label consistent across the component.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 70519d49-1ff4-4a3b-bc93-9f9d13e64d79

📥 Commits

Reviewing files that changed from the base of the PR and between 2a49d44 and d08dc4e.

📒 Files selected for processing (17)
  • .env.example
  • CONTRIBUTING.md
  • README.md
  • docs/PRIVACY.md
  • src/__tests__/api/doubts-anonymity.test.ts
  • src/__tests__/components/DoubtCard.test.tsx
  • src/__tests__/lib/anonymity.test.ts
  • src/app/api/doubts/[id]/route.ts
  • src/app/api/doubts/route.ts
  • src/app/api/replies/route.ts
  • src/app/doubts/[id]/page.tsx
  • src/components/DoubtCard.tsx
  • src/components/DoubtRepliesModal.tsx
  • src/components/InfiniteDoubtFeed.tsx
  • src/lib/anonymity.ts
  • src/lib/offline/syncQueue.ts
  • src/types/index.ts
✅ Files skipped from review due to trivial changes (4)
  • .env.example
  • CONTRIBUTING.md
  • docs/PRIVACY.md
  • README.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/app/api/doubts/[id]/route.ts
  • src/tests/components/DoubtCard.test.tsx
  • src/app/doubts/[id]/page.tsx
  • src/tests/api/doubts-anonymity.test.ts
  • src/app/api/replies/route.ts
  • src/components/DoubtRepliesModal.tsx
  • src/lib/anonymity.ts
  • src/types/index.ts

Comment thread src/__tests__/lib/anonymity.test.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@knoxiboy
knoxiboy merged commit 68ea382 into knoxiboy:main Jun 30, 2026
11 of 16 checks passed
@github-actions github-actions Bot added gssoc:approved Approved for GSSoC quality:clean Clean code quality and removed size/l review-needed labels Jun 30, 2026
@madsysharma madsysharma mentioned this pull request Jun 30, 2026
10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved Approved for GSSoC gssoc'26 GSSoC program issue level:advanced Advanced level task quality:clean Clean code quality quality : needs-work type:bug Bug fix type:docs Documentation update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security: Ensure strict anonymity guarantees by preventing exposure of author identifiers in anonymous doubt APIs

2 participants