|
@@ -1,3 +1,13 @@
|
|
|
|
|
+<!-- --------------------------------------------------------------------------- -->
|
|
|
|
|
+
|
|
|
|
|
+<!-- Ordner: Docs -->
|
|
|
|
|
+
|
|
|
|
|
+<!-- Datei: api.md -->
|
|
|
|
|
+
|
|
|
|
|
+<!-- Relativer Pfad: Docs/api.md -->
|
|
|
|
|
+
|
|
|
|
|
+<!-- --------------------------------------------------------------------------- -->
|
|
|
|
|
+
|
|
|
# API Overview
|
|
# 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`).
|
|
This document describes the HTTP API exposed by the application using Next.js **Route Handlers** in the App Router (`app/api/*/route.js`).
|
|
@@ -60,7 +70,7 @@ RBAC is enforced on filesystem-related endpoints.
|
|
|
|
|
|
|
|
### 3.1 Standard error response format
|
|
### 3.1 Standard error response format
|
|
|
|
|
|
|
|
-All endpoints return JSON.
|
|
|
|
|
|
|
+Most endpoints return JSON.
|
|
|
|
|
|
|
|
Success responses keep their existing shapes (**unchanged**).
|
|
Success responses keep their existing shapes (**unchanged**).
|
|
|
|
|
|
|
@@ -82,6 +92,15 @@ Notes:
|
|
|
- `error.code` is a stable machine-readable identifier (frontend handling, tests, monitoring).
|
|
- `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).
|
|
- `error.details` is optional. When present, it must be a JSON object (e.g. validation info).
|
|
|
|
|
|
|
|
|
|
+**Binary endpoints**
|
|
|
|
|
+
|
|
|
|
|
+Some endpoints may return a non-JSON body on the **200** happy path (for example `application/pdf`).
|
|
|
|
|
+
|
|
|
|
|
+Rules for such endpoints:
|
|
|
|
|
+
|
|
|
|
|
+- On success: return the documented binary payload.
|
|
|
|
|
+- On non-200 errors: return the standardized JSON error payload above.
|
|
|
|
|
+
|
|
|
### 3.2 Status code rules
|
|
### 3.2 Status code rules
|
|
|
|
|
|
|
|
The API uses the following status codes consistently:
|
|
The API uses the following status codes consistently:
|
|
@@ -105,11 +124,29 @@ The API uses these machine-readable codes (non-exhaustive list):
|
|
|
- Validation:
|
|
- Validation:
|
|
|
|
|
|
|
|
- `VALIDATION_MISSING_PARAM`
|
|
- `VALIDATION_MISSING_PARAM`
|
|
|
|
|
+
|
|
|
- `VALIDATION_MISSING_QUERY`
|
|
- `VALIDATION_MISSING_QUERY`
|
|
|
|
|
+
|
|
|
- `VALIDATION_INVALID_JSON`
|
|
- `VALIDATION_INVALID_JSON`
|
|
|
|
|
+
|
|
|
- `VALIDATION_INVALID_BODY`
|
|
- `VALIDATION_INVALID_BODY`
|
|
|
|
|
+
|
|
|
- `VALIDATION_MISSING_FIELD`
|
|
- `VALIDATION_MISSING_FIELD`
|
|
|
|
|
|
|
|
|
|
+ - `VALIDATION_BRANCH`
|
|
|
|
|
+
|
|
|
|
|
+ - `VALIDATION_YEAR`
|
|
|
|
|
+
|
|
|
|
|
+ - `VALIDATION_MONTH`
|
|
|
|
|
+
|
|
|
|
|
+ - `VALIDATION_DAY`
|
|
|
|
|
+
|
|
|
|
|
+ - `VALIDATION_FILENAME`
|
|
|
|
|
+
|
|
|
|
|
+ - `VALIDATION_FILE_EXTENSION`
|
|
|
|
|
+
|
|
|
|
|
+ - `VALIDATION_PATH_TRAVERSAL`
|
|
|
|
|
+
|
|
|
- Storage:
|
|
- Storage:
|
|
|
|
|
|
|
|
- `FS_NOT_FOUND`
|
|
- `FS_NOT_FOUND`
|
|
@@ -149,6 +186,10 @@ All JSON API responses explicitly disable HTTP caching:
|
|
|
|
|
|
|
|
This is applied centrally by `lib/api/errors.js` (the `json()` / `jsonError()` helpers). The policy applies to both success and error responses.
|
|
This is applied centrally by `lib/api/errors.js` (the `json()` / `jsonError()` helpers). The policy applies to both success and error responses.
|
|
|
|
|
|
|
|
|
|
+For binary endpoints (e.g. PDF streaming), the route handler must explicitly set:
|
|
|
|
|
+
|
|
|
|
|
+- `Cache-Control: no-store`
|
|
|
|
|
+
|
|
|
#### 3.6.2 Next.js route handler execution
|
|
#### 3.6.2 Next.js route handler execution
|
|
|
|
|
|
|
|
All API route handlers are forced to execute dynamically at request time:
|
|
All API route handlers are forced to execute dynamically at request time:
|
|
@@ -467,6 +508,96 @@ Example:
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
|
|
+### 4.10 `GET /api/files/:branch/:year/:month/:day/:filename`
|
|
|
|
|
+
|
|
|
|
|
+**Purpose**
|
|
|
|
|
+
|
|
|
|
|
+Stream (or download) a single PDF file from the NAS while enforcing authentication and branch-level RBAC.
|
|
|
|
|
+
|
|
|
|
|
+**Authentication**: required.
|
|
|
|
|
+
|
|
|
|
|
+**RBAC behavior**
|
|
|
|
|
+
|
|
|
|
|
+- `401 AUTH_UNAUTHENTICATED` when no valid session exists.
|
|
|
|
|
+- `403 AUTH_FORBIDDEN_BRANCH` when the session is not allowed to access `:branch`.
|
|
|
|
|
+
|
|
|
|
|
+**URL params**
|
|
|
|
|
+
|
|
|
|
|
+- `branch`: `NL` + digits (e.g. `NL01`)
|
|
|
|
|
+- `year`: `YYYY` (4 digits)
|
|
|
|
|
+- `month`: `MM` (`01`–`12`)
|
|
|
|
|
+- `day`: `DD` (`01`–`31`)
|
|
|
|
|
+- `filename`: PDF file name (must be a simple file name; no path segments)
|
|
|
|
|
+
|
|
|
|
|
+**Query params (optional)**
|
|
|
|
|
+
|
|
|
|
|
+- `download=1` or `download=true`
|
|
|
|
|
+
|
|
|
|
|
+ - Forces `Content-Disposition: attachment` (download)
|
|
|
|
|
+ - Default is `inline` (open in browser)
|
|
|
|
|
+
|
|
|
|
|
+**Success response (200)**
|
|
|
|
|
+
|
|
|
|
|
+- Body: raw PDF bytes (not JSON)
|
|
|
|
|
+- Headers (example):
|
|
|
|
|
+
|
|
|
|
|
+ - `Content-Type: application/pdf`
|
|
|
|
|
+ - `Content-Disposition: inline; filename="<filename>"` (or `attachment` when `download=1`)
|
|
|
|
|
+ - `Cache-Control: no-store`
|
|
|
|
|
+
|
|
|
|
|
+**Error responses (JSON)**
|
|
|
|
|
+
|
|
|
|
|
+- `400` validation errors:
|
|
|
|
|
+
|
|
|
|
|
+ - `VALIDATION_MISSING_PARAM`
|
|
|
|
|
+ - `VALIDATION_BRANCH`
|
|
|
|
|
+ - `VALIDATION_YEAR`
|
|
|
|
|
+ - `VALIDATION_MONTH`
|
|
|
|
|
+ - `VALIDATION_DAY`
|
|
|
|
|
+ - `VALIDATION_FILENAME`
|
|
|
|
|
+ - `VALIDATION_FILE_EXTENSION`
|
|
|
|
|
+ - `VALIDATION_PATH_TRAVERSAL`
|
|
|
|
|
+
|
|
|
|
|
+- `401`
|
|
|
|
|
+
|
|
|
|
|
+ ```json
|
|
|
|
|
+ { "error": { "message": "Unauthorized", "code": "AUTH_UNAUTHENTICATED" } }
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+- `403`
|
|
|
|
|
+
|
|
|
|
|
+ ```json
|
|
|
|
|
+ { "error": { "message": "Forbidden", "code": "AUTH_FORBIDDEN_BRANCH" } }
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+- `404` (file not found)
|
|
|
|
|
+
|
|
|
|
|
+ ```json
|
|
|
|
|
+ {
|
|
|
|
|
+ "error": {
|
|
|
|
|
+ "message": "Not found",
|
|
|
|
|
+ "code": "FS_NOT_FOUND",
|
|
|
|
|
+ "details": {
|
|
|
|
|
+ "branch": "NL01",
|
|
|
|
|
+ "year": "2024",
|
|
|
|
|
+ "month": "10",
|
|
|
|
|
+ "day": "23",
|
|
|
|
|
+ "filename": "example.pdf"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+- `500`
|
|
|
|
|
+
|
|
|
|
|
+ ```json
|
|
|
|
|
+ {
|
|
|
|
|
+ "error": { "message": "Internal server error", "code": "FS_STORAGE_ERROR" }
|
|
|
|
|
+ }
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
## 5. API v1 freeze (RHL-008)
|
|
## 5. API v1 freeze (RHL-008)
|
|
|
|
|
|
|
|
The endpoints and response shapes documented here (and in `Docs/frontend-api-usage.md`) are considered **API v1** for the first frontend implementation.
|
|
The endpoints and response shapes documented here (and in `Docs/frontend-api-usage.md`) are considered **API v1** for the first frontend implementation.
|
|
@@ -485,7 +616,7 @@ When adding new endpoints:
|
|
|
|
|
|
|
|
1. Define URL + method.
|
|
1. Define URL + method.
|
|
|
2. Implement a `route.js` under `app/api/...`.
|
|
2. Implement a `route.js` under `app/api/...`.
|
|
|
-3. Use `lib/storage` for filesystem access.
|
|
|
|
|
|
|
+3. Use `lib/storage` for filesystem listing/navigation access.
|
|
|
4. Enforce RBAC (`getSession()` + `canAccessBranch()` as needed).
|
|
4. Enforce RBAC (`getSession()` + `canAccessBranch()` as needed).
|
|
|
5. Use the standardized error contract (prefer `withErrorHandling` + `ApiError` helpers).
|
|
5. Use the standardized error contract (prefer `withErrorHandling` + `ApiError` helpers).
|
|
|
6. Add route tests (Vitest).
|
|
6. Add route tests (Vitest).
|