Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Wikedhart18/nextjs-ai-chatbot/llms.txt

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

The app uses PostgreSQL via Vercel Postgres (powered by Neon). Drizzle ORM manages the schema and migrations.

Setup

1

Provision a Postgres database

Follow the Vercel Postgres quickstart to create a new database. Vercel will provide a connection string once the database is ready.
2

Set POSTGRES_URL

Add the connection string to your .env.local file:
.env.local
POSTGRES_URL=postgres://user:password@host:5432/dbname
POSTGRES_URL must be set before running migrations. The migration script will throw an error if it is missing.
3

Run migrations

Apply all pending migrations to create the database tables:
pnpm db:migrate
A successful run prints:
⏳ Running migrations...
✅ Migrations completed in Xms
Migrations also run automatically as part of the production build (pnpm build executes tsx lib/db/migrate.ts before next build).

Database scripts

ScriptCommandDescription
Migratepnpm db:migrateApply pending migrations to the database.
Generatepnpm db:generateGenerate a new migration file from schema changes.
Pushpnpm db:pushPush schema changes directly without a migration file (useful during prototyping).
Studiopnpm db:studioOpen Drizzle Studio, a browser-based GUI for inspecting and editing data.
Pullpnpm db:pullIntrospect the database and update the local schema.
Checkpnpm db:checkValidate migration files for consistency.
Use pnpm db:studio during local development to inspect rows and debug data issues without writing raw SQL.

Schema overview

All tables are defined in lib/db/schema.ts. The six tables and their relationships are:
lib/db/schema.ts
// Users — one row per registered account
export const user = pgTable('User', {
  id: uuid('id').primaryKey().notNull().defaultRandom(),
  email: varchar('email', { length: 64 }).notNull(),
  password: varchar('password', { length: 64 }),
});

// Chats — one row per conversation, owned by a user
export const chat = pgTable('Chat', {
  id: uuid('id').primaryKey().notNull().defaultRandom(),
  createdAt: timestamp('createdAt').notNull(),
  title: text('title').notNull(),
  userId: uuid('userId').notNull().references(() => user.id),
  visibility: varchar('visibility', { enum: ['public', 'private'] })
    .notNull()
    .default('private'),
});

// Messages — one row per message in a chat
export const message = pgTable('Message', {
  id: uuid('id').primaryKey().notNull().defaultRandom(),
  chatId: uuid('chatId').notNull().references(() => chat.id),
  role: varchar('role').notNull(),
  content: json('content').notNull(),
  createdAt: timestamp('createdAt').notNull(),
});

// Votes — upvote/downvote per message, per chat (composite primary key)
export const vote = pgTable('Vote', {
  chatId: uuid('chatId').notNull().references(() => chat.id),
  messageId: uuid('messageId').notNull().references(() => message.id),
  isUpvoted: boolean('isUpvoted').notNull(),
});

// Documents — artifacts (text, code, image, sheet) generated during a chat
export const document = pgTable('Document', {
  id: uuid('id').notNull().defaultRandom(),
  createdAt: timestamp('createdAt').notNull(),
  title: text('title').notNull(),
  content: text('content'),
  kind: varchar('text', { enum: ['text', 'code', 'image', 'sheet'] })
    .notNull()
    .default('text'),
  userId: uuid('userId').notNull().references(() => user.id),
});

// Suggestions — inline edit suggestions on a document
export const suggestion = pgTable('Suggestion', {
  id: uuid('id').notNull().defaultRandom(),
  documentId: uuid('documentId').notNull(),
  documentCreatedAt: timestamp('documentCreatedAt').notNull(),
  originalText: text('originalText').notNull(),
  suggestedText: text('suggestedText').notNull(),
  description: text('description'),
  isResolved: boolean('isResolved').notNull().default(false),
  userId: uuid('userId').notNull().references(() => user.id),
  createdAt: timestamp('createdAt').notNull(),
});

Table descriptions

TableDescription
UserOne row per registered account. Stores the email and a bcrypt-hashed password.
ChatOne conversation thread per row, linked to its owner. Can be public or private.
MessageEvery message exchanged in a chat, including both user and assistant turns. Content is stored as JSON to support rich message structures.
VoteRecords whether a user upvoted or downvoted a specific assistant message. Identified by the composite key (chatId, messageId).
DocumentArtifacts generated in the artifact panel: text documents, code files, images, or spreadsheets.
SuggestionInline edit suggestions attached to a document, tracking the original text, the proposed replacement, and whether the suggestion has been resolved.

Build docs developers (and LLMs) love