Add read-only Noya admin panel with assignments and UX polish.

Ship admin auth, user overview, assessments, chats, assignment filters/export, security hardening, and a separate desktop admin shell with clearer assessment answers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ar.badiei
2026-09-21 08:00:24 +03:30
co-authored by Cursor
parent 8016b8f45e
commit c6243caa35
104 changed files with 15654 additions and 415 deletions
+20
View File
@@ -14,6 +14,9 @@ import {
toPublicUser,
} from './auth.service.js';
import { prisma } from '../../lib/prisma.js';
import { AUDIT_ACTIONS } from '../admin/auditActions.js';
import { recordAuditBestEffort } from '../admin/audit.service.js';
import { UserRole } from '@prisma/client';
const authAbuseLimiter = rateLimiter({
windowMs: env.RATE_LIMIT_WINDOW_MS,
@@ -49,6 +52,22 @@ export function createAuthRoutes() {
routes.post('/login', authAbuseLimiter, jsonValidator(loginSchema), async (c) => {
const { email, password } = c.req.valid('json');
const result = await login(email, password);
if (result.user.role === UserRole.admin) {
const user = await prisma.user.findUnique({
where: { externalId: result.user.id },
select: { id: true },
});
await recordAuditBestEffort({
actorUserId: user?.id ?? null,
action: AUDIT_ACTIONS.ADMIN_LOGIN,
metadata: { source: 'password_login' },
ipAddress: getClientIp(c),
userAgent: c.req.header('user-agent') ?? null,
});
}
return success(c, result);
});
@@ -70,6 +89,7 @@ export function createAuthRoutes() {
email: authUser.email,
isGuest: authUser.isGuest,
profileComplete: false,
role: authUser.role,
});
}