import { pgTable, uuid, text, integer, boolean, timestamp, index, check } from 'drizzle-orm/pg-core'; import { sql } from 'drizzle-orm'; // ─── Users & Sessions ────────────────────────────────────────────── export const users = pgTable('users', { id: text('id').primaryKey(), email: text('email').unique().notNull(), displayName: text('display_name'), passwordHash: text('password_hash').notNull(), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull() }); export const sessions = pgTable('sessions', { id: text('id').primaryKey(), // SHA-256 hash of the session token userId: text('user_id') .notNull() .references(() => users.id, { onDelete: 'cascade' }), expiresAt: timestamp('expires_at', { withTimezone: true }).notNull() }); // ─── Locations ────────────────────────────────────────────────────── export const locations = pgTable('locations', { id: uuid('id').defaultRandom().primaryKey(), name: text('name').notNull(), description: text('description'), parentId: uuid('parent_id').references((): any => locations.id), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull() }); // ─── Devices ──────────────────────────────────────────────────────── export const devices = pgTable( 'devices', { id: uuid('id').defaultRandom().primaryKey(), title: text('title').notNull(), category: text('category').notNull(), brand: text('brand'), model: text('model'), serialNumber: text('serial_number'), year: integer('year'), condition: text('condition').notNull().default('Waiting to be Tested'), voltage: text('voltage'), frequency: text('frequency'), origin: text('origin'), faultDescription: text('fault_description'), repairNotes: text('repair_notes'), locationId: uuid('location_id').references(() => locations.id), initialCondition: text('initial_condition'), generalNotes: text('general_notes'), disabled: boolean('disabled').default(false).notNull(), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [ index('devices_category_idx').on(table.category), index('devices_condition_idx').on(table.condition), index('devices_location_idx').on(table.locationId), check('devices_category_check', sql`${table.category} IN ('Computer', 'Audio Equipment', 'Peripheral', 'Other')`), check('devices_condition_check', sql`${table.condition} IN ('Working', 'In Repair', 'Waiting for Repair', 'Waiting to be Tested', 'Unrepairable')`) ] ); // ─── Computer Details (1:1 extension) ─────────────────────────────── export const computerDetails = pgTable('computer_details', { id: uuid('id').defaultRandom().primaryKey(), deviceId: uuid('device_id') .notNull() .unique() .references(() => devices.id, { onDelete: 'cascade' }), osVersion: text('os_version'), firmwareVersion: text('firmware_version'), installedSoftware: text('installed_software') }); // ─── Device Images ────────────────────────────────────────────────── export const deviceImages = pgTable( 'device_images', { id: uuid('id').defaultRandom().primaryKey(), deviceId: uuid('device_id') .notNull() .references(() => devices.id, { onDelete: 'cascade' }), filePath: text('file_path').notNull(), thumbnailPath: text('thumbnail_path'), caption: text('caption'), sortOrder: integer('sort_order').default(0), uploadedAt: timestamp('uploaded_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [index('device_images_device_idx').on(table.deviceId)] ); // ─── Device Documents ─────────────────────────────────────────────── export const deviceDocuments = pgTable( 'device_documents', { id: uuid('id').defaultRandom().primaryKey(), deviceId: uuid('device_id') .notNull() .references(() => devices.id, { onDelete: 'cascade' }), filePath: text('file_path').notNull(), originalFilename: text('original_filename').notNull(), fileType: text('file_type'), description: text('description'), uploadedAt: timestamp('uploaded_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [index('device_documents_device_idx').on(table.deviceId)] ); // ─── Components ───────────────────────────────────────────────────── export const components = pgTable( 'components', { id: uuid('id').defaultRandom().primaryKey(), title: text('title').notNull(), componentType: text('component_type').notNull(), brand: text('brand'), partNumber: text('part_number'), serialNumber: text('serial_number'), condition: text('condition').notNull().default('Working'), firmwareVersion: text('firmware_version'), specs: text('specs'), notes: text('notes'), currentDeviceId: uuid('current_device_id').references(() => devices.id, { onDelete: 'set null' }), locationId: uuid('location_id').references(() => locations.id), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [ index('components_type_idx').on(table.componentType), index('components_device_idx').on(table.currentDeviceId), index('components_location_idx').on(table.locationId), check('components_condition_check', sql`${table.condition} IN ('Working', 'Faulty', 'Unknown', 'Refurbished')`) ] ); // ─── Component Images ─────────────────────────────────────────────── export const componentImages = pgTable( 'component_images', { id: uuid('id').defaultRandom().primaryKey(), componentId: uuid('component_id') .notNull() .references(() => components.id, { onDelete: 'cascade' }), filePath: text('file_path').notNull(), thumbnailPath: text('thumbnail_path'), caption: text('caption'), uploadedAt: timestamp('uploaded_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [index('component_images_component_idx').on(table.componentId)] ); // ─── Component Documents ──────────────────────────────────────────── export const componentDocuments = pgTable( 'component_documents', { id: uuid('id').defaultRandom().primaryKey(), componentId: uuid('component_id') .notNull() .references(() => components.id, { onDelete: 'cascade' }), filePath: text('file_path').notNull(), originalFilename: text('original_filename').notNull(), fileType: text('file_type'), description: text('description'), uploadedAt: timestamp('uploaded_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [index('component_documents_component_idx').on(table.componentId)] ); // ─── Installation Log (append-only) ───────────────────────────────── export const installationLog = pgTable( 'installation_log', { id: uuid('id').defaultRandom().primaryKey(), componentId: uuid('component_id') .notNull() .references(() => components.id, { onDelete: 'cascade' }), deviceId: uuid('device_id') .notNull() .references(() => devices.id, { onDelete: 'cascade' }), action: text('action').notNull(), performedBy: text('performed_by'), notes: text('notes'), performedAt: timestamp('performed_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [ index('install_log_component_idx').on(table.componentId), index('install_log_device_idx').on(table.deviceId), index('install_log_date_idx').on(table.performedAt), check('install_log_action_check', sql`${table.action} IN ('installed', 'removed', 'swapped')`) ] ); // ─── Checklist Templates ──────────────────────────────────────────── export const checklistTemplates = pgTable('checklist_templates', { id: uuid('id').defaultRandom().primaryKey(), title: text('title').notNull(), description: text('description'), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull() }); export const templateItems = pgTable( 'template_items', { id: uuid('id').defaultRandom().primaryKey(), templateId: uuid('template_id') .notNull() .references(() => checklistTemplates.id, { onDelete: 'cascade' }), text: text('text').notNull(), itemType: text('item_type').notNull().default('checkbox'), // 'checkbox' or 'input' unit: text('unit'), // e.g. 'RPM', 'dB', '%' sortOrder: integer('sort_order').default(0).notNull() }, (table) => [index('template_items_template_idx').on(table.templateId)] ); // ─── Device Checklists ────────────────────────────────────────────── export const deviceChecklists = pgTable( 'device_checklists', { id: uuid('id').defaultRandom().primaryKey(), deviceId: uuid('device_id') .notNull() .references(() => devices.id, { onDelete: 'cascade' }), title: text('title').notNull(), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [index('device_checklists_device_idx').on(table.deviceId)] ); export const checklistItems = pgTable( 'checklist_items', { id: uuid('id').defaultRandom().primaryKey(), checklistId: uuid('checklist_id') .notNull() .references(() => deviceChecklists.id, { onDelete: 'cascade' }), text: text('text').notNull(), itemType: text('item_type').notNull().default('checkbox'), // 'checkbox' or 'input' unit: text('unit'), // e.g. 'RPM', 'dB', '%' checked: boolean('checked').default(false).notNull(), value: text('value'), // for input type items sortOrder: integer('sort_order').default(0).notNull(), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [index('checklist_items_checklist_idx').on(table.checklistId)] ); // ─── Device Log (append-only repair/operation history) ─────────────── export const deviceLog = pgTable( 'device_log', { id: uuid('id').defaultRandom().primaryKey(), deviceId: uuid('device_id') .notNull() .references(() => devices.id, { onDelete: 'cascade' }), type: text('type').notNull(), description: text('description').notNull(), conditionAfter: text('condition_after'), performedBy: text('performed_by'), performedAt: timestamp('performed_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [ index('device_log_device_idx').on(table.deviceId), index('device_log_date_idx').on(table.performedAt), check('device_log_type_check', sql`${table.type} IN ('repair', 'inspection', 'cleaning', 'modification', 'diagnostic', 'recap', 'other')`) ] ); // ─── Todos ────────────────────────────────────────────────────────── export const todos = pgTable( 'todos', { id: uuid('id').defaultRandom().primaryKey(), title: text('title').notNull(), description: text('description'), status: text('status').notNull().default('todo'), priority: integer('priority').notNull().default(2), // 0=urgent, 1=high, 2=medium, 3=low deviceId: uuid('device_id').references(() => devices.id, { onDelete: 'set null' }), dueDate: timestamp('due_date', { withTimezone: true }), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull() }, (table) => [ index('todos_status_idx').on(table.status), index('todos_priority_idx').on(table.priority), index('todos_device_idx').on(table.deviceId), check('todos_status_check', sql`${table.status} IN ('todo', 'in_progress', 'done')`), check('todos_priority_check', sql`${table.priority} IN (0, 1, 2, 3)`) ] );