feat(yachts): add yachts, ownership history, notes, tags schema

This commit is contained in:
Matt Ciaccio
2026-04-23 17:51:19 +02:00
parent 11969c0d8a
commit 51523e6768
5 changed files with 7781 additions and 0 deletions

View File

@@ -7,6 +7,9 @@ export * from './users';
// Clients
export * from './clients';
// Yachts
export * from './yachts';
// Interests
export * from './interests';

119
src/lib/db/schema/yachts.ts Normal file
View File

@@ -0,0 +1,119 @@
import {
pgTable,
text,
integer,
numeric,
timestamp,
boolean,
index,
uniqueIndex,
primaryKey,
} from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm';
import { ports } from './ports';
export const yachts = pgTable(
'yachts',
{
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
portId: text('port_id')
.notNull()
.references(() => ports.id),
name: text('name').notNull(),
hullNumber: text('hull_number'),
registration: text('registration'),
flag: text('flag'),
yearBuilt: integer('year_built'),
builder: text('builder'),
model: text('model'),
hullMaterial: text('hull_material'),
lengthFt: numeric('length_ft'),
widthFt: numeric('width_ft'),
draftFt: numeric('draft_ft'),
lengthM: numeric('length_m'),
widthM: numeric('width_m'),
draftM: numeric('draft_m'),
currentOwnerType: text('current_owner_type').notNull(), // 'client' | 'company'
currentOwnerId: text('current_owner_id').notNull(),
status: text('status').notNull().default('active'), // 'active' | 'retired' | 'sold_away'
notes: text('notes'),
archivedAt: timestamp('archived_at', { withTimezone: true }),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
},
(table) => [
index('idx_yachts_port').on(table.portId),
index('idx_yachts_current_owner').on(
table.portId,
table.currentOwnerType,
table.currentOwnerId,
),
index('idx_yachts_name').on(table.portId, table.name),
index('idx_yachts_archived').on(table.portId, table.archivedAt),
],
);
export const yachtOwnershipHistory = pgTable(
'yacht_ownership_history',
{
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
yachtId: text('yacht_id')
.notNull()
.references(() => yachts.id, { onDelete: 'cascade' }),
ownerType: text('owner_type').notNull(),
ownerId: text('owner_id').notNull(),
startDate: timestamp('start_date', { withTimezone: true, mode: 'date' }).notNull(),
endDate: timestamp('end_date', { withTimezone: true, mode: 'date' }),
transferReason: text('transfer_reason'),
transferNotes: text('transfer_notes'),
createdBy: text('created_by').notNull(),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
},
(table) => [
index('idx_yoh_yacht').on(table.yachtId),
uniqueIndex('idx_yoh_active')
.on(table.yachtId)
.where(sql`${table.endDate} IS NULL`),
],
);
export const yachtNotes = pgTable(
'yacht_notes',
{
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
yachtId: text('yacht_id')
.notNull()
.references(() => yachts.id, { onDelete: 'cascade' }),
authorId: text('author_id').notNull(),
content: text('content').notNull(),
mentions: text('mentions').array(),
isLocked: boolean('is_locked').notNull().default(false),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
},
(table) => [index('idx_yn_yacht').on(table.yachtId)],
);
export const yachtTags = pgTable(
'yacht_tags',
{
yachtId: text('yacht_id')
.notNull()
.references(() => yachts.id, { onDelete: 'cascade' }),
tagId: text('tag_id').notNull(),
},
(table) => [primaryKey({ columns: [table.yachtId, table.tagId] })],
);
export type Yacht = typeof yachts.$inferSelect;
export type NewYacht = typeof yachts.$inferInsert;
export type YachtOwnershipHistoryRow = typeof yachtOwnershipHistory.$inferSelect;
export type NewYachtOwnershipHistoryRow = typeof yachtOwnershipHistory.$inferInsert;
export type YachtNote = typeof yachtNotes.$inferSelect;
export type NewYachtNote = typeof yachtNotes.$inferInsert;