Initial import: bare-metal stacks, Server UI, GPU fan, tutorials.

Infrastructure configs for GMKtec K11 (Docker, vLLM, LocalAI, ComfyUI,
control-plane, gpu-fan agent, Server UI with CLI/file explorer/GPU fan curve).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
tomasz-syn-grzegorza
2026-07-05 12:02:04 +00:00
commit 359afb3a59
153 changed files with 18169 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
# Server UI — File Explorer
**Data:** 2026-07-05
**Status:** wdrożone
Zakładka **Pliki** w panelu Server UI (`:8091`) — przeglądanie systemu plików, edycja tekstu, pełny CRUD.
## UI
- Zakładka **Pliki** (druga, po CLI)
- Hash URL: `http://<host>:8091/#files`
- Wymaga `X-API-Key` (ten sam co reszta panelu przy bind LAN)
## API
Wszystkie endpointy: nagłówek `X-API-Key` (gdy `API_KEY` ustawiony i bind LAN).
| Metoda | Ścieżka | Opis |
|--------|---------|------|
| GET | `/api/files?path=/` | Lista katalogu |
| GET | `/api/files/read?path=...` | Odczyt pliku (UTF-8 lub base64 dla binarnych) |
| PUT | `/api/files/write` | `{"path","content"}` — zapis tekstu |
| POST | `/api/files/mkdir` | `{"path"}` — nowy folder |
| POST | `/api/files/rename` | `{"old_path","new_path"}` |
| DELETE | `/api/files?path=...` | Usuń plik lub pusty katalog |
### Przykłady curl
```bash
API_KEY=$(sudo grep ^API_KEY= /opt/control-plane/.env | cut -d= -f2)
curl -s "http://127.0.0.1:8091/api/files?path=/tmp" \
-H "X-API-Key: ${API_KEY}"
curl -s "http://127.0.0.1:8091/api/files/read?path=/tmp/test.txt" \
-H "X-API-Key: ${API_KEY}"
curl -s -X PUT "http://127.0.0.1:8091/api/files/write" \
-H "X-API-Key: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{"path":"/tmp/test.txt","content":"hello"}'
```
## Konfiguracja
W [`/opt/control-plane/.env`](/opt/control-plane/.env) (opcjonalnie):
| Zmienna | Domyślnie | Opis |
|---------|-----------|------|
| `FILE_EXPLORER_ROOT` | `/` | Korzeń przeglądania |
| `FILE_EXPLORER_MAX_BYTES` | `2097152` | Limit odczytu/zapisu (2 MiB) |
## Uprawnienia POSIX
Server UI działa jako użytkownik **`tomasz-syn-grzegorza`** (`server-ui.service`). Explorer **nie omija** uprawnień systemowych:
- `/home/...`, repo, `/data/apps/...` — zwykle OK
- `/opt/control-plane/.env` (root 600) — odmowa w UI
- pliki root-only — komunikat „Brak uprawnień”
## Kod
| Plik | Rola |
|------|------|
| [`stacks/server-ui/file_explorer.py`](../stacks/server-ui/file_explorer.py) | Logika FS |
| [`stacks/server-ui/app.py`](../stacks/server-ui/app.py) | Endpointy `/api/files*` |
| [`stacks/server-ui/static/index.html`](../stacks/server-ui/static/index.html) | Zakładka Pliki |
## Bezpieczeństwo
- Path traversal: `Path.resolve()` + sprawdzenie względem `FILE_EXPLORER_ROOT`
- Pliki binarne: podgląd base64, zapis zablokowany (415)
- Usuwanie: potwierdzenie w UI (`confirm()`)
- Katalog niepusty: 409 przy DELETE
## Deploy
```bash
sudo bash stacks/server-ui/scripts/install.sh
# lub tylko restart po rsync:
sudo systemctl restart server-ui
```
Tutorial użytkownika: [`manual-tutorial/09-file-explorer.md`](../manual-tutorial/09-file-explorer.md)