Remove multi-tenant company_id scoping from entire codebase

Drop company_id column from all 22 domain tables via migration.
Remove companyId from JWT payload, auth plugins, all service method
signatures (~215 occurrences), all route handlers (~105 occurrences),
test runner, test suites, and frontend auth store/types.

The company table stays as store settings (name, timezone). Tenant
isolation in a SaaS deployment would be at the database level (one
DB per customer) not the application level.

All 107 API tests pass. Zero TSC errors across all packages.
This commit is contained in:
Ryan Moon
2026-03-29 14:58:33 -05:00
parent 55f8591cf1
commit d36c6f7135
35 changed files with 353 additions and 511 deletions

View File

@@ -10,16 +10,12 @@ import {
date,
pgEnum,
} from 'drizzle-orm/pg-core'
import { companies } from './stores.js'
export const billingModeEnum = pgEnum('billing_mode', ['consolidated', 'split'])
export const taxExemptStatusEnum = pgEnum('tax_exempt_status', ['none', 'pending', 'approved'])
export const accounts = pgTable('account', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
accountNumber: varchar('account_number', { length: 50 }),
name: varchar('name', { length: 255 }).notNull(),
email: varchar('email', { length: 255 }),
@@ -46,9 +42,6 @@ export const members = pgTable('member', {
accountId: uuid('account_id')
.notNull()
.references(() => accounts.id),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
memberNumber: varchar('member_number', { length: 50 }),
firstName: varchar('first_name', { length: 100 }).notNull(),
lastName: varchar('last_name', { length: 100 }).notNull(),
@@ -73,9 +66,6 @@ export const memberIdentifiers = pgTable('member_identifier', {
memberId: uuid('member_id')
.notNull()
.references(() => members.id),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
type: varchar('type', { length: 50 }).notNull(),
label: varchar('label', { length: 100 }),
value: varchar('value', { length: 255 }).notNull(),
@@ -100,9 +90,6 @@ export const accountProcessorLinks = pgTable('account_processor_link', {
accountId: uuid('account_id')
.notNull()
.references(() => accounts.id),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
processor: processorEnum('processor').notNull(),
processorCustomerId: varchar('processor_customer_id', { length: 255 }).notNull(),
isActive: boolean('is_active').notNull().default(true),
@@ -117,9 +104,6 @@ export const accountPaymentMethods = pgTable('account_payment_method', {
accountId: uuid('account_id')
.notNull()
.references(() => accounts.id),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
processor: processorEnum('processor').notNull(),
processorPaymentMethodId: varchar('processor_payment_method_id', { length: 255 }).notNull(),
cardBrand: varchar('card_brand', { length: 50 }),
@@ -139,9 +123,6 @@ export const taxExemptions = pgTable('tax_exemption', {
accountId: uuid('account_id')
.notNull()
.references(() => accounts.id),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
status: taxExemptStatusEnum('status').notNull().default('pending'),
certificateNumber: varchar('certificate_number', { length: 255 }).notNull(),
certificateType: varchar('certificate_type', { length: 100 }),

View File

@@ -1,11 +1,7 @@
import { pgTable, uuid, varchar, integer, timestamp } from 'drizzle-orm/pg-core'
import { companies } from './stores.js'
export const files = pgTable('file', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
path: varchar('path', { length: 1000 }).notNull(),
filename: varchar('filename', { length: 255 }).notNull(),
contentType: varchar('content_type', { length: 100 }).notNull(),

View File

@@ -9,13 +9,10 @@ import {
numeric,
date,
} from 'drizzle-orm/pg-core'
import { companies, locations } from './stores.js'
import { locations } from './stores.js'
export const categories = pgTable('category', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
parentId: uuid('parent_id'),
name: varchar('name', { length: 255 }).notNull(),
description: text('description'),
@@ -27,9 +24,6 @@ export const categories = pgTable('category', {
export const suppliers = pgTable('supplier', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
name: varchar('name', { length: 255 }).notNull(),
contactName: varchar('contact_name', { length: 255 }),
email: varchar('email', { length: 255 }),
@@ -49,9 +43,6 @@ export const suppliers = pgTable('supplier', {
export const products = pgTable('product', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
locationId: uuid('location_id').references(() => locations.id),
sku: varchar('sku', { length: 100 }),
upc: varchar('upc', { length: 100 }),
@@ -79,9 +70,6 @@ export const inventoryUnits = pgTable('inventory_unit', {
productId: uuid('product_id')
.notNull()
.references(() => products.id),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
locationId: uuid('location_id').references(() => locations.id),
serialNumber: varchar('serial_number', { length: 255 }),
condition: varchar('condition', { length: 100 }).notNull().default('new'),
@@ -112,9 +100,6 @@ export type Supplier = typeof suppliers.$inferSelect
export type SupplierInsert = typeof suppliers.$inferInsert
export const stockReceipts = pgTable('stock_receipt', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
locationId: uuid('location_id').references(() => locations.id),
productId: uuid('product_id')
.notNull()
@@ -136,9 +121,6 @@ export const priceHistory = pgTable('price_history', {
productId: uuid('product_id')
.notNull()
.references(() => products.id),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
previousPrice: numeric('previous_price', { precision: 10, scale: 2 }),
newPrice: numeric('new_price', { precision: 10, scale: 2 }).notNull(),
previousMinPrice: numeric('previous_min_price', { precision: 10, scale: 2 }),
@@ -158,9 +140,6 @@ export const consignmentDetails = pgTable('consignment_detail', {
productId: uuid('product_id')
.notNull()
.references(() => products.id),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
consignorAccountId: uuid('consignor_account_id').notNull(),
commissionPercent: numeric('commission_percent', { precision: 5, scale: 2 }).notNull(),
minPrice: numeric('min_price', { precision: 10, scale: 2 }),

View File

@@ -1,5 +1,4 @@
import { pgTable, uuid, varchar, text, timestamp, boolean, integer } from 'drizzle-orm/pg-core'
import { companies } from './stores.js'
/**
* Lookup tables replace hard-coded pgEnums for values that stores may want to customize.
@@ -9,9 +8,6 @@ import { companies } from './stores.js'
export const inventoryUnitStatuses = pgTable('inventory_unit_status', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
name: varchar('name', { length: 100 }).notNull(),
slug: varchar('slug', { length: 100 }).notNull(),
description: text('description'),
@@ -23,9 +19,6 @@ export const inventoryUnitStatuses = pgTable('inventory_unit_status', {
export const itemConditions = pgTable('item_condition', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
name: varchar('name', { length: 100 }).notNull(),
slug: varchar('slug', { length: 100 }).notNull(),
description: text('description'),

View File

@@ -1,5 +1,4 @@
import { pgTable, uuid, varchar, text, timestamp, boolean, uniqueIndex } from 'drizzle-orm/pg-core'
import { companies } from './stores.js'
import { users } from './users.js'
export const permissions = pgTable('permission', {
@@ -13,9 +12,6 @@ export const permissions = pgTable('permission', {
export const roles = pgTable('role', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
name: varchar('name', { length: 100 }).notNull(),
slug: varchar('slug', { length: 100 }).notNull(),
description: text('description'),

View File

@@ -9,7 +9,7 @@ import {
numeric,
pgEnum,
} from 'drizzle-orm/pg-core'
import { companies, locations } from './stores.js'
import { locations } from './stores.js'
import { accounts } from './accounts.js'
import { inventoryUnits, products } from './inventory.js'
import { users } from './users.js'
@@ -66,9 +66,6 @@ export const repairBatchApprovalEnum = pgEnum('repair_batch_approval', [
// Defined before repairTickets because tickets FK to batches
export const repairBatches = pgTable('repair_batch', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
locationId: uuid('location_id').references(() => locations.id),
batchNumber: varchar('batch_number', { length: 50 }),
accountId: uuid('account_id')
@@ -97,9 +94,6 @@ export const repairBatches = pgTable('repair_batch', {
export const repairTickets = pgTable('repair_ticket', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
locationId: uuid('location_id').references(() => locations.id),
repairBatchId: uuid('repair_batch_id').references(() => repairBatches.id),
ticketNumber: varchar('ticket_number', { length: 50 }),
@@ -163,9 +157,6 @@ export type RepairNoteInsert = typeof repairNotes.$inferInsert
export const repairServiceTemplates = pgTable('repair_service_template', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
name: varchar('name', { length: 255 }).notNull(),
instrumentType: varchar('instrument_type', { length: 100 }),
size: varchar('size', { length: 50 }),

View File

@@ -1,5 +1,4 @@
import { pgTable, uuid, varchar, timestamp, pgEnum, uniqueIndex, boolean } from 'drizzle-orm/pg-core'
import { companies } from './stores.js'
export const userRoleEnum = pgEnum('user_role', [
'admin',
@@ -11,9 +10,6 @@ export const userRoleEnum = pgEnum('user_role', [
export const users = pgTable('user', {
id: uuid('id').primaryKey().defaultRandom(),
companyId: uuid('company_id')
.notNull()
.references(() => companies.id),
email: varchar('email', { length: 255 }).notNull().unique(),
passwordHash: varchar('password_hash', { length: 255 }).notNull(),
firstName: varchar('first_name', { length: 100 }).notNull(),