Skip to content

Conversation

@ailearningguy
Copy link
Owner

@ailearningguy ailearningguy commented Oct 27, 2025

Summary by CodeRabbit

  • New Features

    • Event management: create and manage events with automatic slug/URL generation and normalized dates.
    • Booking system: users can reserve attendance; bookings validate that the referenced event exists and are timestamped.
    • Improved performance: indexes added for faster event and booking lookups.
  • Chores

    • Added backend database connectivity and supporting dependencies for persistent storage.

@coderabbitai
Copy link

coderabbitai bot commented Oct 27, 2025

Walkthrough

Adds Mongoose-backed Event and Booking models with schemas, validations, pre-save hooks, indexes, and timestamps; a cached MongoDB connection utility; a barrel export for models; and adds mongoose and slugify dependencies.

Changes

Cohort / File(s) Summary
Models: Event & Booking
database/event.model.ts, database/booking.model.ts
Adds IEvent and IBooking interfaces and Mongoose schemas with required fields, timestamps, and indexes. Event schema generates a slug on title changes and normalizes date; Booking pre-save hook verifies referenced Event exists. Exports models with reuse via `models.*
Database Barrel
database/index.ts
Re-exports Event and Booking models for consolidated imports.
Connection Utility
lib/mongodb.ts
Adds connectDB() implementing a cached mongoose connection, validates MONGODB_URI, caches connection and connection promise across hot reloads, and sets bufferCommands: false.
Dependencies
package.json
Adds mongoose and slugify to dependencies.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant connectDB
    participant Cache as Global Cache
    participant Mongoose as mongoose.connect()
    participant MongoDB

    App->>connectDB: call connectDB()
    alt cached.conn exists
        connectDB->>Cache: return cached.conn
        connectDB-->>App: connection
    else
        connectDB->>Cache: check cached.promise
        alt promise pending
            Cache-->>connectDB: return cached.promise
            connectDB-->>App: promise
        else
            connectDB->>Mongoose: mongoose.connect(MONGODB_URI, {bufferCommands:false})
            Mongoose->>MongoDB: establish connection
            Mongoose-->>Cache: store conn & promise
            Mongoose-->>App: connection
        end
    end
Loading
sequenceDiagram
    participant Client
    participant BookingModel as Booking.create()
    participant PreSaveHook as Booking pre-save
    participant EventModel as Event.findById()
    participant DB

    Client->>BookingModel: create booking with eventId
    BookingModel->>PreSaveHook: trigger pre-save
    PreSaveHook->>EventModel: findById(eventId)
    EventModel->>DB: query by id
    alt event found
        DB-->>EventModel: event
        EventModel-->>PreSaveHook: exists
        PreSaveHook-->>BookingModel: allow save
    else not found
        DB-->>EventModel: null
        EventModel-->>PreSaveHook: throw "Event not found"
        PreSaveHook-->>Client: validation error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify pre-save hooks (slug generation, date normalization, Event existence) and error handling.
  • Review schema validations (required fields, email regex) and index choices (slug, eventId).
  • Check connection caching logic for concurrency and error propagation.

Poem

🐇 I stitched the schema, soft and bright,

Slugs for paths and timestamps tight,
Bookings check events before they land,
Connection cached by careful hand,
Hop—models ready across the land.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Implement Database models" accurately reflects the primary objective of the pull request, which introduces two new Mongoose database models (Event and Booking) along with supporting infrastructure including a MongoDB connection utility, barrel exports, and required dependencies. The title is concise, clear, and specific enough that a developer scanning commit history would immediately understand the purpose is adding database models to the project. While the title doesn't detail which specific models or their functionality, this level of generalization is appropriate and consistent with effective PR title conventions.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch database-models

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6569e17 and bea0205.

📒 Files selected for processing (1)
  • database/booking.model.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • database/booking.model.ts

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

Copy link

@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 (5)
package.json (1)

15-15: Mongoose/slugify additions look fine; verify TS types and Node engine.

  • Check that slugify ships types in 1.6.6 in your toolchain; if not, add @types/slugify.
  • Consider adding "engines": { "node": ">=18" } to reflect Next 16 + Mongoose 8 runtime expectations.

Also applies to: 22-22

lib/mongodb.ts (1)

36-53: Annotate return type and add a conservative serverSelection timeout.

Small hardening and clarity:

-async function connectDB() {
+async function connectDB(): Promise<Mongoose> {
@@
-    const opts = {
-      bufferCommands: false,
-    };
+    const opts = {
+      bufferCommands: false,
+      serverSelectionTimeoutMS: 5000,
+    } as const;

If you run on any Edge runtime, ensure routes using this import specify runtime: "nodejs".

database/booking.model.ts (1)

1-1: Tighten typing and uniqueness on bookings.

  • Use Types.ObjectId for stronger typing.
  • Normalize email and prevent duplicate bookings per event/email with a compound unique index.

Apply this diff:

-import { Schema, model, models, Document } from "mongoose";
+import { Schema, model, models, Document, Types } from "mongoose";
@@
 export interface IBooking extends Document {
-  eventId: Schema.Types.ObjectId;
+  eventId: Types.ObjectId;
   email: string;
   createdAt: Date;
   updatedAt: Date;
 }
@@
-    eventId: {
-      type: Schema.Types.ObjectId,
+    eventId: {
+      type: Types.ObjectId,
       ref: "Event",
       required: [true, "Event ID is required"],
     },
     email: {
       type: String,
       required: [true, "Email is required"],
-      match: [/.+\@.+\..+/, "Please enter a valid email address"],
+      match: [/.+\@.+\..+/, "Please enter a valid email address"],
+      lowercase: true,
+      trim: true,
     },
@@
-// Add an index on eventId for faster queries
-bookingSchema.index({ eventId: 1 });
+// Prevent duplicate bookings for the same event/email
+bookingSchema.index({ eventId: 1, email: 1 }, { unique: true });

Also applies to: 6-7, 14-23, 41-42

database/event.model.ts (1)

51-55: Consider handling slug collisions and non‑latin titles.

Optional improvements:

  • If slugify yields an empty string, fall back to a safe token.
  • Ensure uniqueness by appending a counter when a slug already exists.

I can provide a concise async pre hook snippet to handle collisions if you want it in this PR.

database/index.ts (1)

1-4: LGTM; optionally re‑export model types for ergonomics.

Add type exports so consumers can import from a single barrel.

 export { Event, Booking };
+export type { IEvent } from "./event.model";
+export type { IBooking } from "./booking.model";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 246dc7f and 6569e17.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • database/booking.model.ts (1 hunks)
  • database/event.model.ts (1 hunks)
  • database/index.ts (1 hunks)
  • lib/mongodb.ts (1 hunks)
  • package.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
database/event.model.ts (1)
database/index.ts (1)
  • Event (4-4)
database/booking.model.ts (1)
database/index.ts (2)
  • Event (4-4)
  • Booking (4-4)
🪛 Biome (2.1.2)
lib/mongodb.ts

[error] 24-24: Shouldn't redeclare 'mongoose'. Consider to delete it or rename it.

'mongoose' is defined here:

(lint/suspicious/noRedeclare)

const eventSchema = new Schema<IEvent>(
{
title: { type: String, required: [true, "Title is required"] },
slug: { type: String, unique: true },
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove duplicate/conflicting slug index (will error at index build).

You already define slug with unique: true. Adding a separate non‑unique index with the same key conflicts and may fail deployment.

Apply this diff:

-// Add a unique index to the slug field for faster queries
-eventSchema.index({ slug: 1 });

Also applies to: 66-67

🤖 Prompt for AI Agents
In database/event.model.ts around lines 27 and 66-67, a duplicate/conflicting
index for the slug field is being created: slug is already defined with unique:
true on the schema property and a separate non-unique index is also added, which
will conflict at index build. Remove the separate index declaration (the
additional index call for slug at lines 66-67) so the schema relies on the
unique: true property only, or alternatively remove unique: true and keep a
single index declaration — ensure only one index definition for slug remains to
avoid index conflicts.

Comment on lines +57 to +61
// Validate and normalize the date to ISO format
if (this.date) {
const isoDate = new Date(this.date).toISOString();
this.date = isoDate;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against invalid dates and only normalize when modified.

-  // Validate and normalize the date to ISO format
-  if (this.date) {
-    const isoDate = new Date(this.date).toISOString();
-    this.date = isoDate;
-  }
+  // Validate and normalize the date to ISO format
+  if (this.isModified("date") && this.date) {
+    const d = new Date(this.date);
+    if (Number.isNaN(d.getTime())) {
+      return next(new Error("Invalid date"));
+    }
+    this.date = d.toISOString();
+  }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In database/event.model.ts around lines 57 to 61, the code always converts
this.date to ISO without checking validity or whether the field was modified;
change it to first check that the document's date field was modified (e.g.,
this.isModified('date')) and only then attempt normalization, and before
assigning run a validity check (e.g., create a Date and ensure
!isNaN(date.getTime()) or use Date.parse) so you only set this.date = isoString
when the input is a valid date; if invalid, leave the field unchanged or set a
validation error as appropriate.

Comment on lines +21 to +35
// Extend NodeJS.Global to include mongoose property
declare global {
// eslint-disable-next-line no-var
var mongoose: MongooseCache | undefined;
}

let cached: MongooseCache = global.mongoose ?? { conn: null, promise: null };

if (!cached) {
cached = (global as typeof globalThis).mongoose = {
conn: null,
promise: null,
};
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix global cache name and ensure it’s actually persisted across reloads.

  • noRedeclare: global var name ‘mongoose’ collides with the imported symbol.
  • Bug: when global.mongoose is undefined, you create a local object but never attach it back to global, so hot‑reload caching won’t work.

Apply this diff:

-// Extend NodeJS.Global to include mongoose property
-declare global {
-  // eslint-disable-next-line no-var
-  var mongoose: MongooseCache | undefined;
-}
-
-let cached: MongooseCache = global.mongoose ?? { conn: null, promise: null };
-
-if (!cached) {
-  cached = (global as typeof globalThis).mongoose = {
-    conn: null,
-    promise: null,
-  };
-}
+// Extend global to include a dedicated mongoose cache property
+declare global {
+  // eslint-disable-next-line no-var
+  var mongooseCache: MongooseCache | undefined;
+}
+
+const globalForMongoose = global as unknown as { mongooseCache?: MongooseCache };
+if (!globalForMongoose.mongooseCache) {
+  globalForMongoose.mongooseCache = { conn: null, promise: null };
+}
+const cached = globalForMongoose.mongooseCache!;
🧰 Tools
🪛 Biome (2.1.2)

[error] 24-24: Shouldn't redeclare 'mongoose'. Consider to delete it or rename it.

'mongoose' is defined here:

(lint/suspicious/noRedeclare)

@coderabbitai
Copy link

coderabbitai bot commented Oct 27, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #4

coderabbitai bot added a commit that referenced this pull request Oct 27, 2025
Docstrings generation was requested by @ailearningguy.

* #3 (comment)

The following files were modified:

* `lib/mongodb.ts`
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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.

2 participants