Разработка
Шаблон department scope
Новые аутентифицированные маршруты должны применять изоляцию отдела через forUser() из src/lib/department-scope.ts. forDepartment() остаётся как совместимый алиас, но forUser() даёт помощники для разрешений и scope нескольких отделов.
Используйте самый узкий хелпер, подходящий под форму данных:
const scope = forUser(request.user);
// Model has departmentId directly.
await prisma.knowledgeBase.findMany({
where: { ...scope.directWhere() },
});
// Model is scoped through Namespace.
await prisma.agentTask.findMany({
where: { ...scope.nestedWhere('namespace') },
});
Пользователи с global scope получают доступ ко всем отделам. Остальные ограничены рассчитанным scope.deptIds; не позволяйте параметрам запроса departmentId переопределять scope.canSeeDept() или scope.directWhere().
Для raw SQL, где допустим только один department-фильтр, стройте фильтры из scope.departmentId и передавайте значения как параметры Prisma SQL:
const departmentFilter = scope.departmentId
? Prisma.sql`AND kb."departmentId" = ${scope.departmentId}`
: Prisma.empty;
Для multi-department scope используйте scope.deptIds и фильтр IN (...), а не предполагайте, что scope.departmentId задан.
Маршруты также могут читать request.departmentScope, который после аутентификации декорируется через src/plugins/department-scope.ts.
Чеклист маршрута
- Добавьте
fastify.authenticateв каждый закрытый маршрут. - Добавьте RBAC-middleware (например,
requirePermission()) там, где операция меняет привилегированные данные. - Примените
forDepartment()илиrequest.departmentScopeперед запросом данных уровня отдела. - Возвращайте явные ошибки через
sendError(), чтобы в ответах был формат{ error, message, statusCode, details? }. - Добавьте route schemas, чтобы
/docsсоответствовал реальному поведению. - Добавляйте или расширяйте тесты изоляции отдела, когда новый эндпоинт отдаёт данные уровня отдела.
Пайплайн agent tasks
Handlers входящих каналов не должны владеть решениями про RAG, confidence и HITL. Для нового канала:
- распарсить транспортный payload;
- найти или создать пользователя, разговор и входящее сообщение;
- создать
AgentTask; - положить в очередь
agent-tasks; - пробросить outbound-зависимость, чтобы agent executor мог отправлять одобренные или авто-пропущенные ответы.
Agent executor worker владеет шагами inject_profile, rag_search, generate и confidence_check. См. ADR-001.