First pass

This commit is contained in:
2025-12-25 22:10:06 -07:00
parent a2af6195f9
commit 455c3dbd9a
58 changed files with 10299 additions and 3 deletions

135
src/db/schema.ts Normal file
View File

@@ -0,0 +1,135 @@
import { sqliteTable, text, integer, primaryKey, foreignKey } from 'drizzle-orm/sqlite-core';
import { nanoid } from 'nanoid';
export const users = sqliteTable('users', {
id: text('id').primaryKey().$defaultFn(() => nanoid()),
email: text('email').notNull().unique(),
passwordHash: text('password_hash').notNull(),
name: text('name').notNull(),
isSiteAdmin: integer('is_site_admin', { mode: 'boolean' }).default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
});
export const organizations = sqliteTable('organizations', {
id: text('id').primaryKey().$defaultFn(() => nanoid()),
name: text('name').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
});
export const members = sqliteTable('members', {
userId: text('user_id').notNull(),
organizationId: text('organization_id').notNull(),
role: text('role').notNull().default('member'), // 'owner', 'admin', 'member'
joinedAt: integer('joined_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
}, (table: any) => ({
pk: primaryKey({ columns: [table.userId, table.organizationId] }),
userFk: foreignKey({
columns: [table.userId],
foreignColumns: [users.id]
}),
orgFk: foreignKey({
columns: [table.organizationId],
foreignColumns: [organizations.id]
})
}));
export const clients = sqliteTable('clients', {
id: text('id').primaryKey().$defaultFn(() => nanoid()),
organizationId: text('organization_id').notNull(),
name: text('name').notNull(),
email: text('email'),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
}, (table: any) => ({
orgFk: foreignKey({
columns: [table.organizationId],
foreignColumns: [organizations.id]
})
}));
export const categories = sqliteTable('categories', {
id: text('id').primaryKey().$defaultFn(() => nanoid()),
organizationId: text('organization_id').notNull(),
name: text('name').notNull(),
color: text('color'),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
}, (table: any) => ({
orgFk: foreignKey({
columns: [table.organizationId],
foreignColumns: [organizations.id]
})
}));
export const timeEntries = sqliteTable('time_entries', {
id: text('id').primaryKey().$defaultFn(() => nanoid()),
userId: text('user_id').notNull(),
organizationId: text('organization_id').notNull(),
clientId: text('client_id').notNull(),
categoryId: text('category_id').notNull(),
startTime: integer('start_time', { mode: 'timestamp' }).notNull(),
endTime: integer('end_time', { mode: 'timestamp' }),
description: text('description'),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
}, (table: any) => ({
userFk: foreignKey({
columns: [table.userId],
foreignColumns: [users.id]
}),
orgFk: foreignKey({
columns: [table.organizationId],
foreignColumns: [organizations.id]
}),
clientFk: foreignKey({
columns: [table.clientId],
foreignColumns: [clients.id]
}),
categoryFk: foreignKey({
columns: [table.categoryId],
foreignColumns: [categories.id]
})
}));
export const tags = sqliteTable('tags', {
id: text('id').primaryKey().$defaultFn(() => nanoid()),
organizationId: text('organization_id').notNull(),
name: text('name').notNull(),
color: text('color'),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
}, (table: any) => ({
orgFk: foreignKey({
columns: [table.organizationId],
foreignColumns: [organizations.id]
})
}));
export const timeEntryTags = sqliteTable('time_entry_tags', {
timeEntryId: text('time_entry_id').notNull(),
tagId: text('tag_id').notNull(),
}, (table: any) => ({
pk: primaryKey({ columns: [table.timeEntryId, table.tagId] }),
timeEntryFk: foreignKey({
columns: [table.timeEntryId],
foreignColumns: [timeEntries.id]
}),
tagFk: foreignKey({
columns: [table.tagId],
foreignColumns: [tags.id]
})
}));
export const sessions = sqliteTable('sessions', {
id: text('id').primaryKey(),
userId: text('user_id').notNull(),
expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
}, (table: any) => ({
userFk: foreignKey({
columns: [table.userId],
foreignColumns: [users.id]
})
}));
export const siteSettings = sqliteTable('site_settings', {
id: text('id').primaryKey().$defaultFn(() => nanoid()),
key: text('key').notNull().unique(),
value: text('value').notNull(),
updatedAt: integer('updated_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
});