aboutsummaryrefslogtreecommitdiff
path: root/admin
diff options
context:
space:
mode:
authorUMTS at Teleco <crt@teleco.ch>2026-02-15 15:53:50 +0100
committerUMTS at Teleco <crt@teleco.ch>2026-02-15 15:53:50 +0100
commitfa680b24d1123f9de27fc752943e43c86c692314 (patch)
treee4875712a0f8298819c490dc42e881218a2175bc /admin
JAYSON DERULO
Diffstat (limited to 'admin')
-rw-r--r--admin/README.md11
-rw-r--r--admin/config_preference.md28
-rw-r--r--admin/preferences.md90
-rw-r--r--admin/reload.md82
4 files changed, 211 insertions, 0 deletions
diff --git a/admin/README.md b/admin/README.md
new file mode 100644
index 0000000..2b29885
--- /dev/null
+++ b/admin/README.md
@@ -0,0 +1,11 @@
+# Administration
+
+[back to index](../README.md)
+
+Server management stuff. Config reloading, user preferences and how config priority works. Partially adminier territory.
+
+## Pages
+
+- [Reload](reload.md) `POST /reload` hot reload config and optionally restart the server
+- [Preferences](preferences.md) `POST /preferences` get/set/reset per user settings
+- [Config Preference](config_preference.md) how the server should decide between config files and database settings
diff --git a/admin/config_preference.md b/admin/config_preference.md
new file mode 100644
index 0000000..842b7d5
--- /dev/null
+++ b/admin/config_preference.md
@@ -0,0 +1,28 @@
+# Config Preference
+
+[back to admin](README.md) /// [home](../README.md)
+
+If the server can read none critical settings from two places in addition to the `jde_settings` table in the database something has to win. The `config_preference` setting controls that.
+
+## Config Preference States
+
+### tables (default)
+
+Database always wins. If a value exists in `jde_settings` it overrides whatever the config files say (unless its a criticial setting)
+
+This is the default because you usually want admins to be able to change stuff at runtime via the database without having to edit files and restart.
+
+### local
+
+Config file wins for keys that were **explicitly written** in the config file. If you actually typed `session_timeout_minutes = 120` in your security config then that value sticks regardless of whats in the database.
+
+But for settings you didnt write in the file (or ones that got set as default because empty) the database can still override them.
+
+This is useful when you want your local file to be the source of truth but still allow the database to fill in settings you havent configured locally.
+
+## Notes
+
+- the database is always read regardless of this setting. config_preference only controls who wins when they are fighting and having a hissifit as to who wins.
+- this applies to security settings, permission definitions, group configs etc
+- changing this setting itself requires editing the config file (its not a DB overridable setting, that would be idiotic)
+- after changing settings in the database call some servers might choose not to implement live hot reloading for all settings, use `POST /reload` to apply them
diff --git a/admin/preferences.md b/admin/preferences.md
new file mode 100644
index 0000000..760d4f7
--- /dev/null
+++ b/admin/preferences.md
@@ -0,0 +1,90 @@
+# POST /preferences
+
+[back to admin](README.md) /// [home](../README.md)
+
+Get, set or reset per user preference settings. Preferences should be stored as JSON on the user record and scoped by client type. This way different apps can have their own settings without stepping on each other and becoming horny.
+
+## Request Body
+
+```json
+{
+ "action": "get",
+ "client": "emoegui",
+ "user_id": 123,
+ "type": "normal",
+ "data": {}
+}
+```
+
+| Field | Type | Required | Notes |
+|-----------|---------|----------|---------------------------------------------------------------------------------------------|
+| `action` | string | yes | `get`, `set` or `reset` |
+| `client` | string | yes | client identifier (1 to 128 chars, alphanumeric plus underscores) |
+| `user_id` | integer | no | target user (defaults to yourself). accessing another users prefs requires `read-write-all` |
+| `type` | string | no | scope of the operation (see below) |
+| `data` | object | set only | the settings to write. must be a JSON DERULO object |
+
+## Scoping with type
+
+Preferences are stored in two layers: `global` (shared across all clients) and per client (like `emoegui`, `mobile`, etc). The `type` field controls which scope you operate on.
+
+### For get
+
+| Type | Default | What you get |
+|----------|---------|-----------------------------------------------------------------------|
+| `normal` | yes | global settings merged with client specific (client overrides global) |
+| `client` | | only the client specific settings |
+| `global` | | only the global settings |
+
+### For set
+
+| Type | Default | What happens |
+|----------|---------|---------------------------------------------------|
+| `client` | yes | deep merges `data` into the client specific scope |
+| `global` | | deep merges `data` into the global scope |
+
+Deep merge means nested objects should be recursively merged not replaced. Scalar values are overwritten. so you can update one key deep in a nested object without blowing away the rest.
+
+### For reset
+
+| Type | Default | What happens |
+|----------|---------|------------------------------------------------------|
+| `client` | yes | wipes the client specific scope |
+| `global` | | wipes the global scope |
+| `full` | | nukes ALL preferences (sets the whole thing to NULL) |
+
+## Access Control
+
+Controlled by your groups `user_settings_access` setting:
+
+| Access Level | What you can do |
+|------------------|-----------------------------------------|
+| `read-own-only` | can only GET your own preferences |
+| `read-write-own` | can GET/SET/RESET your own preferences |
+| `read-write-all` | can GET/SET/RESET any users preferences |
+
+Trying to access another users preferences when you only have `read-write-own` should give you a 403. dont be nosy. Long nosed looking ah mf.
+
+## Response
+
+```json
+{
+ "success": true,
+ "preferences": {
+ "theme": "dark",
+ "language": "en"
+ },
+ "request_id": "abc123"
+}
+```
+
+For set and reset the response should still include the current preferences after the operation so the client doesnt have to make a second request.
+
+## Error Responses
+
+| Code | When |
+|------|-----------------------------------------------------------------------------------------------------------|
+| 400 | invalid action, invalid client name, wrong type for the action, missing data for set, data isnt an object |
+| 401 | no token or invalid session |
+| 403 | cant access another users prefs, write not allowed with read only access |
+| 500 | database error |
diff --git a/admin/reload.md b/admin/reload.md
new file mode 100644
index 0000000..5cfc5b9
--- /dev/null
+++ b/admin/reload.md
@@ -0,0 +1,82 @@
+# POST /reload
+
+[back to admin](README.md) /// [home](../README.md)
+
+Hotreload server configuration. Rereads all config files, merges with DB settings, rebuilds the permission system. All without downtime hopefully maybe.
+
+Requires power >= `min_reload_power` (configurable).
+
+## Request Body (optional)
+
+```json
+{
+ "restart": false,
+ "forced": false
+}
+```
+
+| Field | Type | Default | Notes |
+|-----------|---------|---------|------------------------------------------|
+| `restart` | boolean | false | schedule a full server restart (reexec) |
+| `forced` | boolean | false | skip idle wait and restart immediately |
+
+If you send no body at all the server just does a config reload without restarting.
+
+## Why restart?
+
+Some things might be unable to be hot reloaded because theyre baked in the oven at startup such as:
+- rate limiter settings
+- server port
+- database connection settings
+- scheduled queries
+
+For these feel free to do a full restart. A compliant server should reexec itself (same binary, fresh process).
+
+## Restart modes
+
+### Graceful restart (`restart: true, forced: false`)
+
+Schedules a restart that waits for a configurable idle period before actually restarting. If theres user activity the timer should reset so you dont pull the rug from under active users lol.
+
+Response:
+
+```json
+{
+ "success": true,
+ "message": "Configuration reloaded: server will restart after 30s of idle time...",
+ "request_id": "abc123",
+ "restarting": true,
+ "restart_wait_seconds": 30,
+ "note": "Server restart is scheduled to apply heavy config changes (rate limits)."
+}
+```
+
+### Forced restart (`restart: true, forced: true`)
+
+Restarts immediately, server should flush cached sessions to the database if it supports persistant sessions first (with a reasonable timeout so a dead DB doesnt block the restart) then reexec.
+
+Because the server dies before it can send a json derulo response back the client wont really get a response. Just fire and forget, then wait for jsonderulo to come back lol.
+
+Should require higher power than a normal reload (configurable via `min_manual_restart_power`).
+
+### No restart (`restart: false`)
+
+Just reloads config. Fast and safe.
+
+```json
+{
+ "success": true,
+ "message": "Configuration reloaded successfully (TOML + DB merged, RBAC rebuilt)",
+ "request_id": "abc123",
+ "restarting": false,
+ "note": "Rate limiter and scheduled query changes require a restart to take effect."
+}
+```
+
+## Error Responses
+
+| Code | When |
+|------|---------------------------------------------------------|
+| 401 | no token or invalid session |
+| 403 | power level too low (for reload or for restart) |
+| 500 | config reload failed (bad config syntax, DB error, etc) |