Initial API scaffold: Elysia + Bun + Drizzle + BetterAuth + LangChain

This commit is contained in:
2026-01-27 02:43:11 +00:00
commit 06f1b4e548
18 changed files with 1807 additions and 0 deletions

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

@@ -0,0 +1,163 @@
import { pgTable, text, timestamp, uuid, boolean, jsonb, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
// Users table (managed by BetterAuth, but we define it for relations)
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
email: text('email').notNull().unique(),
name: text('name').notNull(),
emailVerified: boolean('email_verified').default(false),
image: text('image'),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
});
// BetterAuth session table
export const sessions = pgTable('sessions', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
token: text('token').notNull().unique(),
expiresAt: timestamp('expires_at').notNull(),
ipAddress: text('ip_address'),
userAgent: text('user_agent'),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
});
// BetterAuth account table (for OAuth providers)
export const accounts = pgTable('accounts', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
accountId: text('account_id').notNull(),
providerId: text('provider_id').notNull(),
accessToken: text('access_token'),
refreshToken: text('refresh_token'),
accessTokenExpiresAt: timestamp('access_token_expires_at'),
refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
scope: text('scope'),
idToken: text('id_token'),
password: text('password'),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
});
// BetterAuth verification table
export const verifications = pgTable('verifications', {
id: uuid('id').primaryKey().defaultRandom(),
identifier: text('identifier').notNull(),
value: text('value').notNull(),
expiresAt: timestamp('expires_at').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
});
// Clients table
export const clients = pgTable('clients', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
// Basic info
firstName: text('first_name').notNull(),
lastName: text('last_name').notNull(),
email: text('email'),
phone: text('phone'),
// Address
street: text('street'),
city: text('city'),
state: text('state'),
zip: text('zip'),
// Professional
company: text('company'),
role: text('role'),
industry: text('industry'),
// Personal
birthday: timestamp('birthday'),
anniversary: timestamp('anniversary'),
interests: jsonb('interests').$type<string[]>().default([]),
family: jsonb('family').$type<{ spouse?: string; children?: string[] }>(),
notes: text('notes'),
// Organization
tags: jsonb('tags').$type<string[]>().default([]),
// Tracking
lastContactedAt: timestamp('last_contacted_at'),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
});
// Events table (birthdays, anniversaries, follow-ups)
export const events = pgTable('events', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
clientId: uuid('client_id').references(() => clients.id, { onDelete: 'cascade' }).notNull(),
type: text('type').notNull(), // 'birthday' | 'anniversary' | 'followup' | 'custom'
title: text('title').notNull(),
date: timestamp('date').notNull(),
recurring: boolean('recurring').default(false),
reminderDays: integer('reminder_days').default(7),
lastTriggered: timestamp('last_triggered'),
createdAt: timestamp('created_at').defaultNow().notNull(),
});
// Communications table (emails, messages)
export const communications = pgTable('communications', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
clientId: uuid('client_id').references(() => clients.id, { onDelete: 'cascade' }).notNull(),
type: text('type').notNull(), // 'email' | 'birthday' | 'followup'
subject: text('subject'),
content: text('content').notNull(),
aiGenerated: boolean('ai_generated').default(false),
aiModel: text('ai_model'), // Which model was used
status: text('status').default('draft'), // 'draft' | 'approved' | 'sent'
sentAt: timestamp('sent_at'),
createdAt: timestamp('created_at').defaultNow().notNull(),
});
// Relations
export const usersRelations = relations(users, ({ many }) => ({
clients: many(clients),
events: many(events),
communications: many(communications),
sessions: many(sessions),
accounts: many(accounts),
}));
export const clientsRelations = relations(clients, ({ one, many }) => ({
user: one(users, {
fields: [clients.userId],
references: [users.id],
}),
events: many(events),
communications: many(communications),
}));
export const eventsRelations = relations(events, ({ one }) => ({
user: one(users, {
fields: [events.userId],
references: [users.id],
}),
client: one(clients, {
fields: [events.clientId],
references: [clients.id],
}),
}));
export const communicationsRelations = relations(communications, ({ one }) => ({
user: one(users, {
fields: [communications.userId],
references: [users.id],
}),
client: one(clients, {
fields: [communications.clientId],
references: [clients.id],
}),
}));