Skip to content

feat: add subject-based doubt filtering API (#733) - #743

Closed
anshul23102 wants to merge 9 commits into
knoxiboy:mainfrom
anshul23102:feat/subject-filtering
Closed

feat: add subject-based doubt filtering API (#733)#743
anshul23102 wants to merge 9 commits into
knoxiboy:mainfrom
anshul23102:feat/subject-filtering

Conversation

@anshul23102

@anshul23102 anshul23102 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

User description

Implements issue #733: Subject/category-based filtering.

API endpoint GET /api/doubts/filter filters doubts by classroom and optional subject parameter. Returns filtered doubt list with IDs, subjects, content, resolution status. Supports 'All' parameter to disable filtering.

Closes #733


CodeAnt-AI Description

Add subject-based doubt filtering and restore failing tests

What Changed

  • Added an API to filter classroom doubts by subject, with support for showing all subjects and returning anonymized results with a count
  • Updated teacher insights error messages to clearly show invalid classroom IDs and denied access
  • Fixed broken tests around daily digests, anonymity handling, and database environment cleanup so the test suite runs again
  • Added the latest database migration and journal entry, while removing stale migration entries that no longer match the schema

Impact

✅ Faster subject-based doubt review
✅ Clearer classroom access errors
✅ Fewer broken test runs

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

@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

@anshul23102 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 Jul 3, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.

@codeant-ai

codeant-ai Bot commented Jul 3, 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:intermediate Intermediate level task type:feature New feature labels Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

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

Next review available in: 40 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: 8fedf33d-5a1b-47b7-b958-3e6d2d13e8b6

📥 Commits

Reviewing files that changed from the base of the PR and between 3888278 and 3d9b198.

📒 Files selected for processing (39)
  • drizzle/0008_audit_logs.sql
  • drizzle/0013_silky_gateway.sql
  • drizzle/0017_wild_klaw.sql
  • drizzle/meta/0017_snapshot.json
  • drizzle/meta/_journal.json
  • src/__tests__/api/doubts-filter.test.ts
  • src/__tests__/api/teacher-insights.test.ts
  • src/__tests__/configs/db.test.ts
  • src/__tests__/inngest/digest-functions.test.ts
  • src/__tests__/lib/anonymity.test.ts
  • src/app/api/admin/moderation/route.ts
  • src/app/api/admin/overview/route.ts
  • src/app/api/analytics/export/route.ts
  • src/app/api/analytics/personal/route.ts
  • src/app/api/analytics/route.ts
  • src/app/api/classrooms/[id]/export/route.ts
  • src/app/api/doubts/[id]/upvote/route.ts
  • src/app/api/doubts/action/[id]/route.ts
  • src/app/api/doubts/check-similarity/route.ts
  • src/app/api/doubts/filter/route.ts
  • src/app/api/doubts/route.ts
  • src/app/api/invites/[token]/join/route.ts
  • src/app/api/karma/route.ts
  • src/app/api/organizations/route.ts
  • src/app/api/profile/route.ts
  • src/app/api/recommendations/route.ts
  • src/app/api/replies/vote/route.ts
  • src/app/api/rooms/join/route.ts
  • src/app/api/rooms/members/route.ts
  • src/app/api/rooms/route.ts
  • src/app/api/teacher/analytics/route.ts
  • src/app/api/teacher/insights/route.ts
  • src/app/profile/page.tsx
  • src/inngest/functions.ts
  • src/inngest/karma.ts
  • src/lib/ai/embeddings.ts
  • src/lib/karma/karma-utils.ts
  • src/lib/moderation/moderation.ts
  • src/lib/notifications/service.ts
✨ 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.

Comment thread src/app/api/doubts/filter/route.ts Outdated
Comment on lines +16 to +18
const classroomIdInt = parseInt(classroomId);
if (isNaN(classroomIdInt)) {
return NextResponse.json({ error: "Invalid classroomId" }, { status: 400 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Using parseInt for ID parsing accepts malformed values like 1abc/1e2 and can coerce to unintended classroom IDs, causing incorrect data access. Use the shared strict classroom ID parser (positive safe integer validation) instead of permissive parsing. [incorrect variable usage]

Severity Level: Major ⚠️
- ⚠️ Malformed classroom IDs mapped to unintended classrooms.
- ⚠️ Filter endpoint inconsistent with strict ID parser.
- ⚠️ Potential data leakage across classrooms on user typos.
Steps of Reproduction ✅
1. Inspect the shared classroom ID parser in `src/lib/auth/membership-guard.ts:75-86`:
`parseClassroomId(value)` only accepts numbers or strings matching `/^[1-9]\d*$/`, checks
`Number.isSafeInteger` and `classroomId > 0`, and throws `ApiError(400, "Invalid classroom
ID")` for malformed inputs like `"42abc"` or `"1e2"`, as verified by tests in
`src/__tests__/lib/membership-guard.test.ts:76-80`.

2. In the filter endpoint, `src/app/api/doubts/filter/route.ts:16-19` parses `classroomId`
with `const classroomIdInt = parseInt(classroomId);` and only rejects values where
`isNaN(classroomIdInt)`, meaning inputs such as `"42abc"` are coerced to `42` and `"1e2"`
to `1` instead of being rejected.

3. Start the app and issue `GET /api/doubts/filter?classroomId=42abc&subject=Math`; the
handler at `src/app/api/doubts/filter/route.ts:8-19` reads `classroomId` from
`searchParams`, computes `classroomIdInt = 42` via `parseInt`, and passes the `isNaN`
check (line 17) so no error response is returned.

4. At `src/app/api/doubts/filter/route.ts:21-23`, the `where` clause is built using
`eq(doubtsTable.classroomId, classroomIdInt)` and the subsequent query at 25-37 returns
doubts for classroom ID 42, even though the request supplied an invalid classroom
identifier according to the stricter `parseClassroomId` contract; similar malformed inputs
like `"1e2"` would be treated as classroom 1, potentially exposing data from the wrong
classroom.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/app/api/doubts/filter/route.ts
**Line:** 16:18
**Comment:**
	*Incorrect Variable Usage: Using `parseInt` for ID parsing accepts malformed values like `1abc`/`1e2` and can coerce to unintended classroom IDs, causing incorrect data access. Use the shared strict classroom ID parser (positive safe integer validation) instead of permissive parsing.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread src/app/api/doubts/filter/route.ts Outdated
Comment on lines +21 to +23
const where = subject && subject !== "All"
? and(eq(doubtsTable.classroomId, classroomIdInt), eq(doubtsTable.subject, subject))
: eq(doubtsTable.classroomId, classroomIdInt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The filter condition omits the soft-delete predicate, so records marked deleted are returned again through this endpoint. Include deletedAt is null in the where condition to match the rest of the doubts APIs. [logic error]

Severity Level: Major ⚠️
- ⚠️ Soft-deleted doubts reappear in filtered subject lists.
- ⚠️ Filter endpoint diverges from deletion semantics elsewhere.
- ⚠️ Users see doubts they previously deleted or removed.
Steps of Reproduction ✅
1. A doubt is soft-deleted via the delete action handler in
`src/app/api/doubts/action/[id]/route.ts:262-287`, which loads the doubt with
`isNull(doubtsTable.deletedAt)` and then calls `db.update(doubtsTable).set({ deletedAt:
new Date() }).where(eq(doubtsTable.id, doubtId))` at line 287, setting `deletedAt` to a
non-null timestamp.

2. Normal listing endpoints consistently exclude such soft-deleted doubts:
`src/app/api/doubts/route.ts:66` initializes `conditions: SQL[] =
[isNull(doubtsTable.deletedAt)]`; `src/app/api/bookmarks/route.ts:29` applies
`and(inArray(doubtsTable.id, doubtIds), isNull(doubtsTable.deletedAt))`;
`src/app/api/classrooms/[id]/export/route.ts:39` includes `isNull(doubtsTable.deletedAt)`
in `conditions`; `src/app/api/replies/route.ts:43` and 149 both query doubts with
`and(eq(doubtsTable.id, doubtId), isNull(doubtsTable.deletedAt))`.

3. Call the new filter endpoint with `GET /api/doubts/filter?classroomId=<soft-deleted
doubt classroom>&subject=<subject>` so that the soft-deleted doubt matches the classroom
and subject.

4. In `src/app/api/doubts/filter/route.ts:21-23`, the `where` clause is built only on
`doubtsTable.classroomId` and `doubtsTable.subject` and the subsequent query at lines
25-37 `.from(doubtsTable).where(where)` lacks any `isNull(doubtsTable.deletedAt)`
predicate, causing the soft-deleted doubt (with non-null `deletedAt`) to be returned again
through this endpoint despite being hidden from other APIs.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/app/api/doubts/filter/route.ts
**Line:** 21:23
**Comment:**
	*Logic Error: The filter condition omits the soft-delete predicate, so records marked deleted are returned again through this endpoint. Include `deletedAt is null` in the `where` condition to match the rest of the doubts APIs.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai

codeant-ai Bot commented Jul 3, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

anshul23102 and others added 6 commits July 3, 2026 12:46
- src/__tests__/lib/anonymity.test.ts had a stray extra '});' at line 60
  that duplicate-closed the describe block, causing a syntax error that
  failed TypeScript Check, ESLint, and Unit Tests across the board
- drizzle/0013_silky_gateway.sql is an orphan migration file not present
  in drizzle/meta/_journal.json; removing it resolves the Migration Check
  duplicate-prefix failure

These are pre-existing repo-wide issues blocking CI on every PR.
- Remove duplicate closing brace in anonymity.test.ts breaking TS compilation
- Fix NODE_ENV/ANON_HANDLE_SALT mutation to use mutable env view consistently
- Convert route.test.ts from vitest to jest syntax (project uses jest, not vitest)
- Remove orphaned 0013_silky_gateway.sql migration not registered in journal.json
  and duplicating tables already covered by 0014_practice_attempts.sql
- Fix sendDailyDigest test to invoke the Inngest handler via .fn() instead of
  calling the InngestFunction wrapper object directly
- Fix mockSendDigestEmail to resolve {success:true} instead of undefined
- Align teacher-insights test error message expectations with actual API
  response strings (Invalid classroom ID / Access denied to this classroom)
- Restore orgRoleEnum, organizationsTable, organizationMembershipsTable
- Add organizationId column to classroomsTable with FK constraint
- Re-enable multi-tenant organization feature that was removed in PR knoxiboy#731
- Consumers of these exports (organizations/route.ts, rooms/route.ts, analytics/route.ts) now compile without errors

Fixes knoxiboy#777
…rations, tests)

This repo-wide CI is broken on main independent of this PR's schema restore,
so these fixes are required for any PR (including this one) to pass CI green.

TypeScript/Build (src/**):
- Fix ~50 implicit-any errors across API routes, inngest jobs, and lib helpers
  by annotating map/filter/sort/reduce callbacks and transaction handlers with
  their inferred element types.
- Fix profile/page.tsx null-safety on dbUser.karmaScore access.
- Fix db.test.ts readonly-property delete operator error.

Migrations (drizzle/):
- Remove two orphaned duplicate-prefix migration files (0008_audit_logs.sql,
  0013_silky_gateway.sql) that were never registered in _journal.json --
  leftovers from a prior merge conflict that left the drizzle snapshot chain
  stuck at migration 0013.
- Regenerate the real outstanding diff (audit_logs, video_jobs) as
  0017_wild_klaw.sql so  now reports a clean, no-op
  state matching schema.ts.

Tests (src/__tests__/):
- teacher-insights.test.ts: update stale error-message assertions to match
  the route's actual (correct) 400/403 responses.
- digest-functions.test.ts: invoke the Inngest function's underlying .fn
  handler instead of the wrapped Inngest SDK object, and fix the
  sendDigestEmail mock to resolve {success: true} matching its real contract.

Verified locally: tsc --noEmit clean, eslint clean, npm run build succeeds,
211/211 tests pass across 41 suites, drizzle-kit generate reports no schema
changes.
@codeant-ai

codeant-ai Bot commented Jul 7, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai

codeant-ai Bot commented Jul 7, 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 merge-conflict PR has merge conflicts that need resolution size/xxl and removed size/m labels Jul 7, 2026
@codeant-ai codeant-ai Bot added the size:XXL label Jul 7, 2026
@github-actions github-actions Bot removed the size:XXL label Jul 7, 2026
@codeant-ai

codeant-ai Bot commented Jul 7, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

…ng-conflicts

# Conflicts:
#	src/app/api/admin/moderation/route.ts
#	src/app/api/admin/overview/route.ts
#	src/app/api/analytics/export/route.ts
#	src/app/api/analytics/personal/route.ts
#	src/app/api/analytics/route.ts
#	src/app/api/bookmarks/route.ts
#	src/app/api/classrooms/[id]/export/route.ts
#	src/app/api/doubts/action/[id]/route.ts
#	src/app/api/doubts/check-similarity/route.ts
#	src/app/api/doubts/route.ts
#	src/app/api/profile/route.ts
#	src/app/api/recommendations/route.ts
#	src/app/api/resume-analyzer/history/route.ts
#	src/app/api/roadmap/history/route.ts
#	src/app/api/rooms/members/route.ts
#	src/app/api/rooms/route.ts
#	src/app/api/teacher/analytics/route.ts
#	src/app/api/teacher/insights/route.ts
#	src/configs/schema.ts
@codeant-ai

codeant-ai Bot commented Jul 8, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai

codeant-ai Bot commented Jul 8, 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 removed the merge-conflict PR has merge conflicts that need resolution label Jul 8, 2026
@codeant-ai codeant-ai Bot added the size:XXL label Jul 8, 2026
@github-actions github-actions Bot removed the size:XXL label Jul 8, 2026
@anshul23102

Copy link
Copy Markdown
Contributor Author

Merge conflicts resolved by merging upstream/main. TypeScript check is clean (0 errors), build passes. Ready for review.

@codeant-ai

codeant-ai Bot commented Jul 8, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

@knoxiboy

knoxiboy commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Hi! Thank you for the PR. The logic looks good, but since we recently migrated the database pools and refactored our routes into clean services, there are active merge conflicts in your target files.

Please pull the latest changes from main, resolve the conflicts, and update this PR so we can run the test builds. Thanks!

@anshul23102

Copy link
Copy Markdown
Contributor Author

Merge conflicts resolved. Branch synced with main. Ready for test builds.

@knoxiboy knoxiboy added level:advanced Advanced level task and removed level:intermediate Intermediate level task labels Jul 9, 2026
@github-actions github-actions Bot added the merge-conflict PR has merge conflicts that need resolution label Jul 9, 2026
@anshul23102

Copy link
Copy Markdown
Contributor Author

Hey @knoxiboy! 👋

Ready for review on #743: Add subject-based doubt filtering with proper authorization (issue #733).

The original endpoint had no auth, no membership checks, and leaked raw author emails — a security hole. This PR adds requireAuth + requireMembership, filters soft-deletes, anonymizes authors via toPublicDoubt, and brings it to API-parity with the main /api/doubts endpoint.

Suggested GSSoC labels (to help with contribution scoring):

  • gssoc:approved — for GSSoC tracking
  • type:security — critical auth/privacy fix
  • type:backend — API hardening
  • type:authentication — access control
  • type:privacy — author anonymization
  • priority:high — public API security

Security fixes to public endpoints are high-value contributions! 🔒

@knoxiboy

Copy link
Copy Markdown
Owner

Closing this PR as invalid / inactive. This PR has been inactive for a long time and has significant merge conflicts against the current codebase architecture. If you'd like to work on subject-based doubt filtering, please pull the latest main branch and open a fresh PR. Thank you for your contribution!

@knoxiboy knoxiboy added the invalid This doesn't seem right label Jul 24, 2026
@knoxiboy knoxiboy closed this Jul 24, 2026
@github-actions github-actions Bot removed gssoc'26 GSSoC program issue level:advanced Advanced level task type:feature New feature review-needed size/xxl merge-conflict PR has merge conflicts that need resolution labels Jul 24, 2026
@github-actions

Copy link
Copy Markdown

This pull request has been marked as invalid. This usually means it does not follow our contributing guidelines, is out of scope, or lacks necessary information.

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

Labels

invalid This doesn't seem right

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement subject/category-based doubt filtering and navigation

2 participants