merge: cherry-pick e1b96310 (security + type-safety + auth middleware) from web-cad

Brings the following 28.06 improvements into web-cad-neu:
- backend/src/auth/authMiddleware.ts: shared requireAuth/requireAdmin middleware
- backend/src/routes/users.ts: admin role checks (critical security fix)
- 6 routes (projects, drawings, elements, layers, blocks, settings): requireAuth
- server.ts: per-route auth (defense-in-depth alongside global hook)
- 6 test files: auth setup + 401 tests
- Frontend: type safety fixes (App.tsx, RenderEngine, SnapEngine, etc.)
- 10 components: SVG stroke-width/linecap/linejoin -> camelCase
- PropertiesPanel: formatPos/formatDim/parseNum helpers
- LayerPanel: aria-labels
- WORKLOG.md: historical worklog from 28.06

Conflicts resolved (4 blocks, all kept HEAD + e1b96310 improvements):
- LayerPanel.tsx: kept HEAD display:flex + e1b96310 aria-label
- PropertiesPanel.tsx: kept HEAD onDelete handler + e1b96310 formatPos helpers
- PropertiesPanel.tsx: kept HEAD delete button (feature) + full inline styles
- Topbar.tsx: kept HEAD onClick + e1b96310 camelCase SVG attrs

Refs: CODE_ANALYSIS.md (Issue #1 partially improved), e1b96310
This commit is contained in:
2026-06-30 11:32:33 +02:00
parent 4b9140a99b
commit 707214447b
35 changed files with 631 additions and 165 deletions
+9 -2
View File
@@ -3,15 +3,19 @@
*/
import type { FastifyInstance } from 'fastify';
import type { DatabaseInterface, DBProject } from '../database/DatabaseInterface.js';
import { requireAuth } from '../auth/authMiddleware.js';
import type { AuthService } from '../auth/AuthService.js';
export function registerProjectRoutes(fastify: FastifyInstance, db: DatabaseInterface) {
export function registerProjectRoutes(fastify: FastifyInstance, db: DatabaseInterface, authService: AuthService) {
// List all projects
fastify.get('/api/projects', async () => {
fastify.get('/api/projects', async (request, reply) => {
if (!requireAuth(request, reply, authService)) return;
return db.listProjects();
});
// Get single project
fastify.get('/api/projects/:id', async (request, reply) => {
if (!requireAuth(request, reply, authService)) return;
const { id } = request.params as { id: string };
const project = db.getProject(id);
if (!project) return reply.code(404).send({ error: 'Project not found' });
@@ -20,6 +24,7 @@ export function registerProjectRoutes(fastify: FastifyInstance, db: DatabaseInte
// Create project
fastify.post('/api/projects', async (request, reply) => {
if (!requireAuth(request, reply, authService)) return;
const body = request.body as Partial<DBProject>;
if (!body.name) return reply.code(400).send({ error: 'Name is required' });
return reply.code(201).send(db.createProject(body));
@@ -27,6 +32,7 @@ export function registerProjectRoutes(fastify: FastifyInstance, db: DatabaseInte
// Update project
fastify.patch('/api/projects/:id', async (request, reply) => {
if (!requireAuth(request, reply, authService)) return;
const { id } = request.params as { id: string };
const body = request.body as Partial<DBProject>;
const updated = db.updateProject(id, body);
@@ -36,6 +42,7 @@ export function registerProjectRoutes(fastify: FastifyInstance, db: DatabaseInte
// Delete project
fastify.delete('/api/projects/:id', async (request, reply) => {
if (!requireAuth(request, reply, authService)) return;
const { id } = request.params as { id: string };
const ok = db.deleteProject(id);
if (!ok) return reply.code(404).send({ error: 'Project not found' });