Read this when changing the JSON API contract, request authorization, or a React call to `/api/v1`. # API Routes All routes are registered in `src/OpenMind/Api/Api.php`. Responses are JSON with `Cache-Control: no-store`. `CSRF` means `X-CSRF-Token` must equal the token stored in the PHP session. | Method | Path | Handler | Description | Authorization | |---|---|---|---|---| | GET | `/api/v1/auth/session` | `AuthController::session` | Returns authenticated state, safe user DTO, roles, and CSRF token. | Public | | POST | `/api/v1/auth/login` | `AuthController::login` | Validates JSON credentials, regenerates the session ID, stores the user, and returns session state. | Public | | POST | `/api/v1/auth/logout` | `AuthController::logout` | Clears session and returns anonymous state. | CSRF | | GET | `/api/v1/navigation` | `NavigationController::index` | Returns permission-filtered, ordered menu entries. | Authenticated | | GET | `/api/v1/admin/config` | `AdminController::load` | Returns decrypted configuration text. | `admin` | | PUT | `/api/v1/admin/config` | `AdminController::save` | Encrypts and replaces configuration text. | `admin` + CSRF | | GET | `/api/v1/admin/users` | `UserController::index` | Returns safe user DTOs and configured role choices. | `admin` | | POST | `/api/v1/admin/users` | `UserController::create` | Creates a user from username, password, and configured roles. | `admin` + CSRF | | PUT | `/api/v1/admin/users/@id` | `UserController::update` | Updates selected user fields. | `admin` + CSRF | | DELETE | `/api/v1/admin/users/@id` | `UserController::delete` | Deletes an eligible user. | `admin` + CSRF | | GET | `/api/v1/notifications` | `NotificationController::index` | Returns notifications grouped by caption. | Authenticated | | DELETE | `/api/v1/notifications` | `NotificationController::delete` | Clears every notification. | Authenticated + CSRF | | DELETE | `/api/v1/notifications/@code` | `NotificationController::delete` | Deletes notifications matching a non-negative integer code. | Authenticated + CSRF | ## Contract Notes - `Controller::decodeJsonRequest()` accepts only a JSON object; malformed or empty bodies are rejected. - The authentication/session response is the source of the current CSRF token. The client caches it only in memory. - Unauthorized routes return 401; insufficient roles return 403; user-management business conflicts return 409 with a stable `code`. - Route registration is separate from legacy system methods that are not registered in `System::setSystemRoutes()`. See [identity/spec.md](identity/spec.md), [configuration/spec.md](configuration/spec.md), and [rules/add-api-endpoint.md](rules/add-api-endpoint.md).