api.md 8.0 KB

API Overview

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.


1. Configuration Dependencies

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.js
  • scripts/validate-env.mjs

In Docker/production-like runs, execute node scripts/validate-env.mjs before starting the server to fail fast.


2. Authentication & Authorization

2.1 Sessions

Authentication uses a signed JWT stored in an HTTP-only cookie (auth_session).

To access protected endpoints:

  1. POST /api/auth/login to obtain the cookie.
  2. Send subsequent requests with that cookie.

Notes:

  • In production-like setups, cookies should be Secure and the app should run behind HTTPS.
  • For local HTTP testing (http://localhost:3000), you may set SESSION_COOKIE_SECURE=false in your local docker env file.

2.2 RBAC (Branch-Level)

RBAC is enforced on filesystem-related endpoints.

  • 401 Unauthorized: no valid session
  • 403 Forbidden: session exists but branch access is not allowed

3. Error Handling & Conventions

3.1 Standard error response format

All endpoints return JSON.

Success responses keep their existing shapes (unchanged).

Error responses always use this standardized shape:

{
	"error": {
		"message": "Human readable message",
		"code": "SOME_MACHINE_CODE",
		"details": {}
	}
}

Notes:

  • error.message is intended for humans (UI, logs).
  • error.code is a stable machine-readable identifier (frontend handling, tests, monitoring).
  • error.details is optional. When present, it must be a JSON object (e.g. validation info).

3.2 Status code rules

The API uses the following status codes consistently:

  • 400 — invalid/missing parameters, validation errors
  • 401 — unauthenticated (missing/invalid session) or invalid login credentials
  • 403 — authenticated but not allowed (RBAC / branch mismatch)
  • 404 — resource not found (branch/year/month/day/file does not exist)
  • 500 — unexpected server errors (internal failures)

3.3 Common error codes

The API uses these machine-readable codes (non-exhaustive list):

  • Auth:

    • AUTH_UNAUTHENTICATED
    • AUTH_INVALID_CREDENTIALS
    • AUTH_FORBIDDEN_BRANCH
  • Validation:

    • VALIDATION_MISSING_PARAM
    • VALIDATION_MISSING_QUERY
    • VALIDATION_INVALID_JSON
    • VALIDATION_INVALID_BODY
    • VALIDATION_MISSING_FIELD
  • Storage:

    • FS_NOT_FOUND
    • FS_STORAGE_ERROR
  • Internal:

    • INTERNAL_SERVER_ERROR

3.4 Implementation notes

Route handlers use shared helpers:

  • lib/api/errors.js (standard error payloads + withErrorHandling)
  • lib/api/storageErrors.js (maps filesystem errors like ENOENT to 404 vs 500)

3.5 Testing note

  • For realistic Secure cookie behavior, prefer HTTPS.
  • For local testing on http://localhost, many tools/browsers treat localhost as a special-case “secure context”. Behavior may vary between environments.

4. Endpoints

4.1 GET /api/health

Purpose

Health check endpoint:

  • Verifies database connectivity (db.command({ ping: 1 })).
  • Verifies readability of NAS_ROOT_PATH.

Authentication: not required.

Response 200 (example)

{
	"db": "ok",
	"nas": {
		"path": "/mnt/niederlassungen",
		"entriesSample": ["@Recently-Snapshot", "NL01", "NL02"]
	}
}

4.2 POST /api/auth/login

Purpose

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 (invalid JSON/body)

    {
    	"error": {
    		"message": "Invalid request body",
    		"code": "VALIDATION_INVALID_JSON"
    	}
    }
    
  • 400 (missing username/password)

    {
    	"error": {
    		"message": "Missing username or password",
    		"code": "VALIDATION_MISSING_FIELD",
    		"details": { "fields": ["username", "password"] }
    	}
    }
    
  • 401 (invalid credentials)

    {
    	"error": {
    		"message": "Invalid credentials",
    		"code": "AUTH_INVALID_CREDENTIALS"
    	}
    }
    
  • 500

    {
    	"error": {
    		"message": "Internal server error",
    		"code": "INTERNAL_SERVER_ERROR"
    	}
    }
    

4.3 GET /api/auth/logout

Purpose

Destroy the current session by clearing the cookie.

Authentication: recommended (but endpoint is idempotent).

Response

  • 200 { "ok": true }

Error response (rare)

  • 500

    {
    	"error": {
    		"message": "Internal server error",
    		"code": "INTERNAL_SERVER_ERROR"
    	}
    }
    

4.4 GET /api/branches

Returns the list of branches (e.g. ["NL01", "NL02"]).

Authentication: required.

RBAC behavior

  • branch role → only own branch
  • admin/dev → all branches

Response 200

{ "branches": ["NL01", "NL02"] }

Error responses

  • 401

    { "error": { "message": "Unauthorized", "code": "AUTH_UNAUTHENTICATED" } }
    
  • 500

    {
    	"error": { "message": "Internal server error", "code": "FS_STORAGE_ERROR" }
    }
    

4.5 GET /api/branches/[branch]/years

Example: /api/branches/NL01/years

Authentication: required.

Response 200

{ "branch": "NL01", "years": ["2023", "2024"] }

Error responses (common)

  • 401AUTH_UNAUTHENTICATED
  • 403AUTH_FORBIDDEN_BRANCH
  • 400VALIDATION_MISSING_PARAM
  • 404FS_NOT_FOUND
  • 500FS_STORAGE_ERROR / INTERNAL_SERVER_ERROR

4.6 GET /api/branches/[branch]/[year]/months

Example: /api/branches/NL01/2024/months

Authentication: required.

Response 200

{ "branch": "NL01", "year": "2024", "months": ["01", "02", "10"] }

Error responses (common)

  • 401AUTH_UNAUTHENTICATED
  • 403AUTH_FORBIDDEN_BRANCH
  • 400VALIDATION_MISSING_PARAM
  • 404FS_NOT_FOUND
  • 500FS_STORAGE_ERROR / INTERNAL_SERVER_ERROR

4.7 GET /api/branches/[branch]/[year]/[month]/days

Example: /api/branches/NL01/2024/10/days

Authentication: required.

Response 200

{ "branch": "NL01", "year": "2024", "month": "10", "days": ["01", "23"] }

Error responses (common)

  • 401AUTH_UNAUTHENTICATED
  • 403AUTH_FORBIDDEN_BRANCH
  • 400VALIDATION_MISSING_PARAM
  • 404FS_NOT_FOUND
  • 500FS_STORAGE_ERROR / INTERNAL_SERVER_ERROR

4.8 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" }]
}

Error responses (common)

  • 401AUTH_UNAUTHENTICATED
  • 403AUTH_FORBIDDEN_BRANCH
  • 400VALIDATION_MISSING_QUERY
  • 404FS_NOT_FOUND
  • 500FS_STORAGE_ERROR / INTERNAL_SERVER_ERROR

5. Adding New Endpoints

When adding new endpoints:

  1. Define URL + method.
  2. Implement a route.js under app/api/....
  3. Use lib/storage for filesystem access.
  4. Enforce RBAC (getSession() + canAccessBranch() as needed).
  5. Use the standardized error contract (prefer withErrorHandling + ApiError helpers).
  6. Add route tests (Vitest).
  7. Update this document.