Fix dev seed for single-company schema, sync RBAC on startup
- Remove all company_id references from dev-seed.ts (removed in 0021) - seedPermissions now syncs role-permission assignments for system roles when new permissions are added (e.g., vault.view assigned to admin) - Fix enum migration: use text cast workaround for PostgreSQL's "unsafe use of new enum value" error on fresh DB creation
This commit is contained in:
@@ -18,7 +18,7 @@ async function seed() {
|
||||
const [company] = await sql`SELECT id FROM company WHERE id = ${COMPANY_ID}`
|
||||
if (!company) {
|
||||
await sql`INSERT INTO company (id, name, timezone) VALUES (${COMPANY_ID}, 'Forte Music Store', 'America/Chicago')`
|
||||
await sql`INSERT INTO location (id, company_id, name) VALUES ('a0000000-0000-0000-0000-000000000002', ${COMPANY_ID}, 'Main Store')`
|
||||
await sql`INSERT INTO location (id, name) VALUES ('a0000000-0000-0000-0000-000000000002', 'Main Store')`
|
||||
console.log(' Created company and location')
|
||||
|
||||
// Seed RBAC
|
||||
@@ -29,7 +29,7 @@ async function seed() {
|
||||
const permRows = await sql`SELECT id, slug FROM permission`
|
||||
const permMap = new Map(permRows.map((r: any) => [r.slug, r.id]))
|
||||
for (const roleDef of DEFAULT_ROLES) {
|
||||
const [role] = await sql`INSERT INTO role (company_id, name, slug, description, is_system) VALUES (${COMPANY_ID}, ${roleDef.name}, ${roleDef.slug}, ${roleDef.description}, true) RETURNING id`
|
||||
const [role] = await sql`INSERT INTO role (name, slug, description, is_system) VALUES (${roleDef.name}, ${roleDef.slug}, ${roleDef.description}, true) RETURNING id`
|
||||
for (const permSlug of roleDef.permissions) {
|
||||
const permId = permMap.get(permSlug)
|
||||
if (permId) await sql`INSERT INTO role_permission (role_id, permission_id) VALUES (${role.id}, ${permId}) ON CONFLICT DO NOTHING`
|
||||
@@ -39,23 +39,18 @@ async function seed() {
|
||||
}
|
||||
|
||||
// --- Admin user (if not exists) ---
|
||||
const [adminUser] = await sql`SELECT id, company_id FROM "user" WHERE email = 'admin@forte.dev'`
|
||||
const [adminUser] = await sql`SELECT id FROM "user" WHERE email = 'admin@forte.dev'`
|
||||
if (!adminUser) {
|
||||
const bcrypt = await import('bcrypt')
|
||||
const hashedPw = await (bcrypt.default || bcrypt).hash('admin1234', 10)
|
||||
const [user] = await sql`INSERT INTO "user" (company_id, email, password_hash, first_name, last_name, role) VALUES (${COMPANY_ID}, 'admin@forte.dev', ${hashedPw}, 'Admin', 'User', 'admin') RETURNING id`
|
||||
const [adminRole] = await sql`SELECT id FROM role WHERE company_id = ${COMPANY_ID} AND slug = 'admin' LIMIT 1`
|
||||
const [user] = await sql`INSERT INTO "user" (email, password_hash, first_name, last_name, role) VALUES ('admin@forte.dev', ${hashedPw}, 'Admin', 'User', 'admin') RETURNING id`
|
||||
const [adminRole] = await sql`SELECT id FROM role WHERE slug = 'admin' LIMIT 1`
|
||||
if (adminRole) {
|
||||
await sql`INSERT INTO user_role_assignment (user_id, role_id) VALUES (${user.id}, ${adminRole.id}) ON CONFLICT DO NOTHING`
|
||||
}
|
||||
console.log(' Created admin user: admin@forte.dev / admin1234')
|
||||
} else {
|
||||
// Ensure admin is in the right company and has the admin role
|
||||
if (adminUser.company_id !== COMPANY_ID) {
|
||||
await sql`UPDATE "user" SET company_id = ${COMPANY_ID} WHERE id = ${adminUser.id}`
|
||||
console.log(' Moved admin user to correct company')
|
||||
}
|
||||
const [adminRole] = await sql`SELECT id FROM role WHERE company_id = ${COMPANY_ID} AND slug = 'admin' LIMIT 1`
|
||||
const [adminRole] = await sql`SELECT id FROM role WHERE slug = 'admin' LIMIT 1`
|
||||
if (adminRole) {
|
||||
await sql`DELETE FROM user_role_assignment WHERE user_id = ${adminUser.id}`
|
||||
await sql`INSERT INTO user_role_assignment (user_id, role_id) VALUES (${adminUser.id}, ${adminRole.id}) ON CONFLICT DO NOTHING`
|
||||
@@ -76,13 +71,13 @@ async function seed() {
|
||||
|
||||
const acctIds: Record<string, string> = {}
|
||||
for (const a of accounts) {
|
||||
const existing = await sql`SELECT id FROM account WHERE company_id = ${COMPANY_ID} AND name = ${a.name}`
|
||||
const existing = await sql`SELECT id FROM account WHERE name = ${a.name}`
|
||||
if (existing.length > 0) {
|
||||
acctIds[a.name] = existing[0].id
|
||||
continue
|
||||
}
|
||||
const num = String(Math.floor(100000 + Math.random() * 900000))
|
||||
const [row] = await sql`INSERT INTO account (company_id, name, email, phone, account_number, billing_mode) VALUES (${COMPANY_ID}, ${a.name}, ${a.email}, ${a.phone}, ${num}, 'consolidated') RETURNING id`
|
||||
const [row] = await sql`INSERT INTO account (name, email, phone, account_number, billing_mode) VALUES (${a.name}, ${a.email}, ${a.phone}, ${num}, 'consolidated') RETURNING id`
|
||||
acctIds[a.name] = row.id
|
||||
console.log(` Account: ${a.name}`)
|
||||
}
|
||||
@@ -101,10 +96,10 @@ async function seed() {
|
||||
|
||||
for (const m of members) {
|
||||
const acctId = acctIds[m.accountName]
|
||||
const existing = await sql`SELECT id FROM member WHERE company_id = ${COMPANY_ID} AND first_name = ${m.firstName} AND last_name = ${m.lastName}`
|
||||
const existing = await sql`SELECT id FROM member WHERE first_name = ${m.firstName} AND last_name = ${m.lastName}`
|
||||
if (existing.length > 0) continue
|
||||
const num = String(Math.floor(100000 + Math.random() * 900000))
|
||||
await sql`INSERT INTO member (company_id, account_id, first_name, last_name, email, member_number, is_minor) VALUES (${COMPANY_ID}, ${acctId}, ${m.firstName}, ${m.lastName}, ${m.email ?? null}, ${num}, ${m.isMinor ?? false})`
|
||||
await sql`INSERT INTO member (account_id, first_name, last_name, email, member_number, is_minor) VALUES (${acctId}, ${m.firstName}, ${m.lastName}, ${m.email ?? null}, ${num}, ${m.isMinor ?? false})`
|
||||
console.log(` Member: ${m.firstName} ${m.lastName}`)
|
||||
}
|
||||
|
||||
@@ -129,9 +124,9 @@ async function seed() {
|
||||
]
|
||||
|
||||
for (const t of templates) {
|
||||
const existing = await sql`SELECT id FROM repair_service_template WHERE company_id = ${COMPANY_ID} AND name = ${t.name} AND COALESCE(instrument_type, '') = ${t.instrumentType ?? ''} AND COALESCE(size, '') = ${t.size ?? ''}`
|
||||
const existing = await sql`SELECT id FROM repair_service_template WHERE name = ${t.name} AND COALESCE(instrument_type, '') = ${t.instrumentType ?? ''} AND COALESCE(size, '') = ${t.size ?? ''}`
|
||||
if (existing.length > 0) continue
|
||||
await sql`INSERT INTO repair_service_template (company_id, name, instrument_type, size, item_type, default_price, default_cost, is_active) VALUES (${COMPANY_ID}, ${t.name}, ${t.instrumentType}, ${t.size}, ${t.itemType}, ${t.price}, ${t.cost}, true)`
|
||||
await sql`INSERT INTO repair_service_template (name, instrument_type, size, item_type, default_price, default_cost, is_active) VALUES (${t.name}, ${t.instrumentType}, ${t.size}, ${t.itemType}, ${t.price}, ${t.cost}, true)`
|
||||
console.log(` Template: ${t.name} ${t.instrumentType ?? ''} ${t.size ?? ''}`)
|
||||
}
|
||||
|
||||
@@ -146,20 +141,20 @@ async function seed() {
|
||||
]
|
||||
|
||||
for (const t of tickets) {
|
||||
const existing = await sql`SELECT id FROM repair_ticket WHERE company_id = ${COMPANY_ID} AND customer_name = ${t.customer} AND problem_description = ${t.problem}`
|
||||
const existing = await sql`SELECT id FROM repair_ticket WHERE customer_name = ${t.customer} AND problem_description = ${t.problem}`
|
||||
if (existing.length > 0) continue
|
||||
const num = String(Math.floor(100000 + Math.random() * 900000))
|
||||
const acctId = acctIds[t.customer] ?? null
|
||||
await sql`INSERT INTO repair_ticket (company_id, ticket_number, customer_name, account_id, instrument_description, serial_number, problem_description, condition_in, status, estimated_cost) VALUES (${COMPANY_ID}, ${num}, ${t.customer}, ${acctId}, ${t.instrument}, ${t.serial}, ${t.problem}, ${t.condition}, ${t.status}, ${t.estimate})`
|
||||
await sql`INSERT INTO repair_ticket (ticket_number, customer_name, account_id, instrument_description, serial_number, problem_description, condition_in, status, estimated_cost) VALUES (${num}, ${t.customer}, ${acctId}, ${t.instrument}, ${t.serial}, ${t.problem}, ${t.condition}, ${t.status}, ${t.estimate})`
|
||||
console.log(` Ticket: ${t.customer} — ${t.instrument} [${t.status}]`)
|
||||
}
|
||||
|
||||
// --- Repair Batch ---
|
||||
const batchExists = await sql`SELECT id FROM repair_batch WHERE company_id = ${COMPANY_ID} AND contact_name = 'Mr. Williams'`
|
||||
const batchExists = await sql`SELECT id FROM repair_batch WHERE contact_name = 'Mr. Williams'`
|
||||
if (batchExists.length === 0) {
|
||||
const batchNum = String(Math.floor(100000 + Math.random() * 900000))
|
||||
const schoolId = acctIds['Lincoln High School']
|
||||
const [batch] = await sql`INSERT INTO repair_batch (company_id, batch_number, account_id, contact_name, contact_phone, contact_email, instrument_count, notes, status) VALUES (${COMPANY_ID}, ${batchNum}, ${schoolId}, 'Mr. Williams', '555-0210', 'williams@lincoln.edu', 5, 'Annual band instrument checkup — 5 instruments', 'intake') RETURNING id`
|
||||
const [batch] = await sql`INSERT INTO repair_batch (batch_number, account_id, contact_name, contact_phone, contact_email, instrument_count, notes, status) VALUES (${batchNum}, ${schoolId}, 'Mr. Williams', '555-0210', 'williams@lincoln.edu', 5, 'Annual band instrument checkup — 5 instruments', 'intake') RETURNING id`
|
||||
|
||||
const batchTickets = [
|
||||
{ instrument: 'Student Flute', problem: 'Pads worn, needs replacement check', condition: 'fair' },
|
||||
@@ -171,7 +166,7 @@ async function seed() {
|
||||
|
||||
for (const bt of batchTickets) {
|
||||
const num = String(Math.floor(100000 + Math.random() * 900000))
|
||||
await sql`INSERT INTO repair_ticket (company_id, ticket_number, customer_name, account_id, repair_batch_id, instrument_description, problem_description, condition_in, status) VALUES (${COMPANY_ID}, ${num}, 'Lincoln High School', ${schoolId}, ${batch.id}, ${bt.instrument}, ${bt.problem}, ${bt.condition}, 'new')`
|
||||
await sql`INSERT INTO repair_ticket (ticket_number, customer_name, account_id, repair_batch_id, instrument_description, problem_description, condition_in, status) VALUES (${num}, 'Lincoln High School', ${schoolId}, ${batch.id}, ${bt.instrument}, ${bt.problem}, ${bt.condition}, 'new')`
|
||||
console.log(` Batch ticket: ${bt.instrument}`)
|
||||
}
|
||||
console.log(` Batch: Lincoln High School — 5 instruments`)
|
||||
|
||||
Reference in New Issue
Block a user