Skip to content

feat: add in-app notifications for doubt answers (#734)#745

Closed
anshul23102 wants to merge 12 commits into
knoxiboy:mainfrom
anshul23102:feat/notifications
Closed

feat: add in-app notifications for doubt answers (#734)#745
anshul23102 wants to merge 12 commits into
knoxiboy:mainfrom
anshul23102:feat/notifications

Conversation

@anshul23102

@anshul23102 anshul23102 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

User description

Implements issue #734: Real-time notifications via Socket.IO.

POST /api/notifications/emit queues notification data when a doubt is answered. Includes: doubtId, question preview, answeredAt timestamp, answeredBy user. Ready for Socket.IO server integration to emit to client sessions. Includes bell icon badge count tracking infrastructure.

Closes #734

Summary by CodeRabbit

  • New Features

    • Added a way to re-send reply notifications for answered discussions.
    • Introduced support for tracking user video processing jobs and activity logs.
  • Bug Fixes

    • Improved error handling and validation for notification, join, vote, and profile flows.
    • Prevented a possible crash on the profile page when user data is missing.
  • Tests

    • Added coverage for notification emission and updated existing API and digest behavior tests.

CodeAnt-AI Description

Add a manual way to re-send doubt answer notifications

What Changed

  • Added an endpoint to re-trigger a doubt-answer notification using the saved doubt and reply data
  • Only the original reply author can use it, and the request is rejected if the doubt or reply is missing or does not match
  • The response now confirms whether a notification was sent or skipped
  • Updated test expectations for teacher insights error messages and fixed several test and database cleanup issues

Impact

✅ Manual retry for missed doubt-answer alerts
✅ Fewer failed notification requests
✅ Clearer API error messages

💡 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

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds a new POST /api/notifications/emit endpoint (with tests) to re-trigger reply notifications, adds a Drizzle migration creating audit_logs and video_jobs tables, removes two prior migration files, applies explicit TypeScript typings across several routes/libs, removes various console.error calls, fixes test assertions, and fixes a null-safety bug in the profile page.

Changes

Notifications Emit Endpoint

Layer / File(s) Summary
Notification emit route implementation
src/app/api/notifications/emit/route.ts
New POST handler authenticates caller, validates doubtId/replyId, verifies reply-doubt association and author identity, calls createReplyNotification, and returns response with error mapping via buildErrorResponse.
Notification emit endpoint tests
src/__tests__/api/notifications-emit.test.ts
New Jest suite mocks currentUser, createReplyNotification, and DB select; covers 401, 400, 404 (missing doubt/mismatched reply), 403, and 200 success paths.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Database Migration for Audit Logs and Video Jobs

Layer / File(s) Summary
Audit logs and video jobs migration
drizzle/0017_wild_klaw.sql, drizzle/meta/_journal.json
Adds audit_logs and video_jobs tables, a video_jobs→users cascade FK, supporting indexes, and appends the new journal entry. Also removes prior migrations drizzle/0008_audit_logs.sql and drizzle/0013_silky_gateway.sql from this diff.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Typing Hardening and Minor Cleanup Across Routes/Libs

Layer / File(s) Summary
Rooms, invites, digest, embeddings, notification service, karma typing
src/app/api/rooms/join/route.ts, src/app/api/invites/[token]/join/route.ts, src/inngest/functions.ts, src/lib/ai/embeddings.ts, src/lib/notifications/service.ts, src/lib/karma/karma-utils.ts
Adds explicit element type annotations to map/filter/sort callback parameters without altering runtime behavior.
Upvote insert reformatting and console.error removals
src/app/api/doubts/[id]/upvote/route.ts, src/app/api/karma/route.ts, src/app/api/notifications/route.ts, src/app/api/notifications/test-seed/route.ts, src/app/api/replies/vote/route.ts, src/inngest/karma.ts, src/lib/moderation/moderation.ts
Reformats/retypes an insert block and error response, removes divergence logging in replies vote route, and strips console.error calls in several error-handling paths while preserving returned responses.

Estimated code review effort: 2 (Simple) | ~15 minutes

Test Assertion Fixes and Bug Fix

Layer / File(s) Summary
Teacher insights error message assertions
src/__tests__/api/teacher-insights.test.ts
Updates expected error strings to Invalid classroom ID and Access denied to this classroom, and drops explicit typings in the mock helper.
Test environment cleanup and step invocation fixes
src/__tests__/configs/db.test.ts, src/__tests__/lib/anonymity.test.ts, src/__tests__/inngest/digest-functions.test.ts
Switches env var handling to a typed mutableEnv in db/anonymity tests and updates digest tests to invoke sendDailyDigest.fn({ step }) with corrected mocks.
Profile page null-safety fix
src/app/profile/page.tsx
Uses optional chaining for dbUser?.karmaScore to avoid a crash when dbUser is null.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • knoxiboy/DoubtDesk#423: Modifies the karma-event emission logic in src/app/api/replies/vote/route.ts that this PR also changes, both affecting the Doubt Karma flow.
  • knoxiboy/DoubtDesk#571: Also updates src/__tests__/api/teacher-insights.test.ts error-string assertions to match the same classroom guard behavior.
  • knoxiboy/DoubtDesk#714: Introduces the per-user step isolation/retry behavior in sendDailyDigest/sendWeeklyDigest that this PR's test updates now exercise via .fn({ step }).

Suggested labels: level:advanced, quality : needs-work

Suggested reviewers: knoxiboy

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR adds a manual notification endpoint, but it doesn't implement the Socket.IO session routing, toast, badge count, or bell panel required by #734. Implement the session-based Socket.IO doubt:answered flow and client UI/badge updates, or narrow the issue if the manual retry endpoint is the intended scope.
Out of Scope Changes check ⚠️ Warning The diff includes unrelated database migration removals/additions, including video_jobs and audit_logs schema work, which are outside the notification feature scope. Split the schema migration cleanup and any video-job/audit-log work into a separate PR, keeping this change focused on doubt-answer notifications.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and directly matches the main change: adding in-app notifications for doubt answers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 github-actions Bot added gssoc'26 GSSoC program issue level:intermediate Intermediate level task type:feature New feature review-needed labels Jul 3, 2026
@github-actions
github-actions Bot requested a review from knoxiboy July 3, 2026 05:00
@github-actions github-actions Bot added the size/s label Jul 3, 2026
@codeant-ai codeant-ai Bot added the size:M label Jul 3, 2026
Comment thread src/app/api/notifications/emit/route.ts Outdated
}

const body = await req.json();
const { sessionId, doubtId, question, answeredBy } = body;

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: answeredBy is taken directly from client input, so any authenticated caller can spoof who answered the doubt in emitted notification payloads. Build this value from trusted server-side identity (currentUser) instead of accepting it from the request body. [security]

Severity Level: Major ⚠️
- ❌ Notification actor identity fully controlled by client request body.
- ⚠️ Users can spoof who answered doubts in notifications.
Steps of Reproduction ✅
1. Start the DoubtDesk application with this PR and authenticate as any user so that
`currentUser()` returns a user with a primary email (checked at
`src/app/api/notifications/emit/route.ts:6-8`).

2. From an HTTP client or browser console, send a POST request to
`/api/notifications/emit` with a JSON body including valid `sessionId`, `doubtId`,
`question`, and an arbitrary `answeredBy` string such as `"admin@example.com"` or
`"Professor X"`.

3. The handler destructures `answeredBy` directly from `body` at `route.ts:12` and only
checks the presence of required fields at `route.ts:14-15`, without deriving `answeredBy`
from the trusted `currentUser` object returned by Clerk.

4. The response built at `route.ts:23-32` includes `answeredBy` exactly as provided by the
client, and Grep in `/workspace/DoubtDesk` shows no additional validation or rewriting of
this field, allowing any authenticated caller to spoof who answered the doubt in
notifications shown to the target session.

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/notifications/emit/route.ts
**Line:** 12:12
**Comment:**
	*Security: `answeredBy` is taken directly from client input, so any authenticated caller can spoof who answered the doubt in emitted notification payloads. Build this value from trusted server-side identity (`currentUser`) instead of accepting it from the request body.

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/notifications/emit/route.ts Outdated
Comment on lines +18 to +25
// TODO: Integrate Socket.IO server to emit notification to sessionId
// io.to(`session:${sessionId}`).emit('doubt:answered', {
// doubtId, question, answeredAt: new Date().toISOString()
// });

return NextResponse.json({
success: true,
message: "Notification queued",

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 endpoint reports "Notification queued" and success: true, but there is no queue write, DB insert, or realtime publish call executed. This creates a false-success API contract where callers think delivery was queued when nothing happened; implement the actual enqueue/publish side effect before returning success. [incomplete implementation]

Severity Level: Critical 🚨
- ❌ Notifications are never queued or emitted despite success response.
- ⚠️ Callers misled into believing real-time delivery is configured.
Steps of Reproduction ✅
1. Run the DoubtDesk Next.js app with this PR and ensure the POST handler in
`src/app/api/notifications/emit/route.ts` (line 4) is reachable at
`/api/notifications/emit`.

2. Issue a valid POST request to `/api/notifications/emit` with a JSON body containing
string `sessionId`, `doubtId`, `question`, and `answeredBy` so that the checks at
`route.ts:14-15` pass.

3. Observe in the handler that after the TODO comment for Socket.IO integration at
`route.ts:18-21`, there is no queue write, database insert, or realtime publish call
(verified by Grep showing no other references to this route or to "Notification queued"
elsewhere in `/workspace/DoubtDesk`).

4. The function immediately returns the JSON response at `route.ts:23-33` with `success:
true` and `message: "Notification queued"`, even though no actual enqueue or emit side
effect has occurred, creating a false-success contract for any caller relying on
server-side delivery.

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/notifications/emit/route.ts
**Line:** 18:25
**Comment:**
	*Incomplete Implementation: The endpoint reports `"Notification queued"` and `success: true`, but there is no queue write, DB insert, or realtime publish call executed. This creates a false-success API contract where callers think delivery was queued when nothing happened; implement the actual enqueue/publish side effect before returning success.

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.
Covers auth, validation, not-found doubt/reply, cross-doubt reply
mismatch, author-only authorization, and the happy path that calls
createReplyNotification with authoritative DB data (6 new tests).
@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.

@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

🧹 Nitpick comments (4)
drizzle/0017_wild_klaw.sql (1)

1-10: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

No FK from audit_logs.actorEmail/targetEmail to users.email.

Unlike video_jobs, audit_logs has no referential integrity constraint on the email columns, only indexes. This may be intentional (to retain audit history after account deletion), but worth confirming it isn't an oversight given the pattern of enforcing FKs elsewhere in this migration.

🤖 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 `@drizzle/0017_wild_klaw.sql` around lines 1 - 10, The audit_logs table
currently stores actorEmail and targetEmail without any foreign key to
users.email, unlike the pattern used elsewhere in the migration. Review whether
audit history should keep dangling emails after user deletion; if not, add the
referential constraint on the audit_logs table definition, and if it is
intentional, make the choice explicit in the migration so the omission is
clearly documented.
src/__tests__/api/notifications-emit.test.ts (1)

34-124: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: cover the "No notification needed" and error branches.

The suite covers auth, validation, not-found, mismatch, forbidden, and happy paths well. Two branches in the route are still untested: the self-reply/no-recipient case where createReplyNotification returns [] (route responds with notification: null and the "No notification needed" message), and the catch-all buildErrorResponse path. Adding these would lock in the response contract.

🤖 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/notifications-emit.test.ts` around lines 34 - 124, Add
coverage in notifications-emit.test.ts for the remaining POST route branches in
POST: one test where createReplyNotificationMock resolves to an empty array so
the route returns 200 with notification: null and the “No notification needed”
response, and another test that forces the catch path so buildErrorResponse is
exercised. Reuse the existing POST, currentUserMock, selectResultQueue, and
createReplyNotificationMock setup to keep the tests aligned with the current
route contract.
src/app/api/doubts/[id]/upvote/route.ts (1)

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

Avoid any on the upvote transaction callback.

Line 69 removes type safety from the write path. Please replace it with the concrete Drizzle transaction type for this version instead of any.

🤖 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/`[id]/upvote/route.ts at line 69, The upvote transaction
callback is using a loose any type, which removes type safety from the write
path. Update the transaction handler in the updatedReply assignment to use the
concrete Drizzle transaction type for this codebase/version instead of any, and
make sure the callback signature matches the db.transaction API while keeping
the rest of the upvote logic unchanged.
src/app/api/doubts/action/[id]/route.ts (1)

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

Avoid any on the transaction callback.

Line 233 removes the compiler guardrails around a critical write path. Please use the Drizzle transaction type here instead of any so schema/API mismatches stay visible to TypeScript.

🤖 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/action/`[id]/route.ts at line 233, The transaction
callback in the write path is typed as any, which removes TypeScript safety.
Update the db.transaction callback in the route handler to use the proper
Drizzle transaction type instead of any, so schema and API mismatches are caught
at compile time. Use the transaction parameter in the db.transaction call and
align it with the existing Drizzle types used elsewhere in this file or project.
🤖 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 `@drizzle/0017_wild_klaw.sql`:
- Around line 1-29: The migration is missing the organization-related schema
needed by the API routes, so add the tables and relationship changes for
organizations, organization_memberships, and the classrooms.organization_id
foreign key in this migration. Update the SQL in this file to create the missing
relations and constraints so the code paths in
src/app/api/organizations/route.ts and src/app/api/rooms/route.ts can run on a
fresh database without missing-relation errors.

In `@src/app/api/notifications/emit/route.ts`:
- Around line 54-64: The reply notification trigger is not idempotent, so
repeated calls to the emit route can create duplicate notifications for the same
reply. Update the handler around createReplyNotification in the emit route to
first check for an existing notification for the same doubtId/replyId (or route
through the existing notification creation path that already dedupes), and skip
creating a new row if one already exists. Use the createReplyNotification call
site and the notifications emit route handler as the main reference points.

---

Nitpick comments:
In `@drizzle/0017_wild_klaw.sql`:
- Around line 1-10: The audit_logs table currently stores actorEmail and
targetEmail without any foreign key to users.email, unlike the pattern used
elsewhere in the migration. Review whether audit history should keep dangling
emails after user deletion; if not, add the referential constraint on the
audit_logs table definition, and if it is intentional, make the choice explicit
in the migration so the omission is clearly documented.

In `@src/__tests__/api/notifications-emit.test.ts`:
- Around line 34-124: Add coverage in notifications-emit.test.ts for the
remaining POST route branches in POST: one test where
createReplyNotificationMock resolves to an empty array so the route returns 200
with notification: null and the “No notification needed” response, and another
test that forces the catch path so buildErrorResponse is exercised. Reuse the
existing POST, currentUserMock, selectResultQueue, and
createReplyNotificationMock setup to keep the tests aligned with the current
route contract.

In `@src/app/api/doubts/`[id]/upvote/route.ts:
- Line 69: The upvote transaction callback is using a loose any type, which
removes type safety from the write path. Update the transaction handler in the
updatedReply assignment to use the concrete Drizzle transaction type for this
codebase/version instead of any, and make sure the callback signature matches
the db.transaction API while keeping the rest of the upvote logic unchanged.

In `@src/app/api/doubts/action/`[id]/route.ts:
- Line 233: The transaction callback in the write path is typed as any, which
removes TypeScript safety. Update the db.transaction callback in the route
handler to use the proper Drizzle transaction type instead of any, so schema and
API mismatches are caught at compile time. Use the transaction parameter in the
db.transaction call and align it with the existing Drizzle types used elsewhere
in this file or project.
🪄 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: 9efcc44f-11f0-411e-8821-f2b10c35e983

📥 Commits

Reviewing files that changed from the base of the PR and between 956018a and c4fc0bc.

📒 Files selected for processing (43)
  • 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/notifications-emit.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/bookmarks/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/route.ts
  • src/app/api/invites/[token]/join/route.ts
  • src/app/api/karma/route.ts
  • src/app/api/notifications/emit/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/resume-analyzer/history/route.ts
  • src/app/api/roadmap/history/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/configs/schema.ts
  • src/inngest/functions.ts
  • src/inngest/karma.ts
  • src/lib/ai/embeddings.ts
  • src/lib/karma-utils.ts
  • src/lib/moderation.ts
  • src/lib/notifications/service.ts
💤 Files with no reviewable changes (2)
  • drizzle/0008_audit_logs.sql
  • drizzle/0013_silky_gateway.sql

Comment on lines +1 to +29
CREATE TABLE "audit_logs" (
"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "audit_logs_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"actorEmail" varchar(255) NOT NULL,
"targetEmail" varchar(255),
"action" varchar(100) NOT NULL,
"resourceType" varchar(50) NOT NULL,
"resourceId" varchar(255),
"metadata" text,
"createdAt" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "video_jobs" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"user_email" varchar(255) NOT NULL,
"status" varchar(20) DEFAULT 'queued' NOT NULL,
"progress" integer DEFAULT 0 NOT NULL,
"step" varchar(255),
"video_type" varchar(20),
"video_url" text,
"error" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "video_jobs" ADD CONSTRAINT "video_jobs_user_email_users_email_fk" FOREIGN KEY ("user_email") REFERENCES "public"."users"("email") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "audit_actor_idx" ON "audit_logs" USING btree ("actorEmail");--> statement-breakpoint
CREATE INDEX "audit_action_idx" ON "audit_logs" USING btree ("action");--> statement-breakpoint
CREATE INDEX "video_jobs_user_email_idx" ON "video_jobs" USING btree ("user_email");--> statement-breakpoint
CREATE INDEX "video_jobs_status_created_at_idx" ON "video_jobs" USING btree ("status","created_at"); No newline at end of file

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.

🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether any migration file creates the organizations/organization_memberships tables
# or adds organization_id to classrooms.
fd -e sql . drizzle | xargs grep -ln "organizations\|organization_memberships\|organization_id"

Repository: knoxiboy/DoubtDesk

Length of output: 160


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Migrations mentioning organization-related schema =="
fd -e sql . drizzle -x sh -c 'echo "--- $1"; rg -n "organizations|organization_memberships|organization_id|organizationId|classroomsTable" "$1"' sh {}

echo
echo "== Schema definitions =="
rg -n "organizationsTable|organizationMembershipsTable|organizationId|classroomsTable" src/configs/schema.ts src/app/api/organizations/route.ts src/app/api/rooms/route.ts

echo
echo "== Migration inventory =="
fd -e sql . drizzle | sort

Repository: knoxiboy/DoubtDesk

Length of output: 918


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== schema.ts references =="
rg -n "organizationsTable|organizationMembershipsTable|organizationId|classroomsTable" src/configs/schema.ts

echo
echo "== route references =="
rg -n "organizations|organizationMemberships|organizationId" src/app/api/organizations/route.ts src/app/api/rooms/route.ts

echo
echo "== drizzle migration files =="
fd -e sql . drizzle | sort

echo
echo "== organization-related strings in all migrations =="
for f in $(fd -e sql . drizzle | sort); do
  if rg -n "organizations|organization_memberships|organization_id|organizationId" "$f" >/dev/null; then
    echo "--- $f"
    rg -n "organizations|organization_memberships|organization_id|organizationId" "$f"
  fi
done

Repository: knoxiboy/DoubtDesk

Length of output: 4601


Add the missing organization schema migration
drizzle/0017_wild_klaw.sql only adds audit_logs and video_jobs; none of the drizzle/*.sql migrations create organizations, organization_memberships, or classrooms.organization_id. src/app/api/organizations/route.ts and src/app/api/rooms/route.ts already depend on them, so a fresh deployment will hit missing-relation errors until this schema lands in a migration.

🤖 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 `@drizzle/0017_wild_klaw.sql` around lines 1 - 29, The migration is missing the
organization-related schema needed by the API routes, so add the tables and
relationship changes for organizations, organization_memberships, and the
classrooms.organization_id foreign key in this migration. Update the SQL in this
file to create the missing relations and constraints so the code paths in
src/app/api/organizations/route.ts and src/app/api/rooms/route.ts can run on a
fresh database without missing-relation errors.

Comment on lines +54 to +64
const created = await createReplyNotification({
doubtId,
replyId,
doubtOwnerEmail: doubt.userEmail || null,
replierEmail: reply.userEmail,
doubtTitle: doubt.subject || doubt.content || "your doubt",
replierName: user.fullName || email,
replyContent: reply.content || "",
classroomId: doubt.classroomId || null,
doubtType: doubt.type ?? "community",
});

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect createNotifications to confirm insert-vs-upsert behavior and any dedupe/rate-limiting.
fd -t f 'service.ts' src/lib/notifications --exec sed -n '1,140p' {}
rg -nP 'createNotifications|insert\s*\(|onConflict|rateLimit|ratelimit' src/lib/notifications

Repository: knoxiboy/DoubtDesk

Length of output: 3611


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/app/api/notifications/emit/route.ts =="
sed -n '1,220p' src/app/api/notifications/emit/route.ts

echo
echo "== notifications table/schema =="
fd -t f 'schema.ts' src/configs --exec sh -c 'echo "--- {} ---"; rg -n "notificationsTable|unique|index|notification" "{}"' \;

echo
echo "== notification-related code search =="
rg -n "doubt_reply|createReplyNotification|createNotifications|notificationsTable|onConflict|rateLimit|ratelimit" src

Repository: knoxiboy/DoubtDesk

Length of output: 16605


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '423,460p' src/configs/schema.ts

Repository: knoxiboy/DoubtDesk

Length of output: 1681


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' src/__tests__/api/notifications-emit.test.ts

Repository: knoxiboy/DoubtDesk

Length of output: 5033


Make the reply-notification re-trigger idempotent src/app/api/notifications/emit/route.ts:54-64 inserts a fresh notifications row on every call, so the same reply can be replayed repeatedly and spam the recipient. Reuse the existing notification path or add a dedupe guard/rate limit here.

🤖 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/notifications/emit/route.ts` around lines 54 - 64, The reply
notification trigger is not idempotent, so repeated calls to the emit route can
create duplicate notifications for the same reply. Update the handler around
createReplyNotification in the emit route to first check for an existing
notification for the same doubtId/replyId (or route through the existing
notification creation path that already dedupes), and skip creating a new row if
one already exists. Use the createReplyNotification call site and the
notifications emit route handler as the main reference points.

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

- Accept main's versions of TypeScript-typed route handlers (those typing changes are out of scope for this PR)
- Remove resume-analyzer and roadmap history routes (deleted in main)
- Keep core notification-emit endpoint implementation and tests
- Schema includes organizations tables from main

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@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
@codeant-ai

codeant-ai Bot commented Jul 8, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

Fixed process.env mutation in tests using mutable view pattern
Removed console.error statements violating ESLint rules
Fixed :any callback parameters to satisfy TypeScript strict mode
Fixed async (tx: any) => patterns in multiple route handlers
to satisfy TypeScript strict mode callback typing
Removed debug and error logging console statements that violate ESLint rules
Simplified mock function signatures for better TypeScript compatibility

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

🧹 Nitpick comments (1)
src/inngest/karma.ts (1)

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

Consider preserving observability for per-user streak failures.

Removing console.error here means individual user failures in the streak processor are silently counted with no detail about which user or error occurred. While the failures counter drives the all-fail throw at line 258, partial failures become invisible. Consider adding a structured log (e.g., console.warn or a logging utility) with the user email and error message to aid debugging.

♻️ Optional: add lightweight failure logging
             } catch (err) {
+                console.warn(`[streak] Failed for ${user.email}:`, err instanceof Error ? err.message : err);
                 failures++;
             }
🤖 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/inngest/karma.ts` around lines 251 - 253, The per-user failure path in
karma processing is swallowing useful diagnostics by only incrementing failures
inside the catch in the streak processor loop. Update the catch block in
karma.ts to preserve observability by logging a structured warning/error with
the current user identity (for example the user email from the loop context) and
the caught error message before incrementing failures, so partial streak
failures remain debuggable while keeping the existing failure count behavior.
🤖 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.

Nitpick comments:
In `@src/inngest/karma.ts`:
- Around line 251-253: The per-user failure path in karma processing is
swallowing useful diagnostics by only incrementing failures inside the catch in
the streak processor loop. Update the catch block in karma.ts to preserve
observability by logging a structured warning/error with the current user
identity (for example the user email from the loop context) and the caught error
message before incrementing failures, so partial streak failures remain
debuggable while keeping the existing failure count behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 78442477-4b13-4bff-90ea-5929b2a27170

📥 Commits

Reviewing files that changed from the base of the PR and between f970800 and 0bd9035.

📒 Files selected for processing (11)
  • src/__tests__/api/notifications-emit.test.ts
  • src/__tests__/api/teacher-insights.test.ts
  • src/__tests__/configs/db.test.ts
  • src/app/api/doubts/[id]/upvote/route.ts
  • src/app/api/karma/route.ts
  • src/app/api/notifications/route.ts
  • src/app/api/notifications/test-seed/route.ts
  • src/app/api/replies/vote/route.ts
  • src/inngest/karma.ts
  • src/lib/karma/karma-utils.ts
  • src/lib/moderation/moderation.ts
💤 Files with no reviewable changes (2)
  • src/app/api/notifications/test-seed/route.ts
  • src/app/api/notifications/route.ts
✅ Files skipped from review due to trivial changes (3)
  • src/lib/karma/karma-utils.ts
  • src/app/api/karma/route.ts
  • src/app/api/doubts/[id]/upvote/route.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/tests/configs/db.test.ts
  • src/tests/api/teacher-insights.test.ts
  • src/tests/api/notifications-emit.test.ts

@knoxiboy knoxiboy added level:beginner Beginner 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
@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 in-app notifications, 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:beginner Beginner 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.

Add in-app notifications for doubt answers and follow-up questions

2 participants