Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/abdelhafid37/talkbox/llms.txt

Use this file to discover all available pages before exploring further.

TalkBox persists all application data in MongoDB through two Mongoose schemas: User and Message. Mongoose provides schema-level validation, type coercion, and the populate helper that resolves ObjectId references into embedded subdocuments — a pattern TalkBox uses heavily when returning conversation history. Both schemas enable the timestamps option, so every document automatically carries createdAt and updatedAt fields managed by Mongoose.

User model

The User schema represents a registered account. It stores the minimal information needed to authenticate a user and display their identity to other participants in the chat.
// server/src/models/User.js
const mongoose = require("mongoose");

const userSchema = new mongoose.Schema(
  {
    username: {
      type: String,
      required: true,
      unique: true,
      trim: true,
    },
    email: {
      type: String,
      required: true,
      unique: true,
      trim: true,
    },
    password: {
      type: String,
      required: true,
    },
  },
  {
    timestamps: true,
  },
);

const User = mongoose.model("User", userSchema);

module.exports = User;

Fields

username
String
required
The user’s public display name, shown in the chat sidebar and on message bubbles. Leading and trailing whitespace is stripped by the trim option before the value is saved. Enforced as unique at the MongoDB index level — attempting to register a duplicate username returns a validation error.
email
String
required
The user’s email address, used as the login credential alongside their password. Leading and trailing whitespace is stripped by trim before the value is saved. Enforced as unique at the MongoDB index level — duplicate email registrations are rejected before they reach the database.
password
String
required
The user’s hashed password. The plain-text password submitted during registration is never stored; the auth controller passes it through bcrypt.hash() before calling User.create(). During login, bcrypt.compare() validates the submitted password against this stored hash. This field is never included in API responses — the /api/users endpoints return only _id, username, and email.
createdAt
Date
Automatically set by Mongoose when the document is first created (timestamps: true). Not explicitly defined in the schema.
updatedAt
Date
Automatically updated by Mongoose on every save. Not explicitly defined in the schema.
The password field is intentionally omitted from all user-facing query results. Controllers that return user data use Mongoose’s select("-password") projection to strip it before sending the response.

Message model

The Message schema represents a single chat message exchanged between two users. References to User documents are stored as MongoDB ObjectIds rather than embedded subdocuments, keeping the messages collection compact.
// server/src/models/Message.js
const mongoose = require("mongoose");

const messageSchema = new mongoose.Schema(
  {
    sender: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    receiver: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    content: {
      type: String,
      required: true,
      trim: true,
    },
  },
  {
    timestamps: true,
  },
);

const Message = mongoose.model("Message", messageSchema);

module.exports = Message;

Fields

sender
ObjectId (ref: User)
required
The MongoDB _id of the user who sent the message. Stored as a reference so that the User document can be joined via Mongoose populate. When conversation history is returned by the API or emitted over the socket, sender is populated to include username only (select: "username").
receiver
ObjectId (ref: User)
required
The MongoDB _id of the user who is the intended recipient. Stored and populated in the same way as sender. The getConversation query uses both sender and receiver fields together to filter all messages exchanged between a specific pair of users, regardless of direction.
content
String
required
The text body of the message. Leading and trailing whitespace is stripped by trim before the value is persisted. There is currently no maximum-length constraint defined in the schema.
createdAt
Date
Automatically set by Mongoose when the message is first created. The chat UI uses this timestamp (formatted with date-fns) to display the send time on each message bubble.
updatedAt
Date
Automatically maintained by Mongoose. Messages are not edited in the current version of TalkBox, so this value equals createdAt in practice.

Relationships

Messages and users are linked by MongoDB ObjectId references, following the standard Mongoose ref / populate pattern. Two key relationships exist:
  • Message.sender → User — every message knows which user sent it.
  • Message.receiver → User — every message knows which user should receive it.
When a message is created via the sendMessage socket event, populate is called immediately on the new document before it is emitted to both parties, so the client never needs to make a secondary request to resolve usernames:
// server/src/sockets/socket.js — population after create
const populatedMessage = await message.populate([
  { path: "sender", select: "username" },
  { path: "receiver", select: "username" },
]);
When the REST API loads a conversation between two users, the getConversation controller queries for messages where the pair appears in either direction and populates both reference fields using the same projection.

Indexes and uniqueness

MongoDB unique indexes are declared directly on the User schema via Mongoose’s unique: true shorthand. Mongoose creates these indexes automatically on first connection when they do not already exist:
CollectionFieldIndex type
usersusernameUnique
usersemailUnique
No additional indexes are defined on the messages collection in the current schema. For production deployments handling large conversation histories, a compound index on { sender: 1, receiver: 1, createdAt: -1 } would significantly improve the performance of the getConversation query.

Build docs developers (and LLMs) love