Add Turso/Vercel deployment configuration

- Updated database connection to support Turso auth token
- Added vercel.json with bun build configuration
- Updated environment schema for production deployment
- Added new features and components for production readiness
This commit is contained in:
2025-07-12 01:42:43 -04:00
parent 2d217fab47
commit a1b40e7a9c
75 changed files with 8821 additions and 1803 deletions

View File

@@ -13,7 +13,11 @@ const globalForDb = globalThis as unknown as {
};
export const client =
globalForDb.client ?? createClient({ url: env.DATABASE_URL });
globalForDb.client ??
createClient({
url: env.DATABASE_URL,
authToken: env.DATABASE_AUTH_TOKEN,
});
if (env.NODE_ENV !== "production") globalForDb.client = client;
export const db = drizzle(client, { schema });

View File

@@ -27,6 +27,7 @@ export const users = createTable("user", (d) => ({
export const usersRelations = relations(users, ({ many }) => ({
accounts: many(accounts),
clients: many(clients),
businesses: many(businesses),
invoices: many(invoices),
}));
@@ -127,6 +128,50 @@ export const clientsRelations = relations(clients, ({ one, many }) => ({
invoices: many(invoices),
}));
export const businesses = createTable(
"business",
(d) => ({
id: d
.text({ length: 255 })
.notNull()
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
name: d.text({ length: 255 }).notNull(),
email: d.text({ length: 255 }),
phone: d.text({ length: 50 }),
addressLine1: d.text({ length: 255 }),
addressLine2: d.text({ length: 255 }),
city: d.text({ length: 100 }),
state: d.text({ length: 50 }),
postalCode: d.text({ length: 20 }),
country: d.text({ length: 100 }),
website: d.text({ length: 255 }),
taxId: d.text({ length: 100 }),
logoUrl: d.text({ length: 500 }),
isDefault: d.integer({ mode: "boolean" }).default(false),
createdById: d
.text({ length: 255 })
.notNull()
.references(() => users.id),
createdAt: d
.integer({ mode: "timestamp" })
.default(sql`(unixepoch())`)
.notNull(),
updatedAt: d.integer({ mode: "timestamp" }).$onUpdate(() => new Date()),
}),
(t) => [
index("business_created_by_idx").on(t.createdById),
index("business_name_idx").on(t.name),
index("business_email_idx").on(t.email),
index("business_is_default_idx").on(t.isDefault),
],
);
export const businessesRelations = relations(businesses, ({ one, many }) => ({
createdBy: one(users, { fields: [businesses.createdById], references: [users.id] }),
invoices: many(invoices),
}));
export const invoices = createTable(
"invoice",
(d) => ({
@@ -136,6 +181,9 @@ export const invoices = createTable(
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
invoiceNumber: d.text({ length: 100 }).notNull(),
businessId: d
.text({ length: 255 })
.references(() => businesses.id),
clientId: d
.text({ length: 255 })
.notNull()
@@ -144,6 +192,7 @@ export const invoices = createTable(
dueDate: d.integer({ mode: "timestamp" }).notNull(),
status: d.text({ length: 50 }).notNull().default("draft"), // draft, sent, paid, overdue
totalAmount: d.real().notNull().default(0),
taxRate: d.real().notNull().default(0.00),
notes: d.text({ length: 1000 }),
createdById: d
.text({ length: 255 })
@@ -156,6 +205,7 @@ export const invoices = createTable(
updatedAt: d.integer({ mode: "timestamp" }).$onUpdate(() => new Date()),
}),
(t) => [
index("invoice_business_id_idx").on(t.businessId),
index("invoice_client_id_idx").on(t.clientId),
index("invoice_created_by_idx").on(t.createdById),
index("invoice_number_idx").on(t.invoiceNumber),
@@ -164,6 +214,7 @@ export const invoices = createTable(
);
export const invoicesRelations = relations(invoices, ({ one, many }) => ({
business: one(businesses, { fields: [invoices.businessId], references: [businesses.id] }),
client: one(clients, { fields: [invoices.clientId], references: [clients.id] }),
createdBy: one(users, { fields: [invoices.createdById], references: [users.id] }),
items: many(invoiceItems),
@@ -186,6 +237,7 @@ export const invoiceItems = createTable(
hours: d.real().notNull(),
rate: d.real().notNull(),
amount: d.real().notNull(),
position: d.integer().notNull().default(0), // NEW: position for ordering
createdAt: d
.integer({ mode: "timestamp" })
.default(sql`(unixepoch())`)
@@ -194,6 +246,7 @@ export const invoiceItems = createTable(
(t) => [
index("invoice_item_invoice_id_idx").on(t.invoiceId),
index("invoice_item_date_idx").on(t.date),
index("invoice_item_position_idx").on(t.position), // NEW: index for position
],
);