feat(admin): Complete tenant management and module access control system
Major Features: - Tenant management CRUD (list, create, edit, delete, module configuration) - Dynamic module management system (modules table with 8 modules) - Multi-tenant module permission merging (ModuleService) - Module access control middleware (requireModule) - User module permission API (GET /api/v1/auth/me/modules) - Frontend module permission filtering (HomePage + TopNavigation) Module Integration: - RVW module integrated with PromptService (editorial + methodology) - All modules (RVW/PKB/ASL/DC) added authenticate + requireModule middleware - Fixed ReviewTask foreign key constraint (cross-schema issue) - Removed all MOCK_USER_ID, unified to request.user?.userId Prompt Management Enhancements: - Module names displayed in Chinese (RVW -> 智能审稿) - Enhanced version history with view content and rollback features - List page shows both activeVersion and draftVersion columns Database Changes: - Added platform_schema.modules table - Modified tenant_modules table (added index and UUID) - Removed ReviewTask foreign key to public.users (cross-schema fix) - Seeded 8 modules: RVW, PKB, ASL, DC, IIT, AIA, SSA, ST Documentation Updates: - Updated ADMIN module development status - Updated TODO checklist (89% progress) - Updated Prompt management plan (Phase 3.5.5 completed) - Added module authentication specification Files Changed: 80+ Status: All features tested and verified locally Next: User management module development
This commit is contained in:
@@ -28,6 +28,17 @@ import { jobQueue } from '../../../../common/jobs/index.js';
|
||||
import { splitIntoChunks, recommendChunkSize } from '../../../../common/jobs/utils.js';
|
||||
import * as xlsx from 'xlsx';
|
||||
|
||||
/**
|
||||
* 获取用户ID(从JWT Token中获取)
|
||||
*/
|
||||
function getUserId(request: FastifyRequest): string {
|
||||
const userId = (request as any).user?.userId;
|
||||
if (!userId) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
export class ExtractionController {
|
||||
/**
|
||||
* 文件上传
|
||||
@@ -44,7 +55,7 @@ export class ExtractionController {
|
||||
});
|
||||
}
|
||||
|
||||
const userId = (request as any).userId || 'default-user';
|
||||
const userId = getUserId(request);
|
||||
const buffer = await data.toBuffer();
|
||||
const originalFilename = data.filename;
|
||||
const timestamp = Date.now();
|
||||
@@ -105,7 +116,7 @@ export class ExtractionController {
|
||||
}>, reply: FastifyReply) {
|
||||
try {
|
||||
const { fileKey, columnName } = request.body;
|
||||
const userId = (request as any).userId || 'default-user'; // TODO: 从auth middleware获取
|
||||
const userId = getUserId(request); // TODO: 从auth middleware获取
|
||||
|
||||
logger.info('[API] Health check request', { fileKey, columnName, userId });
|
||||
|
||||
@@ -194,7 +205,7 @@ export class ExtractionController {
|
||||
modelA = 'deepseek-v3',
|
||||
modelB = 'qwen-max'
|
||||
} = request.body;
|
||||
const userId = (request as any).userId || 'default-user';
|
||||
const userId = getUserId(request);
|
||||
|
||||
logger.info('[API] Create task request', {
|
||||
userId,
|
||||
|
||||
@@ -7,17 +7,20 @@
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import { extractionController } from '../controllers/ExtractionController.js';
|
||||
import { logger } from '../../../../common/logging/index.js';
|
||||
import { authenticate, requireModule } from '../../../../common/auth/auth.middleware.js';
|
||||
|
||||
export async function registerToolBRoutes(fastify: FastifyInstance) {
|
||||
logger.info('[Routes] Registering DC Tool-B routes');
|
||||
|
||||
// 文件上传
|
||||
fastify.post('/upload', {
|
||||
preHandler: [authenticate, requireModule('DC')],
|
||||
handler: extractionController.uploadFile.bind(extractionController)
|
||||
});
|
||||
|
||||
// 健康检查
|
||||
fastify.post('/health-check', {
|
||||
preHandler: [authenticate, requireModule('DC')],
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
@@ -31,13 +34,14 @@ export async function registerToolBRoutes(fastify: FastifyInstance) {
|
||||
handler: extractionController.healthCheck.bind(extractionController)
|
||||
});
|
||||
|
||||
// 获取模板列表
|
||||
// 获取模板列表(公开API)
|
||||
fastify.get('/templates', {
|
||||
handler: extractionController.getTemplates.bind(extractionController)
|
||||
});
|
||||
|
||||
// 创建提取任务
|
||||
fastify.post('/tasks', {
|
||||
preHandler: [authenticate, requireModule('DC')],
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
@@ -58,6 +62,7 @@ export async function registerToolBRoutes(fastify: FastifyInstance) {
|
||||
|
||||
// 查询任务进度
|
||||
fastify.get('/tasks/:taskId/progress', {
|
||||
preHandler: [authenticate, requireModule('DC')],
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
@@ -72,6 +77,7 @@ export async function registerToolBRoutes(fastify: FastifyInstance) {
|
||||
|
||||
// 获取验证网格数据
|
||||
fastify.get('/tasks/:taskId/items', {
|
||||
preHandler: [authenticate, requireModule('DC')],
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
@@ -94,6 +100,7 @@ export async function registerToolBRoutes(fastify: FastifyInstance) {
|
||||
|
||||
// 裁决冲突
|
||||
fastify.post('/items/:itemId/resolve', {
|
||||
preHandler: [authenticate, requireModule('DC')],
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
@@ -116,6 +123,7 @@ export async function registerToolBRoutes(fastify: FastifyInstance) {
|
||||
|
||||
// 导出结果
|
||||
fastify.get('/tasks/:taskId/export', {
|
||||
preHandler: [authenticate, requireModule('DC')],
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
|
||||
@@ -264,6 +264,8 @@ export const conflictDetectionService = new ConflictDetectionService();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user