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:
@@ -1,5 +1,5 @@
|
||||
import type { FastifyPluginAsync } from 'fastify'
|
||||
import { eq, and, count, sql, type Column } from 'drizzle-orm'
|
||||
import { eq, count, sql, type Column } from 'drizzle-orm'
|
||||
import { PaginationSchema } from '@forte/shared/schemas'
|
||||
import { RbacService } from '../../services/rbac.service.js'
|
||||
import { ValidationError } from '../../lib/errors.js'
|
||||
@@ -12,13 +12,12 @@ export const rbacRoutes: FastifyPluginAsync = async (app) => {
|
||||
|
||||
app.get('/users', { preHandler: [app.authenticate, app.requirePermission('users.view')] }, async (request, reply) => {
|
||||
const params = PaginationSchema.parse(request.query)
|
||||
const baseWhere = eq(users.companyId, request.companyId)
|
||||
|
||||
const searchCondition = params.q
|
||||
? buildSearchCondition(params.q, [users.firstName, users.lastName, users.email])
|
||||
: undefined
|
||||
|
||||
const where = searchCondition ? and(baseWhere, searchCondition) : baseWhere
|
||||
const where = searchCondition ?? undefined
|
||||
|
||||
const sortableColumns: Record<string, Column> = {
|
||||
name: users.lastName,
|
||||
@@ -96,7 +95,7 @@ export const rbacRoutes: FastifyPluginAsync = async (app) => {
|
||||
const [updated] = await app.db
|
||||
.update(users)
|
||||
.set({ isActive, updatedAt: new Date() })
|
||||
.where(and(eq(users.id, userId), eq(users.companyId, request.companyId)))
|
||||
.where(eq(users.id, userId))
|
||||
.returning({ id: users.id, isActive: users.isActive })
|
||||
|
||||
if (!updated) return reply.status(404).send({ error: { message: 'User not found', statusCode: 404 } })
|
||||
@@ -116,7 +115,7 @@ export const rbacRoutes: FastifyPluginAsync = async (app) => {
|
||||
|
||||
app.get('/roles', { preHandler: [app.authenticate, app.requirePermission('users.view')] }, async (request, reply) => {
|
||||
const params = PaginationSchema.parse(request.query)
|
||||
const result = await RbacService.listRoles(app.db, request.companyId, params)
|
||||
const result = await RbacService.listRoles(app.db, params)
|
||||
return reply.send(result)
|
||||
})
|
||||
|
||||
@@ -125,14 +124,14 @@ export const rbacRoutes: FastifyPluginAsync = async (app) => {
|
||||
const data = await app.db
|
||||
.select()
|
||||
.from(roles)
|
||||
.where(and(eq(roles.companyId, request.companyId), eq(roles.isActive, true)))
|
||||
.where(eq(roles.isActive, true))
|
||||
.orderBy(roles.name)
|
||||
return reply.send({ data })
|
||||
})
|
||||
|
||||
app.get('/roles/:id', { preHandler: [app.authenticate, app.requirePermission('users.view')] }, async (request, reply) => {
|
||||
const { id } = request.params as { id: string }
|
||||
const role = await RbacService.getRoleWithPermissions(app.db, request.companyId, id)
|
||||
const role = await RbacService.getRoleWithPermissions(app.db, id)
|
||||
if (!role) return reply.status(404).send({ error: { message: 'Role not found', statusCode: 404 } })
|
||||
return reply.send(role)
|
||||
})
|
||||
@@ -153,7 +152,7 @@ export const rbacRoutes: FastifyPluginAsync = async (app) => {
|
||||
throw new ValidationError('slug must be lowercase alphanumeric with underscores')
|
||||
}
|
||||
|
||||
const role = await RbacService.createRole(app.db, request.companyId, {
|
||||
const role = await RbacService.createRole(app.db, {
|
||||
name,
|
||||
slug,
|
||||
description,
|
||||
@@ -172,7 +171,7 @@ export const rbacRoutes: FastifyPluginAsync = async (app) => {
|
||||
permissionSlugs?: string[]
|
||||
}
|
||||
|
||||
const role = await RbacService.updateRole(app.db, request.companyId, id, {
|
||||
const role = await RbacService.updateRole(app.db, id, {
|
||||
name,
|
||||
description,
|
||||
permissionSlugs,
|
||||
@@ -185,7 +184,7 @@ export const rbacRoutes: FastifyPluginAsync = async (app) => {
|
||||
|
||||
app.delete('/roles/:id', { preHandler: [app.authenticate, app.requirePermission('users.admin')] }, async (request, reply) => {
|
||||
const { id } = request.params as { id: string }
|
||||
const role = await RbacService.deleteRole(app.db, request.companyId, id)
|
||||
const role = await RbacService.deleteRole(app.db, id)
|
||||
if (!role) return reply.status(404).send({ error: { message: 'Role not found', statusCode: 404 } })
|
||||
request.log.info({ roleId: id, roleName: role.name, userId: request.user.id }, 'Role deleted')
|
||||
return reply.send(role)
|
||||
|
||||
Reference in New Issue
Block a user