All schema definitions are in lib/db/schema.ts.
User accounts supporting both email and LDAP authentication.
{
id: serial (primary key),
username: varchar(255) unique not null,
name: varchar(255) not null,
email: varchar(255) unique not null,
password: varchar(255) nullable, // Hashed, only for email auth
authType: varchar(50) not null default 'email', // 'email' or 'ldap'
mustChangePassword: boolean default false,
createdAt: timestamp not null,
updatedAt: timestamp not null,
lastLogin: timestamp nullable
}Indexes:
- Primary key on
id - Unique constraint on
username - Unique constraint on
email
Notes:
passwordis null for LDAP usersauthTypedetermines authentication methodmustChangePasswordforces password change on next login
User-generated content/posts.
{
id: serial (primary key),
title: varchar(255) not null,
content: text nullable,
authorId: integer not null, // FK -> users.id
createdAt: timestamp not null,
updatedAt: timestamp not null
}Relationships:
authorIdreferencesusers.id
Project management records.
{
id: serial (primary key),
projectVersion: varchar(100) not null,
projectCode: varchar(100) not null,
name: varchar(255) nullable,
description: text nullable,
ownerId: integer not null, // FK -> users.id
status: varchar(50) not null default 'active', // 'active', 'archived', 'completed'
visibility: varchar(50) not null default 'private', // 'private', 'public'
metadata: jsonb nullable,
createdAt: timestamp not null,
updatedAt: timestamp not null,
lastAccessedAt: timestamp nullable
}Relationships:
ownerIdreferencesusers.id
Notes:
projectVersionandprojectCodeare required identifiersnameis optional, falls back to "Untitled Project"metadatastores additional project data as JSON
Project access control and memberships.
{
id: serial (primary key),
projectId: integer not null, // FK -> projects.id
userId: integer not null, // FK -> users.id
role: varchar(50) not null default 'member', // 'owner', 'admin', 'member', 'viewer'
joinedAt: timestamp not null
}Relationships:
projectIdreferencesprojects.iduserIdreferencesusers.id
Roles:
owner- Full controladmin- Management permissionsmember- Read/write accessviewer- Read-only access
Access request workflow for projects.
{
id: serial (primary key),
projectId: integer not null, // FK -> projects.id
userId: integer not null, // FK -> users.id
status: varchar(50) not null default 'pending', // 'pending', 'approved', 'rejected'
requestedAt: timestamp not null,
resolvedAt: timestamp nullable,
resolvedBy: integer nullable // FK -> users.id
}Relationships:
projectIdreferencesprojects.iduserIdreferencesusers.id(requester)resolvedByreferencesusers.id(approver)
Workflow:
- User requests access (
status: 'pending') - Owner/admin approves or rejects
resolvedAtandresolvedByare set- If approved, user is added to
project_members
Background job tracking (BullMQ).
{
id: serial (primary key),
name: varchar(255) not null,
status: varchar(50) not null default 'pending', // 'pending', 'processing', 'completed', 'failed'
data: jsonb nullable,
result: jsonb nullable,
createdAt: timestamp not null,
completedAt: timestamp nullable
}Status Flow:
pending- Job createdprocessing- Job being executedcompleted- Job succeededfailed- Job failed
users
├──< posts (authorId)
├──< projects (ownerId)
├──< project_members (userId)
├──< permission_requests (userId, resolvedBy)
└──< (other user-related entities)
projects
├──< project_members (projectId)
└──< permission_requests (projectId)
- Define schema in
lib/db/schema.ts:
export const myTable = pgTable('my_table', {
id: serial('id').primaryKey(),
name: varchar('name', { length: 255 }).notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
});- Push to database:
npm run db:pushCommon Drizzle column types:
serial('id')- Auto-incrementing integervarchar('name', { length: 255 })- Variable-length stringtext('content')- Unlimited length stringinteger('count')- Integer numberboolean('active')- Booleantimestamp('created_at')- Timestamp with timezonejsonb('data')- JSON data
// Not null
.notNull()
// Unique
.unique()
// Default value
.default('value')
.defaultNow() // For timestamps
// Primary key
.primaryKey()
// Foreign key
.references(() => users.id)Default seed creates root user:
npm run db:seedCreates:
{
username: 'root',
password: 'Must-Changed' (hashed),
email: 'root@example.com',
authType: 'email',
mustChangePassword: true
}