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

@@ -23,7 +23,7 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const ticket = await RepairTicketService.create(app.db, request.companyId, parsed.data)
const ticket = await RepairTicketService.create(app.db, parsed.data)
return reply.status(201).send(ticket)
})
@@ -44,13 +44,13 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
completedDateTo: query.completedDateTo,
}
const result = await RepairTicketService.list(app.db, request.companyId, params, filters)
const result = await RepairTicketService.list(app.db, params, filters)
return reply.send(result)
})
app.get('/repair-tickets/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
const { id } = request.params as { id: string }
const ticket = await RepairTicketService.getById(app.db, request.companyId, id)
const ticket = await RepairTicketService.getById(app.db, id)
if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })
return reply.send(ticket)
})
@@ -61,7 +61,7 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const ticket = await RepairTicketService.update(app.db, request.companyId, id, parsed.data)
const ticket = await RepairTicketService.update(app.db, id, parsed.data)
if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })
return reply.send(ticket)
})
@@ -72,14 +72,14 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const ticket = await RepairTicketService.updateStatus(app.db, request.companyId, id, parsed.data.status)
const ticket = await RepairTicketService.updateStatus(app.db, id, parsed.data.status)
if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })
return reply.send(ticket)
})
app.delete('/repair-tickets/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
const { id } = request.params as { id: string }
const ticket = await RepairTicketService.delete(app.db, request.companyId, id)
const ticket = await RepairTicketService.delete(app.db, id)
if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })
return reply.send(ticket)
})
@@ -109,14 +109,14 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const item = await RepairLineItemService.update(app.db, request.companyId, id, parsed.data)
const item = await RepairLineItemService.update(app.db, id, parsed.data)
if (!item) return reply.status(404).send({ error: { message: 'Line item not found', statusCode: 404 } })
return reply.send(item)
})
app.delete('/repair-line-items/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
const { id } = request.params as { id: string }
const item = await RepairLineItemService.delete(app.db, request.companyId, id)
const item = await RepairLineItemService.delete(app.db, id)
if (!item) return reply.status(404).send({ error: { message: 'Line item not found', statusCode: 404 } })
return reply.send(item)
})
@@ -128,19 +128,19 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const batch = await RepairBatchService.create(app.db, request.companyId, parsed.data)
const batch = await RepairBatchService.create(app.db, parsed.data)
return reply.status(201).send(batch)
})
app.get('/repair-batches', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
const params = PaginationSchema.parse(request.query)
const result = await RepairBatchService.list(app.db, request.companyId, params)
const result = await RepairBatchService.list(app.db, params)
return reply.send(result)
})
app.get('/repair-batches/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
const { id } = request.params as { id: string }
const batch = await RepairBatchService.getById(app.db, request.companyId, id)
const batch = await RepairBatchService.getById(app.db, id)
if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
return reply.send(batch)
})
@@ -151,7 +151,7 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const batch = await RepairBatchService.update(app.db, request.companyId, id, parsed.data)
const batch = await RepairBatchService.update(app.db, id, parsed.data)
if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
return reply.send(batch)
})
@@ -162,21 +162,21 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const batch = await RepairBatchService.updateStatus(app.db, request.companyId, id, parsed.data.status)
const batch = await RepairBatchService.updateStatus(app.db, id, parsed.data.status)
if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
return reply.send(batch)
})
app.post('/repair-batches/:id/approve', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
const { id } = request.params as { id: string }
const batch = await RepairBatchService.approve(app.db, request.companyId, id, request.user.id)
const batch = await RepairBatchService.approve(app.db, id, request.user.id)
if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
return reply.send(batch)
})
app.post('/repair-batches/:id/reject', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
const { id } = request.params as { id: string }
const batch = await RepairBatchService.reject(app.db, request.companyId, id)
const batch = await RepairBatchService.reject(app.db, id)
if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
return reply.send(batch)
})
@@ -184,7 +184,7 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
app.get('/repair-batches/:batchId/tickets', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
const { batchId } = request.params as { batchId: string }
const params = PaginationSchema.parse(request.query)
const result = await RepairTicketService.listByBatch(app.db, request.companyId, batchId, params)
const result = await RepairTicketService.listByBatch(app.db, batchId, params)
return reply.send(result)
})
@@ -196,7 +196,7 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const ticket = await RepairTicketService.getById(app.db, request.companyId, ticketId)
const ticket = await RepairTicketService.getById(app.db, ticketId)
if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })
// Look up author name from users table
@@ -217,7 +217,7 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
app.delete('/repair-notes/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
const { id } = request.params as { id: string }
const note = await RepairNoteService.delete(app.db, request.companyId, id)
const note = await RepairNoteService.delete(app.db, id)
if (!note) return reply.status(404).send({ error: { message: 'Note not found', statusCode: 404 } })
return reply.send(note)
})
@@ -229,13 +229,13 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const template = await RepairServiceTemplateService.create(app.db, request.companyId, parsed.data)
const template = await RepairServiceTemplateService.create(app.db, parsed.data)
return reply.status(201).send(template)
})
app.get('/repair-service-templates', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
const params = PaginationSchema.parse(request.query)
const result = await RepairServiceTemplateService.list(app.db, request.companyId, params)
const result = await RepairServiceTemplateService.list(app.db, params)
return reply.send(result)
})
@@ -245,14 +245,14 @@ export const repairRoutes: FastifyPluginAsync = async (app) => {
if (!parsed.success) {
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
}
const template = await RepairServiceTemplateService.update(app.db, request.companyId, id, parsed.data)
const template = await RepairServiceTemplateService.update(app.db, id, parsed.data)
if (!template) return reply.status(404).send({ error: { message: 'Template not found', statusCode: 404 } })
return reply.send(template)
})
app.delete('/repair-service-templates/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
const { id } = request.params as { id: string }
const template = await RepairServiceTemplateService.delete(app.db, request.companyId, id)
const template = await RepairServiceTemplateService.delete(app.db, id)
if (!template) return reply.status(404).send({ error: { message: 'Template not found', statusCode: 404 } })
return reply.send(template)
})