First slice of Phase 4 (route extraction). Pulls 8 well-tested, mostly
independent route groups out of index.ts into focused Router files. No
behavior change; every handler body moves verbatim.
New route files under backend/src/routes/:
- meta.ts /api/health, /api/meta (mounted before authGate)
- license.ts /api/license/* + /api/system/update,
exports scheduleLocalUpdate for the fleet route
- permissions.ts /api/permissions/me
- convert.ts POST /api/convert
- alerts.ts /api/alerts/*
- labels.ts /api/labels/* + PUT /api/stacks/:name/labels
(exported as stackLabelsRouter)
- apiTokens.ts /api/api-tokens/*
- auditLog.ts /api/audit-log/*
Shared helper lifts:
- helpers/cacheInvalidation.ts: invalidateNodeCaches()
- middleware/tierGates.ts: requireBody (was inline in index.ts)
- utils/errors.ts: isSqliteUniqueViolation (was inline in index.ts)
- middleware/apiTokenScope.ts: rejectApiTokenScope() helper (new)
- utils/csv.ts: escapeCsvField() (new)
index.ts drops from ~7520 to ~6775 lines and now mounts the routers right
after enforceApiTokenScope. The remote proxy and fleet/auth/webhooks/users
routes remain inline in index.ts pending later Phase 4 slices.
Code review fixes: rejectApiTokenScope helper replaces duplicated
`if (req.apiTokenScope) 403 SCOPE_DENIED` blocks in apiTokens.ts and
license.ts; escapeCsvField replaces the inline CSV escape in auditLog.ts.
* fix(stacks): harden stack management with security fixes, validation alignment, and logging
Validate WebSocket stack names with isValidStackName() to close a
path-traversal gap on the /api/stacks/:stackName/logs WS endpoint.
Align POST /api/stacks to use the canonical validator (allows underscores).
Replace error: any catch blocks with error: unknown + type narrowing.
Add cache invalidation to PUT /api/stacks/:stackName/env.
Rename DELETE param from :name to :stackName for consistency.
Add standard [Stacks] lifecycle logs and diagnostic [Stacks:debug] logs
gated behind the Developer Mode toggle (with 5s TTL cache).
Extract shared isDebugEnabled() and getErrorMessage() utilities.
Frontend: roll back optimistic status on API failure, guard unsaved
changes when switching stacks, pre-check duplicate names in App Store.
* docs(settings): update Developer Mode description to mention debug diagnostics