diff --git a/CHANGELOG.md b/CHANGELOG.md index 1811ae5..3dae8f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,12 @@ By: Codex (GPT-5) | 15.01.2026 | 📝 Req | ID: Makefile als bevorzugter Einstieg in Doku ergaenzt. By: Codex (GPT-5) | | 15.01.2026 | 🏗️ Planning | ID: US_000043/TASK_000049 Enrollment-Token Script geplant. By: Codex (GPT-5) | | 15.01.2026 | ⚙️ Code | ID: US_000043 Enrollment-Script fuer Update-Service hinzugefuegt. By: Codex (GPT-5) | +| 15.01.2026 | 🏗️ Planning | ID: EPIC_000013/US_000044/TASK_000050-TASK_000051 System Telemetry im Dashboard geplant. By: Codex (GPT-5) | +| 15.01.2026 | 🏗️ Planning | ID: EPIC_000014/US_000045/TASK_000052-TASK_000054 Login-Zeitfenster und Parent-Control Regeln geplant. By: Codex (GPT-5) | +| 15.01.2026 | 🏗️ Planning | ID: US_000045 Kriterien konkretisiert (lokale Zeit, OS-Login, Auto-Reaktivierung). By: Codex (GPT-5) | +| 15.01.2026 | 🏗️ Planning | ID: US_000046/TASK_000055 Update-Service Erreichbarkeit anzeigen. By: Codex (GPT-5) | +| 15.01.2026 | ⚙️ Code | ID: US_000046 Update-Service Statusanzeige implementiert. By: Codex (GPT-5) | +| 15.01.2026 | ⚙️ Code | ID: Makefile restart-Target hinzugefuegt. By: Codex (GPT-5) | --- ## Legende diff --git a/Makefile b/Makefile index 357a10b..7ef2102 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ HEALTH_URL ?= http://$(HOST):$(PORT)/health TOKEN ?= $(shell awk -F= '/^SKD_AUTH_TOKEN=/{print $$2}' $(ENV_FILE) 2>/dev/null) KEEP_INSTALL_DIR ?= 1 -.PHONY: install up down uninstall healthcheck update token +.PHONY: install up down restart uninstall healthcheck update token install: $(SUDO) env SERVICE_NAME=$(SERVICE) SERVICE_USER=$(SERVICE_USER) SERVICE_GROUP=$(SERVICE_GROUP) INSTALL_DIR=$(INSTALL_DIR) ./scripts/install.sh @@ -24,6 +24,9 @@ up: down: $(SUDO) systemctl stop $(SERVICE).service +restart: + $(SUDO) systemctl restart $(SERVICE).service + uninstall: -$(SUDO) systemctl stop $(SERVICE).service -$(SUDO) systemctl disable $(SERVICE).service diff --git a/backend/app.py b/backend/app.py index 3a83e1e..8890d99 100644 --- a/backend/app.py +++ b/backend/app.py @@ -26,6 +26,7 @@ from backend.models import ( UpdateActionResponse, UpdateCheckResponse, UpdateLogEntry, + UpdateServiceStatus, UpdateStatus, UserStatus, ) @@ -314,6 +315,12 @@ def update_logs(settings: Settings = Depends(get_settings), limit: int = 200) -> ) from exc +@app.get("/update/service-status", response_model=UpdateServiceStatus, dependencies=[Depends(get_current_admin)]) +def update_service_status(settings: Settings = Depends(get_settings)) -> UpdateServiceStatus: + data = update.get_service_status(settings) + return UpdateServiceStatus(**data) + + @app.get("/", response_class=HTMLResponse) @app.get("/login", response_class=HTMLResponse) @app.get("/dashboard", response_class=HTMLResponse) diff --git a/backend/models.py b/backend/models.py index cf0de50..2801934 100644 --- a/backend/models.py +++ b/backend/models.py @@ -73,3 +73,11 @@ class UpdateLogEntry(BaseModel): version: Optional[str] = None error: Optional[str] = None device_id: Optional[str] = None + + +class UpdateServiceStatus(BaseModel): + url: str + reachable: bool + status_code: Optional[int] = None + error: Optional[str] = None + checked_url: str diff --git a/backend/templates/index.html b/backend/templates/index.html index 6e286f4..6da5e9b 100644 --- a/backend/templates/index.html +++ b/backend/templates/index.html @@ -414,7 +414,10 @@ statusDiv.innerHTML = '

