seahaven-ap/packages/api/src/db/seed.ts
Adam Moussa 9d3646876e
feat(api): stand up Hono Drizzle foundation with auth and Redocly (AP-14) (#12)
* feat(api): stand up Hono Drizzle foundation with auth and Redocly

* fix(api): bump drizzle-orm and hono node-server past audit highs

* fix(api): harden auth upsert and Cognito token verification
2026-08-11 00:10:49 +00:00

161 lines
4.1 KiB
TypeScript

import { faker } from "@faker-js/faker";
import { closeDb, createDb } from "./client.js";
import { loadEnv, USER_ROLES, type UserRole } from "../env.js";
import {
activityLog,
approvalPolicies,
approvalSteps,
departments,
documents,
glAccounts,
invoiceComments,
invoiceLines,
invoices,
payRuns,
payments,
users,
vendors,
} from "./schema/index.js";
/** Stable UUIDs so re-seeds and docs stay deterministic. */
const IDS = {
users: {
admin: "11111111-1111-4111-8111-111111111111",
ap_processor: "22222222-2222-4222-8222-222222222222",
approver: "33333333-3333-4333-8333-333333333333",
viewer: "44444444-4444-4444-8444-444444444444",
} satisfies Record<UserRole, string>,
vendor: "55555555-5555-4555-8555-555555555555",
gl: "66666666-6666-4666-8666-666666666666",
department: "77777777-7777-4777-8777-777777777777",
invoice: "88888888-8888-4888-8888-888888888888",
line: "99999999-9999-4999-8999-999999999999",
comment: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
activity: "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
policy: "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
document: "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
} as const;
const ROLE_EMAIL: Record<UserRole, string> = {
admin: "admin@seahavenind.com",
ap_processor: "ap.processor@seahavenind.com",
approver: "approver@seahavenind.com",
viewer: "viewer@seahavenind.com",
};
export async function seedDatabase(): Promise<void> {
faker.seed(14);
const env = loadEnv({
...process.env,
DEV_AUTH_BYPASS: process.env.DEV_AUTH_BYPASS ?? "true",
});
const handle = createDb(env);
const { db } = handle;
await db.delete(documents);
await db.delete(activityLog);
await db.delete(invoiceComments);
await db.delete(invoiceLines);
await db.delete(approvalSteps);
await db.delete(payments);
await db.delete(payRuns);
await db.delete(invoices);
await db.delete(approvalPolicies);
await db.delete(departments);
await db.delete(glAccounts);
await db.delete(vendors);
await db.delete(users);
await db.insert(users).values(
USER_ROLES.map((role) => ({
id: IDS.users[role],
cognitoSub: `seed-sub-${role}`,
email: ROLE_EMAIL[role],
name: faker.person.fullName(),
role,
})),
);
await db.insert(vendors).values({
id: IDS.vendor,
name: "Acme Facilities Supply",
email: "billing@acmefacilities.example",
defaultPaymentMethod: "check",
});
await db.insert(glAccounts).values({
id: IDS.gl,
code: "6100",
name: "Facilities Expense",
});
await db.insert(departments).values({
id: IDS.department,
code: "OPS",
name: "Operations",
});
await db.insert(approvalPolicies).values({
id: IDS.policy,
name: "Default approver policy",
priority: 10,
amountThreshold: "0.00",
skipBelowAmount: "25.00",
active: true,
});
await db.insert(invoices).values({
id: IDS.invoice,
vendorId: IDS.vendor,
invoiceNumber: "INV-1001",
amount: "1250.00",
amountDue: "1250.00",
dueDate: "2026-09-01",
payDate: null,
sendPaymentOn: null,
status: "pending_approval",
paymentMethod: "check",
memo: "Seed invoice for local smoke.",
});
await db.insert(invoiceLines).values({
id: IDS.line,
invoiceId: IDS.invoice,
description: "Monthly maintenance",
amount: "1250.00",
glAccountId: IDS.gl,
departmentId: IDS.department,
});
await db.insert(invoiceComments).values({
id: IDS.comment,
invoiceId: IDS.invoice,
authorUserId: IDS.users.ap_processor,
body: "Seed comment on INV-1001.",
});
await db.insert(activityLog).values({
id: IDS.activity,
invoiceId: IDS.invoice,
actorUserId: IDS.users.ap_processor,
message: "Invoice created from seed.",
});
await db.insert(documents).values({
id: IDS.document,
invoiceId: IDS.invoice,
objectKey: "seed/inv-1001.pdf",
contentType: "application/pdf",
fileName: "inv-1001.pdf",
uploadedByUserId: IDS.users.ap_processor,
});
await closeDb(handle);
console.log("Seed applied (faker seed=14).");
}
seedDatabase().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});