Skip to content

auth and db sync#3

Merged
realACO merged 1 commit into
mainfrom
auth-db-sync
Mar 6, 2026
Merged

auth and db sync#3
realACO merged 1 commit into
mainfrom
auth-db-sync

Conversation

@realACO
Copy link
Copy Markdown
Owner

@realACO realACO commented Mar 6, 2026

Summary by CodeRabbit

  • New Features
    • User account synchronization: Profiles are now automatically created and deleted in real-time based on authentication system events, streamlining account lifecycle management.
    • Cross-Origin Resource Sharing (CORS): The backend API now properly supports secure cross-origin requests with credential-based access control, enabling seamless frontend-backend communication.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 6, 2026

📝 Walkthrough

Walkthrough

This PR adds Inngest event-driven infrastructure to synchronize users from Clerk authentication events into the database. It introduces a User model, configures Inngest with event handlers for user creation/deletion, and integrates CORS and Inngest middleware into the Express server with required environment variables.

Changes

Cohort / File(s) Summary
Dependencies & Configuration
backend/package.json, backend/src/lib/env.js
Added CORS and Inngest npm dependencies; exposed five new environment variables (CLIENT_URL, INNGEST_EVENT_KEY, INNGEST_SIGNING_KEY, STREAM_API_KEY, STREAM_API_SECRET) in ENV object.
Event Integration
backend/src/lib/inngest.js
Created Inngest client instance ("CodeMeet") with two event handlers: syncUser (listens to clerk/user.created events and saves User to DB) and deleteUserFromDB (listens to clerk/user.deleted events and removes User from DB).
Data Model
backend/src/models/User.js
Introduced Mongoose User schema with required fields (name, email, clerkId), unique constraints on email and clerkId, optional profileImage, and automatic timestamps (createdAt, updatedAt).
Server Setup
backend/src/server.js
Wired CORS middleware with CLIENT_URL origin restriction and credentials enabled; added JSON body parser; mounted Inngest express adapter at /api/inngest endpoint.

Sequence Diagram

sequenceDiagram
    participant Clerk as Clerk (Auth)
    participant Inngest as Inngest (Event Hub)
    participant Express as Express Server
    participant DB as MongoDB

    Clerk->>Inngest: Trigger user.created event
    Inngest->>Express: Route to /api/inngest
    Express->>Inngest: Process syncUser handler
    Inngest->>DB: Create new User document
    DB-->>Inngest: User saved with clerkId
    
    Clerk->>Inngest: Trigger user.deleted event
    Inngest->>Express: Route to /api/inngest
    Express->>Inngest: Process deleteUserFromDB handler
    Inngest->>DB: Delete User by clerkId
    DB-->>Inngest: User removed
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • PR #2: Introduces database connection setup and server startup wiring in backend/src/lib/db.js and backend/src/server.js, which directly supports the Inngest handlers that depend on database operations added in this PR.
  • PR #1: Extends the same backend configuration files (backend/src/lib/env.js and backend/package.json) with additional environment variables and dependencies.

Poem

🐰✨ From Clerk's whisper comes a user born,
Inngest catches it, the event is sworn,
Into MongoDB it finds its home,
When deleted, away the user does roam,
CORS guards the gates with grace so bright! 🌟

🚥 Pre-merge checks | ✅ 3
✅ 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 'auth and db sync' is directly related to the main changes in the PR, which add Inngest event handlers for user authentication sync (clerk user creation/deletion) and database synchronization (User model creation and data persistence).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch auth-db-sync

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
backend/src/lib/inngest.js (1)

23-31: Consider adding error handling for database operations.

The deleteOne operation doesn't verify if a user was actually deleted. If the user doesn't exist in the database (e.g., sync failed during creation), this silently succeeds.