Lade Update-Status...

'; try { - const data = await api('/update/status'); + const [data, serviceStatus] = await Promise.all([ + api('/update/status'), + api('/update/service-status') + ]); document.querySelector('#metricVersion .value').textContent = data.current_version; document.getElementById('headerVersion').textContent = `v${data.current_version}`; @@ -436,12 +439,24 @@ enrollSection.classList.remove('hidden'); } + const serviceBadge = serviceStatus.reachable + ? ' Online' + : ' Offline'; + const serviceHint = serviceStatus.status_code + ? `HTTP ${serviceStatus.status_code}` + : (serviceStatus.error || 'keine Antwort'); + statusDiv.innerHTML = `
Version
${data.current_version}
+
+
Update-Service
+
${serviceBadge}
+
${serviceStatus.url} (${serviceHint})
+
Registrierung
${enrolledBadge}
diff --git a/backend/update.py b/backend/update.py index eb9acdb..f52c20c 100644 --- a/backend/update.py +++ b/backend/update.py @@ -220,3 +220,35 @@ def get_logs(settings: Settings, limit: int = 200) -> List[Dict[str, Any]]: except json.JSONDecodeError: continue return entries + + +def get_service_status(settings: Settings) -> Dict[str, Any]: + base_url = settings.update_service_url.rstrip("/") + if not base_url: + return { + "url": "", + "reachable": False, + "status_code": None, + "error": "update service url not configured", + "checked_url": "", + } + + check_url = base_url + try: + with httpx.Client(timeout=3.0) as client: + response = client.get(check_url) + return { + "url": base_url, + "reachable": True, + "status_code": response.status_code, + "error": None, + "checked_url": check_url, + } + except Exception as exc: + return { + "url": base_url, + "reachable": False, + "status_code": None, + "error": str(exc), + "checked_url": check_url, + } diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 57d3fc4..53e15df 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -27,6 +27,7 @@ sudo systemctl status skd.service make install make up make down +make restart make update make uninstall ``` diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index e2b1c51..3d42606 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -47,6 +47,7 @@ Hinweis: `jq` ist optional; ohne jq das Token manuell aus der JSON-Antwort lesen make install # Installation (systemd, env, venv) make up # Service starten make down # Service stoppen +make restart # Service neu starten make update # Code-Update (git reset --hard origin/main) make healthcheck TOKEN=... # Healthcheck mit Bearer-Token ``` diff --git a/docs/USAGE.md b/docs/USAGE.md index 273bf56..b8d8600 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -54,6 +54,7 @@ curl -X POST -H "Authorization: Bearer $token" \ ### Update-API (lokal) Alle Update-Endpunkte erfordern Admin-Auth. - `GET /update/status` +- `GET /update/service-status` (zeigt URL und Erreichbarkeit des Update-Services) - `POST /update/enroll` (optional Body: `{ "enroll_token": "..." }`) - `POST /update/check` - `POST /update/apply` (optional Body: `{ "version": "x.y.z" }`) diff --git a/project-management/PROJECT_STATUS.md b/project-management/PROJECT_STATUS.md index 6c32ac7..053614a 100644 --- a/project-management/PROJECT_STATUS.md +++ b/project-management/PROJECT_STATUS.md @@ -22,6 +22,7 @@ Sicheres, remote steuerbares System zum Sperren/Entsperren lokaler Nutzerkonten. | 15.01.2026 | 📝 Req | Doku-Overhaul mit neuer Struktur und Archivierung. | | 15.01.2026 | 📝 Req | Externe Service-Links in der Doku ergaenzt. | | 15.01.2026 | 📝 Req | Makefile als Einstieg in Doku aufgenommen. | +| 15.01.2026 | ⚙️ Code | Makefile restart-Target hinzugefuegt. | ## Epic-Backlog (Uebersicht) ### EPIC_000001: Legacy CLI Account Control (sk.sh) @@ -108,6 +109,8 @@ Sicheres, remote steuerbares System zum Sperren/Entsperren lokaler Nutzerkonten. - [x] TASK_000034: UI rollback action - [x] US_000043: Enrollment-Token per Script abrufen - [x] TASK_000049: Script fuer Enrollment-Flow erstellen +- [x] US_000046: Update-Service Erreichbarkeit anzeigen +- [x] TASK_000055: Endpoint und UI fuer Update-Service Status ### EPIC_000009: Update Webservice (External Team) - [ ] US_000026: Client bezieht Updates (Pull) @@ -138,6 +141,17 @@ Sicheres, remote steuerbares System zum Sperren/Entsperren lokaler Nutzerkonten. - [x] TASK_000047: README und Audience-Split anpassen - [x] TASK_000048: External Dependencies und Audience-Ergaenzungen +### EPIC_000013: System Telemetry im Dashboard +- [ ] US_000044: Systemmetriken im Dashboard anzeigen +- [ ] TASK_000050: Backend-Endpoint fuer Systemmetriken +- [ ] TASK_000051: UI-Kacheln im Dashboard (System Information) + +### EPIC_000014: Login-Zeitfenster und Parent-Control Regeln +- [ ] US_000045: Regeln fuer Login-Zeitfenster definieren und durchsetzen +- [ ] TASK_000052: Regelmodell und Speicherung definieren +- [ ] TASK_000053: Login-Pruefung und Enforcement +- [ ] TASK_000054: Admin-UI fuer Regeln und Scheduler + ## Offene Risiken / Abhaengigkeiten - Betrieb erfordert Root/sudo und lokale System-Tools (notify-send, sound player, uvicorn). - OIDC-Validierung blockiert bis IdP bereit und Service laeuft. diff --git a/project-management/requirements/epics/EPIC_000008.md b/project-management/requirements/epics/EPIC_000008.md index 9d8c136..29768c4 100644 --- a/project-management/requirements/epics/EPIC_000008.md +++ b/project-management/requirements/epics/EPIC_000008.md @@ -45,3 +45,4 @@ Ermoegliche einen robusten Client-Update-Flow mit Verifikation und Rollback. - US_000032: Update-Logs im Web-UI anzeigen - US_000033: Rollback im Web-UI anstossen - US_000043: Enrollment-Token per Script abrufen +- US_000046: Update-Service Erreichbarkeit anzeigen diff --git a/project-management/requirements/epics/EPIC_000013.md b/project-management/requirements/epics/EPIC_000013.md new file mode 100644 index 0000000..6daf771 --- /dev/null +++ b/project-management/requirements/epics/EPIC_000013.md @@ -0,0 +1,38 @@ +ID: EPIC_000013 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# EPIC_000013: System Telemetry im Dashboard + +## Beschreibung +Anzeige von Systemmetriken (CPU, RAM, GPU, Netzwerk) fuer Operatoren im Web-Dashboard. + +## Ziel / Business Value +Schneller Ueberblick ueber Systemzustand und Last ohne externe Tools. + +## Mission Statement +Stelle aktuelle Telemetriedaten im Dashboard bereit, aktualisiert in kurzen Intervallen. + +## Business Value & Metriken +- Operatoren erkennen Engpaesse sofort. +- Erfolgsmetrik: Metriken aktualisieren sich alle 5 Sekunden im UI. + +## In-Scope +- API liefert aktuelle CPU/RAM/GPU/Netzwerkwerte. +- Web-UI zeigt Kacheln in einem "System Information" Container. + +## Out-of-Scope +- Langzeit-Historie oder Trend-Analysen. +- Alerting oder Threshold-Management. + +## High-Level Akzeptanzkriterien +- CPU als Gesamt-% angezeigt. +- RAM: Total und Usage %. +- GPU: VRAM Total und Usage % (falls GPU vorhanden). +- Netzwerk: aktuelle RX/TX in Mbps. + +## Technische Constraints & Risiken +- GPU-Metriken sind hardware-/driver-abhaengig. +- Netzwerkwerte benoetigen Delta-Berechnung ueber Zeitfenster. + +## Zugeordnete User Stories +- US_000044: Systemmetriken im Dashboard anzeigen diff --git a/project-management/requirements/epics/EPIC_000014.md b/project-management/requirements/epics/EPIC_000014.md new file mode 100644 index 0000000..7743a4d --- /dev/null +++ b/project-management/requirements/epics/EPIC_000014.md @@ -0,0 +1,42 @@ +ID: EPIC_000014 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# EPIC_000014: Login-Zeitfenster und Parent-Control Regeln + +## Beschreibung +Admins definieren Zeitfenster pro Nutzer, in denen Login erlaubt ist. Beim Login wird +geprueft, ob der Zeitpunkt erlaubt ist; andernfalls erfolgt Hinweis, Konto wird deaktiviert +und der Rechner heruntergefahren. Beim Systemstart wird geprueft, welche Nutzer sich anmelden duerfen. + +## Ziel / Business Value +Verlaessliche Einhaltung von Nutzungszeiten ohne manuelle Eingriffe. + +## Mission Statement +Stelle regelbasierte Login-Beschraenkungen bereit, die zentral verwaltbar und systemweit +durchsetzbar sind. + +## Business Value & Metriken +- Reduzierte manuelle Sperren. +- Erfolgsmetrik: Verbotene Logins werden zu 100% blockiert. + +## In-Scope +- Regeln pro Nutzer (erlaubte Zeitfenster). +- Automatische Aktivierung/Deaktivierung nach Regeln. +- Durchsetzung bei Login und beim Systemstart. + +## Out-of-Scope +- Historische Reports oder Nutzungsstatistiken. +- MFA oder externe Auth-Systeme. + +## High-Level Akzeptanzkriterien +- Ohne Regel ist Login erlaubt. +- Mit Regel wird Login nur in erlaubten Zeitfenstern zugelassen. +- Bei Verbot: Hinweis, Konto wird deaktiviert, Shutdown wird gestartet. +- Optional: Konto wird nach Zeitfenster automatisch wieder aktiviert. + +## Technische Constraints & Risiken +- Zeit- und Zeitzonenhandling. +- Durchsetzung erfordert Hook in Auth/Login-Prozess. + +## Zugeordnete User Stories +- US_000045: Regeln fuer Login-Zeitfenster definieren und durchsetzen diff --git a/project-management/requirements/stories/US_000044.md b/project-management/requirements/stories/US_000044.md new file mode 100644 index 0000000..71d3f41 --- /dev/null +++ b/project-management/requirements/stories/US_000044.md @@ -0,0 +1,20 @@ +ID: US_000044 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# US_000044: Systemmetriken im Dashboard anzeigen + +Als User moechte ich die aktuelle CPU-, GPU-, RAM- und Netzwerkauslastung sehen, +damit ich den Systemzustand schnell bewerten kann. + +## Akzeptanzkriterien +- Given ich bin im Dashboard eingeloggt +- When die System Information Kacheln angezeigt werden +- Then sehe ich CPU Gesamt-Auslastung in Prozent +- And RAM Total sowie Usage in Prozent +- And GPU VRAM Total sowie Usage in Prozent (falls GPU vorhanden) +- And Netzwerk RX/TX als aktuelle Mbps +- And die Werte aktualisieren sich alle 5 Sekunden + +## Task-Platzhalter +- TASK_000050: Backend-Endpoint fuer Systemmetriken +- TASK_000051: UI-Kacheln im Dashboard (System Information) diff --git a/project-management/requirements/stories/US_000045.md b/project-management/requirements/stories/US_000045.md new file mode 100644 index 0000000..8266da0 --- /dev/null +++ b/project-management/requirements/stories/US_000045.md @@ -0,0 +1,33 @@ +ID: US_000045 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# US_000045: Regeln fuer Login-Zeitfenster definieren und durchsetzen + +Als Administrator moechte ich Regeln definieren, in welchen Zeitfenstern sich ein Nutzer +anmelden darf, damit Parent-Control verbindlich umgesetzt wird. + +## Akzeptanzkriterien +- Given ein Nutzer hat keine Regel +- When er sich anmeldet +- Then ist Login erlaubt + +- Given ein Nutzer hat eine Regel mit erlaubten Zeitfenstern +- When er sich ausserhalb dieser Zeiten anmeldet +- Then erhaelt er einen Hinweis +- And das Konto wird deaktiviert +- And der Rechner wird heruntergefahren + +- Given das Geraet startet +- When Regeln existieren +- Then wird geprueft, welche Nutzer anmelden duerfen +- And gesperrte Nutzer bleiben deaktiviert + - And Nutzer ohne Auto-Reaktivierung bleiben gesperrt, auch wenn ein Zeitfenster startet + +- Given eine Regel erlaubt automatische Reaktivierung +- When ein Zeitfenster beginnt +- Then wird das Konto automatisch wieder aktiviert + +## Task-Platzhalter +- TASK_000052: Regelmodell und Speicherung definieren +- TASK_000053: Login-Pruefung und Enforcement +- TASK_000054: Admin-UI fuer Regeln und Scheduler diff --git a/project-management/requirements/stories/US_000046.md b/project-management/requirements/stories/US_000046.md new file mode 100644 index 0000000..e7677c2 --- /dev/null +++ b/project-management/requirements/stories/US_000046.md @@ -0,0 +1,17 @@ +ID: US_000046 | Version: 0.2.1 | Status: Done +By: Codex (GPT-5) + +# US_000046: Update-Service Erreichbarkeit anzeigen + +Als Admin moechte ich sehen, ob der Update-Service erreichbar ist und welche URL aktiv ist, +damit ich erkenne, ob das Geraet gegen Dev oder Prod konfiguriert ist. + +## Akzeptanzkriterien +- Given ich bin im Update-Dashboard eingeloggt +- When der Statusbereich angezeigt wird +- Then sehe ich die konfigurierte Update-Service URL +- And einen Online/Offline-Status basierend auf Erreichbarkeit +- And die Anzeige aktualisiert sich bei Status-Refresh + +## Task-Platzhalter +- TASK_000055: Endpoint und UI fuer Update-Service Status diff --git a/project-management/requirements/tasks/TASK_000050.md b/project-management/requirements/tasks/TASK_000050.md new file mode 100644 index 0000000..619262d --- /dev/null +++ b/project-management/requirements/tasks/TASK_000050.md @@ -0,0 +1,19 @@ +ID: TASK_000050 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# TASK_000050: Backend-Endpoint fuer Systemmetriken + +## Outcome +API liefert aktuelle CPU/RAM/GPU/Netzwerkdaten in einem Payload. + +## Story-Bezug +US_000044 + +## Beschreibung +- Endpoint (z.B. `GET /system/metrics`) mit Auth. +- CPU Gesamt-%, RAM total + usage %, GPU VRAM total + usage % (fallback wenn nicht vorhanden). +- Netzwerk RX/TX in Mbps via Delta ueber 5s Fenster. + +## Definition of Done (DoD) +- Endpoint antwortet in <1s. +- Payload klar dokumentiert. diff --git a/project-management/requirements/tasks/TASK_000051.md b/project-management/requirements/tasks/TASK_000051.md new file mode 100644 index 0000000..4d5181c --- /dev/null +++ b/project-management/requirements/tasks/TASK_000051.md @@ -0,0 +1,18 @@ +ID: TASK_000051 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# TASK_000051: UI-Kacheln im Dashboard (System Information) + +## Outcome +Dashboard zeigt System Information Container mit Kacheln fuer CPU/RAM/GPU/Netzwerk. + +## Story-Bezug +US_000044 + +## Beschreibung +- UI-Container "System Information" mit Kacheln. +- Polling alle 5 Sekunden. +- Fallback-Text, wenn GPU nicht vorhanden. + +## Definition of Done (DoD) +- UI aktualisiert Werte ohne Page-Reload. diff --git a/project-management/requirements/tasks/TASK_000052.md b/project-management/requirements/tasks/TASK_000052.md new file mode 100644 index 0000000..fa831e4 --- /dev/null +++ b/project-management/requirements/tasks/TASK_000052.md @@ -0,0 +1,19 @@ +ID: TASK_000052 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# TASK_000052: Regelmodell und Speicherung definieren + +## Outcome +Ein persistentes Regelmodell fuer Login-Zeitfenster und Auto-Reaktivierung. + +## Story-Bezug +US_000045 + +## Beschreibung +- Regelstruktur (User, erlaubte Zeitfenster pro Tag, Wochentage, Auto-Reaktivierung). +- Speicherort (Datei/DB), Format und Validierung. +- Zeitzonen-Handling definieren (lokale Systemzeit). + +## Definition of Done (DoD) +- Regelmodell dokumentiert. +- Persistenzstrategie festgelegt. diff --git a/project-management/requirements/tasks/TASK_000053.md b/project-management/requirements/tasks/TASK_000053.md new file mode 100644 index 0000000..dc090c7 --- /dev/null +++ b/project-management/requirements/tasks/TASK_000053.md @@ -0,0 +1,18 @@ +ID: TASK_000053 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# TASK_000053: Login-Pruefung und Enforcement + +## Outcome +Login wird anhand der Regeln geprueft und bei Verbot durchgesetzt (Hinweis, Sperre, Shutdown). + +## Story-Bezug +US_000045 + +## Beschreibung +- Hook in Login-Flow (PAM am OS). +- Hinweistext definieren. +- Deaktivierung und Shutdown-Logik ausloesen. + +## Definition of Done (DoD) +- Login-Blockade funktioniert bei Verbot. diff --git a/project-management/requirements/tasks/TASK_000054.md b/project-management/requirements/tasks/TASK_000054.md new file mode 100644 index 0000000..0dfce30 --- /dev/null +++ b/project-management/requirements/tasks/TASK_000054.md @@ -0,0 +1,19 @@ +ID: TASK_000054 | Version: 0.2.1 | Status: Draft +By: Codex (GPT-5) + +# TASK_000054: Admin-UI fuer Regeln und Scheduler + +## Outcome +Admins koennen Regeln verwalten; ein Scheduler aktiviert Nutzer bei erlaubten Zeiten. + +## Story-Bezug +US_000045 + +## Beschreibung +- UI: Regeln anlegen/aktualisieren/loeschen. +- Scheduler: Pruefung beim Boot (Systemstart) und regelmaessig. +- Auto-Reaktivierung umsetzen (ausser Regel sagt nein). + +## Definition of Done (DoD) +- UI verwaltet Regeln. +- Scheduler aktiviert Nutzer entsprechend Regeln. diff --git a/project-management/requirements/tasks/TASK_000055.md b/project-management/requirements/tasks/TASK_000055.md new file mode 100644 index 0000000..70a2c4d --- /dev/null +++ b/project-management/requirements/tasks/TASK_000055.md @@ -0,0 +1,17 @@ +ID: TASK_000055 | Version: 0.2.1 | Status: Done +By: Codex (GPT-5) + +# TASK_000055: Endpoint und UI fuer Update-Service Status + +## Outcome +UI zeigt Update-Service URL und Erreichbarkeit; Backend liefert Status. + +## Story-Bezug +US_000046 + +## Beschreibung +- `GET /update/service-status` liefert URL, Reachability, Status-Code. +- UI zeigt Status im Update-Bereich. + +## Definition of Done (DoD) +- Statusanzeige funktioniert auch bei Fehlern (Offline).