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.
96 lines
4.7 KiB
TypeScript
96 lines
4.7 KiB
TypeScript
import type { FastifyPluginAsync } from 'fastify'
|
|
import {
|
|
CategoryCreateSchema,
|
|
CategoryUpdateSchema,
|
|
SupplierCreateSchema,
|
|
SupplierUpdateSchema,
|
|
PaginationSchema,
|
|
} from '@forte/shared/schemas'
|
|
import { CategoryService, SupplierService } from '../../services/inventory.service.js'
|
|
|
|
export const inventoryRoutes: FastifyPluginAsync = async (app) => {
|
|
// --- Categories ---
|
|
|
|
app.post('/categories', { preHandler: [app.authenticate, app.requirePermission('inventory.edit')] }, async (request, reply) => {
|
|
const parsed = CategoryCreateSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const category = await CategoryService.create(app.db, parsed.data)
|
|
return reply.status(201).send(category)
|
|
})
|
|
|
|
app.get('/categories', { preHandler: [app.authenticate, app.requirePermission('inventory.view')] }, async (request, reply) => {
|
|
const params = PaginationSchema.parse(request.query)
|
|
const result = await CategoryService.list(app.db, params)
|
|
return reply.send(result)
|
|
})
|
|
|
|
app.get('/categories/:id', { preHandler: [app.authenticate, app.requirePermission('inventory.view')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const category = await CategoryService.getById(app.db, id)
|
|
if (!category) return reply.status(404).send({ error: { message: 'Category not found', statusCode: 404 } })
|
|
return reply.send(category)
|
|
})
|
|
|
|
app.patch('/categories/:id', { preHandler: [app.authenticate, app.requirePermission('inventory.edit')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const parsed = CategoryUpdateSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const category = await CategoryService.update(app.db, id, parsed.data)
|
|
if (!category) return reply.status(404).send({ error: { message: 'Category not found', statusCode: 404 } })
|
|
return reply.send(category)
|
|
})
|
|
|
|
app.delete('/categories/:id', { preHandler: [app.authenticate, app.requirePermission('inventory.admin')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const category = await CategoryService.softDelete(app.db, id)
|
|
if (!category) return reply.status(404).send({ error: { message: 'Category not found', statusCode: 404 } })
|
|
return reply.send(category)
|
|
})
|
|
|
|
// --- Suppliers ---
|
|
|
|
app.post('/suppliers', { preHandler: [app.authenticate, app.requirePermission('inventory.edit')] }, async (request, reply) => {
|
|
const parsed = SupplierCreateSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const supplier = await SupplierService.create(app.db, parsed.data)
|
|
return reply.status(201).send(supplier)
|
|
})
|
|
|
|
app.get('/suppliers', { preHandler: [app.authenticate, app.requirePermission('inventory.view')] }, async (request, reply) => {
|
|
const params = PaginationSchema.parse(request.query)
|
|
const result = await SupplierService.list(app.db, params)
|
|
return reply.send(result)
|
|
})
|
|
|
|
app.get('/suppliers/:id', { preHandler: [app.authenticate, app.requirePermission('inventory.view')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const supplier = await SupplierService.getById(app.db, id)
|
|
if (!supplier) return reply.status(404).send({ error: { message: 'Supplier not found', statusCode: 404 } })
|
|
return reply.send(supplier)
|
|
})
|
|
|
|
app.patch('/suppliers/:id', { preHandler: [app.authenticate, app.requirePermission('inventory.edit')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const parsed = SupplierUpdateSchema.safeParse(request.body)
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
|
|
}
|
|
const supplier = await SupplierService.update(app.db, id, parsed.data)
|
|
if (!supplier) return reply.status(404).send({ error: { message: 'Supplier not found', statusCode: 404 } })
|
|
return reply.send(supplier)
|
|
})
|
|
|
|
app.delete('/suppliers/:id', { preHandler: [app.authenticate, app.requirePermission('inventory.admin')] }, async (request, reply) => {
|
|
const { id } = request.params as { id: string }
|
|
const supplier = await SupplierService.softDelete(app.db, id)
|
|
if (!supplier) return reply.status(404).send({ error: { message: 'Supplier not found', statusCode: 404 } })
|
|
return reply.send(supplier)
|
|
})
|
|
}
|