💡 Optional: Add verification and logging
   async ({ event }) => {
     await connectDB();
     const { id } = event.data;
-    await User.deleteOne({ clerkId: id });
+    const result = await User.deleteOne({ clerkId: id });
+    if (result.deletedCount === 0) {
+      console.warn(`User with clerkId ${id} not found for deletion`);
+    }
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/lib/inngest.js` around lines 23 - 31, The deleteUserFromDB
function using inngest.createFunction should add error handling and verify the
delete result: wrap the connectDB and User.deleteOne call in try/catch, catch
and log any DB errors (including the event.data.id) using your logger, and after
User.deleteOne({ clerkId: id }) check the returned result (e.g., deletedCount or
acknowledged) to detect when no document was removed and log a warning or take
corrective action; ensure the handler still fails or signals an error
appropriately when the DB operation throws.
backend/src/lib/env.js (1)

9-13: Consider adding validation for required environment variables.

These environment variables (especially CLIENT_URL and INNGEST_SIGNING_KEY) are critical for the application to function correctly. If they're missing, the app will fail at runtime with unclear errors. Consider adding startup validation.

💡 Optional: Add validation helper
const required = (key) => {
  const value = process.env[key];
  if (!value) throw new Error(`Missing required env var: ${key}`);
  return value;
};

export const ENV = {
  PORT: process.env.PORT,
  DB_URL: required("DB_URL"),
  NODE_ENV: process.env.NODE_ENV,
  CLIENT_URL: required("CLIENT_URL"),
  // ...
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/lib/env.js` around lines 9 - 13, Add startup validation by
introducing a small helper function (e.g., required(key)) and use it when
constructing the ENV object so critical vars like CLIENT_URL and
INNGEST_SIGNING_KEY (and any other mandatory keys such as DB_URL or
INNGEST_EVENT_KEY) are validated at module load; the required helper should read
process.env[key] and throw a clear Error(`Missing required env var: ${key}`)
when absent, and then replace direct uses of process.env.CLIENT_URL and
process.env.INNGEST_SIGNING_KEY in ENV with required("CLIENT_URL") and
required("INNGEST_SIGNING_KEY") respectively to fail fast with a clear message.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/src/lib/inngest.js`:
- Line 3: The import path for the User model in inngest.js is incorrect; update
the import that references User so it points to the actual module location
(backend/src/models/User.js) instead of ./models/User.js — locate the import
statement importing User in inngest.js and change its path to the correct
relative path to the models folder so the User symbol resolves correctly.
- Around line 12-18: The code is destructuring the wrong Clerk payload field and
lacks validation: replace uses of event.data.email_address with
event.data.email_addresses (an array) when building newUser (the
clerkId/email/name/profileImage object) and extract the primary email as
email_addresses[0]?.email_address (or find the verified one); then add
validation before returning/creating the user to ensure newUser.email is
non-empty and newUser.name falls back to a safe value (e.g., use first_name or
last_name individually or a placeholder) and fail fast with a clear error if
email is missing so the User creation won’t silently break.

In `@backend/src/server.js`:
- Line 7: The import currently only brings in inngest but the exported array
functions from the module is referenced later (e.g., on line 19); update the
import statement to also import functions from "./lib/inngest.js" (ensure the
named export matches the exported symbol in that module) so the referenced
functions identifier is defined at runtime.
- Line 17: The CORS setup uses ENV.CLIENT_URL directly which can be undefined;
update the app.use(cors(...)) configuration (the call where app.use and cors are
used) to validate ENV.CLIENT_URL and provide a safe fallback for local/dev (or
use a dynamic origin function) so origin never becomes undefined—e.g., check
ENV.CLIENT_URL and set a default like a localhost dev URL or a function that
conditionally allows the origin; ensure this change is applied where
app.use(cors({ origin: ENV.CLIENT_URL, credentials: true })) is defined.

---

Nitpick comments:
In `@backend/src/lib/env.js`:
- Around line 9-13: Add startup validation by introducing a small helper
function (e.g., required(key)) and use it when constructing the ENV object so
critical vars like CLIENT_URL and INNGEST_SIGNING_KEY (and any other mandatory
keys such as DB_URL or INNGEST_EVENT_KEY) are validated at module load; the
required helper should read process.env[key] and throw a clear Error(`Missing
required env var: ${key}`) when absent, and then replace direct uses of
process.env.CLIENT_URL and process.env.INNGEST_SIGNING_KEY in ENV with
required("CLIENT_URL") and required("INNGEST_SIGNING_KEY") respectively to fail
fast with a clear message.

In `@backend/src/lib/inngest.js`:
- Around line 23-31: The deleteUserFromDB function using inngest.createFunction
should add error handling and verify the delete result: wrap the connectDB and
User.deleteOne call in try/catch, catch and log any DB errors (including the
event.data.id) using your logger, and after User.deleteOne({ clerkId: id })
check the returned result (e.g., deletedCount or acknowledged) to detect when no
document was removed and log a warning or take corrective action; ensure the
handler still fails or signals an error appropriately when the DB operation
throws.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7c8d7675-572c-44ba-819b-94685e17cd4a

📥 Commits

Reviewing files that changed from the base of the PR and between cef590a and 50f3504.

⛔ Files ignored due to path filters (1)
  • backend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • backend/package.json
  • backend/src/lib/env.js
  • backend/src/lib/inngest.js
  • backend/src/models/User.js
  • backend/src/server.js

@@ -0,0 +1,33 @@
import { Inngest } from "inngest";
import { connectDB } from "./db.js";
import User from "./models/User.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Incorrect import path - module will not be found.

The file is located at backend/src/lib/inngest.js, so the import path ./models/User.js resolves to backend/src/lib/models/User.js, which doesn't exist. The User model is at backend/src/models/User.js.

🐛 Fix the import path
-import User from "./models/User.js";
+import User from "../models/User.js";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import User from "./models/User.js";
import User from "../models/User.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/lib/inngest.js` at line 3, The import path for the User model in
inngest.js is incorrect; update the import that references User so it points to
the actual module location (backend/src/models/User.js) instead of
./models/User.js — locate the import statement importing User in inngest.js and
change its path to the correct relative path to the models folder so the User
symbol resolves correctly.

Comment on lines +12 to +18
const { id, email_address, first_name, last_name, image_url } = event.data;
const newUser = {
clerkId: id,
email: email_address[0]?.email_address,
name: `${first_name || ""} ${last_name || ""}`,
profileImage: image_url,
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Clerk webhook user.created event payload structure email_addresses field

💡 Result:

In a Clerk user.created webhook, data is the full User object, and email_addresses is an array of email address objects. Each entry looks like this (fields shown in Clerk’s example payload): [1]

"email_addresses": [
  {
    "email_address": "example@example.org",
    "id": "idn_29w83yL7CwVlJXylYLxcslromF1",
    "linked_to": [],
    "object": "email_address",
    "verification": {
      "status": "verified",
      "strategy": "ticket"
    }
  }
]

The user object also includes primary_email_address_id, which references the id of the primary entry in email_addresses. [1]

Source
[1] Clerk Docs — Webhooks overview (example user.created payload) (clerk.com)

Citations:


🏁 Script executed:

cat -n backend/src/lib/inngest.js | head -30

Repository: realACO/CodeMeet

Length of output: 1127


Fix critical Clerk webhook payload field name and add validation.

The code destructures email_address (singular), but Clerk's webhook payload provides email_addresses (plural array). This will cause email_address to be undefined, and the email extraction will fail.

Additionally, the code lacks validation for empty email addresses or missing name fields, which could cause User schema validation to fail silently.

Proposed fix
   async ({ event }) => {
     await connectDB();
-    const { id, email_address, first_name, last_name, image_url } = event.data;
+    const { id, email_addresses, first_name, last_name, image_url } = event.data;
+    
+    const primaryEmail = email_addresses?.[0]?.email_address;
+    if (!primaryEmail) {
+      throw new Error(`No email found for user ${id}`);
+    }
+    
+    const fullName = [first_name, last_name].filter(Boolean).join(" ") || "Unknown";
+    
     const newUser = {
       clerkId: id,
-      email: email_address[0]?.email_address,
-      name: `${first_name || ""} ${last_name || ""}`,
+      email: primaryEmail,
+      name: fullName,
       profileImage: image_url,
     };
     await User.create(newUser);
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/lib/inngest.js` around lines 12 - 18, The code is destructuring
the wrong Clerk payload field and lacks validation: replace uses of
event.data.email_address with event.data.email_addresses (an array) when
building newUser (the clerkId/email/name/profileImage object) and extract the
primary email as email_addresses[0]?.email_address (or find the verified one);
then add validation before returning/creating the user to ensure newUser.email
is non-empty and newUser.name falls back to a safe value (e.g., use first_name
or last_name individually or a placeholder) and fail fast with a clear error if
email is missing so the User creation won’t silently break.

Comment thread backend/src/server.js
import { connectDB } from "./lib/db.js";
import cors from "cors";
import { serve } from "inngest/express";
import { inngest } from "./lib/inngest.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Missing import: functions is not imported but used on line 19.

The functions array is exported from ./lib/inngest.js but is not included in the import statement. This will cause a ReferenceError: functions is not defined at server startup.

🐛 Fix the import
-import { inngest } from "./lib/inngest.js";
+import { inngest, functions } from "./lib/inngest.js";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { inngest } from "./lib/inngest.js";
import { inngest, functions } from "./lib/inngest.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/server.js` at line 7, The import currently only brings in inngest
but the exported array functions from the module is referenced later (e.g., on
line 19); update the import statement to also import functions from
"./lib/inngest.js" (ensure the named export matches the exported symbol in that
module) so the referenced functions identifier is defined at runtime.

Comment thread backend/src/server.js
app.use(express.json());

//credentials true meaning server allows browser to include cookies on request
app.use(cors({ origin: ENV.CLIENT_URL, credentials: true }));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

CORS origin will be undefined if CLIENT_URL is not set.

If ENV.CLIENT_URL is not defined, the CORS middleware will have origin: undefined, which may not behave as expected (could block all cross-origin requests or allow all, depending on the cors library version).

Consider adding a fallback or validation for development environments:

💡 Suggested improvement
-app.use(cors({ origin: ENV.CLIENT_URL, credentials: true }));
+app.use(cors({ 
+  origin: ENV.CLIENT_URL || "http://localhost:5173", 
+  credentials: true 
+}));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.use(cors({ origin: ENV.CLIENT_URL, credentials: true }));
app.use(cors({
origin: ENV.CLIENT_URL || "http://localhost:5173",
credentials: true
}));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/server.js` at line 17, The CORS setup uses ENV.CLIENT_URL
directly which can be undefined; update the app.use(cors(...)) configuration
(the call where app.use and cors are used) to validate ENV.CLIENT_URL and
provide a safe fallback for local/dev (or use a dynamic origin function) so
origin never becomes undefined—e.g., check ENV.CLIENT_URL and set a default like
a localhost dev URL or a function that conditionally allows the origin; ensure
this change is applied where app.use(cors({ origin: ENV.CLIENT_URL, credentials:
true })) is defined.

@realACO realACO merged commit 6c0cc8c into main Mar 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant