This document describes the HTTP API exposed by the application using Next.js Route Handlers in the App Router (app/api/*/route.js).
All routes below are served under the /api prefix.
The API expects a valid server configuration.
Required environment variables:
MONGODB_URI — database connection string (used by lib/db.js).SESSION_SECRET — JWT signing secret for session cookies.NAS_ROOT_PATH — NAS mount root for storage operations.Optional environment variables:
SESSION_COOKIE_SECURE — override for the cookie Secure flag (true/false).The environment can be validated via:
lib/config/validateEnv.jsscripts/validate-env.mjsIn Docker/production-like runs, execute node scripts/validate-env.mjs before starting the server to fail fast.
Authentication uses a signed JWT stored in an HTTP-only cookie (auth_session).
To access protected endpoints:
POST /api/auth/login to obtain the cookie.Notes:
Secure and the app should run behind HTTPS.http://localhost:3000), set SESSION_COOKIE_SECURE=false in your local docker env file.RBAC is enforced on filesystem-related endpoints.
All endpoints return JSON.
Error responses use:
{ "error": "Human-readable error message" }
Route handlers use Web Request / Response primitives.
For dynamic routes, Next.js 16 resolves parameters asynchronously via ctx.params.
GET /api/healthPurpose
Health check endpoint:
db.command({ ping: 1 })).NAS_ROOT_PATH.Authentication: not required.
Response 200 (example)
{
"db": "ok",
"nas": {
"path": "/mnt/niederlassungen",
"entriesSample": ["@Recently-Snapshot", "NL01", "NL02"]
}
}
POST /api/auth/loginPurpose
Authenticate a user and set the session cookie.
Authentication: not required.
Request body (JSON)
{ "username": "example.user", "password": "plain-text-password" }
Responses
200 { "ok": true }400 { "error": "Invalid request body" }400 { "error": "Missing username or password" }401 { "error": "Invalid credentials" }500 { "error": "Internal server error" }GET /api/auth/logoutPurpose
Destroy the current session by clearing the cookie.
Authentication: recommended (but endpoint is idempotent).
Response
200 { "ok": true }GET /api/branchesReturns the list of branches (e.g. ["NL01", "NL02"]).
Authentication: required.
RBAC behavior
branch role → only own branchadmin/dev → all branchesResponse 200
{ "branches": ["NL01", "NL02"] }
GET /api/branches/[branch]/yearsExample: /api/branches/NL01/years
Authentication: required.
Response 200
{ "branch": "NL01", "years": ["2023", "2024"] }
GET /api/branches/[branch]/[year]/monthsExample: /api/branches/NL01/2024/months
Authentication: required.
Response 200
{ "branch": "NL01", "year": "2024", "months": ["01", "02", "10"] }
GET /api/branches/[branch]/[year]/[month]/daysExample: /api/branches/NL01/2024/10/days
Authentication: required.
Response 200
{ "branch": "NL01", "year": "2024", "month": "10", "days": ["01", "23"] }
GET /api/files?branch=&year=&month=&day=Example:
/api/files?branch=NL01&year=2024&month=10&day=23
Authentication: required.
Response 200
{
"branch": "NL01",
"year": "2024",
"month": "10",
"day": "23",
"files": [{ "name": "test.pdf", "relativePath": "NL01/2024/10/23/test.pdf" }]
}
When adding new endpoints:
route.js under app/api/....lib/storage for filesystem access.getSession() + canAccessBranch() as needed).