docs: add project management structure

This commit is contained in:
2025-12-28 09:16:22 +01:00
parent 3991362e67
commit 4eb20e2449
50 changed files with 1905 additions and 0 deletions

View File

@ -0,0 +1,62 @@
# Theme: Watchtower (Sci-Fi / Dark)
Dieses Theme basiert auf der `minecraft-watchtower` UI. Es ist ein **High-Contrast Dark Mode** mit Neon-Akzenten, ausgelegt auf technische Dashboards und "Immersive UIs".
## Verwendung
Binde statt `tokens.css` die Datei `tokens_watchtower.css` ein und ergänze `theme_watchtower.css`.
```html
<link rel="stylesheet" href="design/tokens_watchtower.css">
<link rel="stylesheet" href="design/components.css"> <!-- Standard Components -->
<link rel="stylesheet" href="design/theme_watchtower.css"> <!-- Theme Overrides -->
```
Zusätzlich sollte die Klasse `.bg-noise` direkt nach dem `<body>` Tag eingefügt werden:
```html
<body>
<div class="bg-noise"></div>
...
</body>
```
---
## TUI (Terminal User Interface) Adaption
Da dieses Design oft in CLI-Tools oder TUIs verwendet wird, gelten folgende Mappings für Terminals (16/256 Farben).
### Farb-Palette
| Rolle | CSS Variable | ANSI Color (16) | ANSI Code | Hex Fallback |
| :--- | :--- | :--- | :--- | :--- |
| **Background** | `--bg-dark` | Black | `\e[40m` | `#0b0f14` |
| **Text** | `--text` | White (Bright) | `\e[97m` | `#e6edf5` |
| **Muted Text** | `--text-dim` | Cyan (Dim) | `\e[36m` | `#9aa7b8` |
| **Accent** | `--accent` | Cyan (Bright) | `\e[96m` | `#00e08f` |
| **Success** | `--success` | Green (Bright) | `\e[92m` | `#00e08f` (Teal) |
| **Warning** | `--warning` | Yellow (Bright) | `\e[93m` | `#ffb454` |
| **Error** | `--danger` | Red (Bright) | `\e[91m` | `#ff5e5e` |
### Block-Elemente & Rahmen
Für TUI-Rahmen nutzen wir "Heavy" oder "Double" Lines, um den technischen Look zu imitieren.
* **Box Border:** `═` (Double Horizontal), `║` (Double Vertical), `╔ ╗ ╚ ╝` (Corners)
* **Progress Bar:** `█` (Full Block) für den Füllstand, `░` (Light Shade) für den Hintergrund.
### Beispiel (Charm / Bubble Tea - Go)
```go
var (
ColorAccent = lipgloss.Color("#00e08f")
ColorBg = lipgloss.Color("#0b0f14")
ColorText = lipgloss.Color("#e6edf5")
StyleCard = lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(ColorAccent).
Padding(1, 2).
Background(ColorBg)
)
```

View File

@ -0,0 +1,86 @@
# OIDC Integration: OICD (IdP) + Kiddo (Clients)
## Herangehensweise und Gedankengang
Ziel war es, beide Projekte so zu verbinden, dass Kiddo OICD als OIDC-Provider nutzt, ohne Codeaenderungen vorzunehmen. Wir haben die vorhandenen Konfigurationspfade, DCR-Faehigkeiten und OIDC-Endpunkte geprueft und daraus die minimalen, operationalen Schritte abgeleitet.
Leitfragen, die wir dabei beantwortet haben:
- Welche Konfiguration erwartet Kiddo fuer OIDC (Issuer, Client, Redirect, Cookies)?
- Welche OIDC-Funktionen liefert OICD (Discovery, JWKS, DCR, Admin-UI)?
- Wo liegen die harten OIDC-Anforderungen (Issuer-Match, exakte Redirect-URIs, TLS-Vertrauen)?
- Wie kann die Registrierung skalieren, wenn Geraete und Redirects erst spaeter feststehen?
### OICD (IdP) - Herangehensweise
Wir haben in OICD geprueft, welche OIDC-Endpunkte vorhanden sind (Discovery, JWKS, Token, DCR) und wie der Issuer erzeugt wird. Entscheidend ist, dass der Issuer exakt der externen URL entspricht, unter der OICD erreichbar ist. Zudem gibt es eine Admin-Funktion zur Erzeugung von Initial-Access-Tokens, die den DCR-Flow ermoeglichen. Daraus folgt: Stabiler Issuer (prod/dev), TLS trust, und ein standardisierter Weg zur Token-Erzeugung fuer DCR.
### Kiddo (Client) - Herangehensweise
Wir haben in Kiddo geprueft, welche Umgebungsvariablen fuer OIDC benoetigt werden und wie die Claims interpretiert werden. Kiddo validiert ID-Tokens gegen den Issuer und JWKS und benoetigt exakte Redirect-URIs. Da die Device-Hosts dynamisch sind, ist DCR der beste Weg, pro Geraet eigene Clients zu registrieren, sobald die finale URL bekannt ist. Daraus folgen: pro Geraet DCR, danach Env-Setup, optional Allowlist fuer OIDC-User.
Aus diesen Punkten ergab sich der Weg: OICD stellt stabile Issuer-URLs bereit, Redirect-URIs muessen konkret registriert werden, und DCR (mit Initial-Access-Token) ist der beste Weg, um pro Geraet eigene Clients dynamisch zu erzeugen. Daraus wurden die Stories, Akzeptanzkriterien und das Provisioning-Kommando abgeleitet.
## Epic: OIDC-Login fuer Kiddo (Client-Seite)
### Story 1: Zentrales Provisioning registriert pro Geraet einen OIDC-Client
Als Provisioner moechte ich pro Geraet einen OIDC-Client via DCR anlegen, damit jedes Geraet einen eigenen Client-ID/Secret hat.
Acceptance Criteria:
- DCR-Call mit `SKD_OIDC_ISSUER`, `SKD_OIDC_REDIRECT_URI` und `OIDC_INITIAL_ACCESS_TOKEN` erzeugt `client_id` und `client_secret`.
- Redirect-URI ist exakt `https://<device-host>[:port]/login/oidc/callback` (keine Wildcards).
Referenzen:
- `kiddo/scripts/register_oidc_client.sh`
### Story 2: Kiddo-Geraet ist per OIDC konfiguriert
Als Geraetebetreiber moechte ich ein Kiddo-Geraet so konfigurieren, dass es sich ueber OICD authentifiziert.
Acceptance Criteria:
- `SKD_AUTH_MODE=oidc` ist gesetzt.
- `SKD_OIDC_ISSUER`, `SKD_OIDC_CLIENT_ID`, `SKD_OIDC_CLIENT_SECRET`, `SKD_OIDC_REDIRECT_URI` sind gesetzt.
- Bei HTTPS ist `SKD_SESSION_COOKIE_SECURE=true`.
Referenzen:
- `kiddo/env.example`
- `kiddo/README.md`
- `kiddo/backend/settings.py`
### Story 3: Zugriffskontrolle auf OIDC-Login
Als Betreiber moechte ich steuern, welche Benutzer sich via OIDC anmelden duerfen.
Acceptance Criteria:
- `SKD_AUTH_ALLOWED_USERS` schraenkt Zugriff ein, basierend auf `preferred_username` oder `email` oder `sub` aus dem ID-Token.
Referenzen:
- `kiddo/backend/oidc.py`
- `kiddo/backend/auth.py`
### Story 4: Betrieb mit wechselnden Geraeten (DCR-Flow)
Als Betreiber moechte ich neue Geraete spaeter onboarden koennen, ohne OICD manuell zu konfigurieren.
Acceptance Criteria:
- DCR-Prozess ist dokumentiert und kann pro Geraet wiederholt werden.
- Bei Host/Port-Aenderung erfolgt Neuregistrierung (neuer Client/Secret).
Referenzen:
- `kiddo/scripts/register_oidc_client.sh`
## DCR Kommando (zentral, pro Geraet)
Prod:
```bash
export SKD_OIDC_ISSUER="https://auth.wlkns.org"
export SKD_OIDC_REDIRECT_URI="https://<device-host>[:port]/login/oidc/callback"
export OIDC_INITIAL_ACCESS_TOKEN="<initial-access-token>"
/home/stephan/applications/wlkns/kiddo/scripts/register_oidc_client.sh
```
Dev:
```bash
export SKD_OIDC_ISSUER="https://dev.wlkns.org"
export SKD_OIDC_REDIRECT_URI="https://<device-host>[:port]/login/oidc/callback"
export OIDC_INITIAL_ACCESS_TOKEN="<initial-access-token>"
/home/stephan/applications/wlkns/kiddo/scripts/register_oidc_client.sh
```
Hinweise:
- Redirect-URIs muessen exakt registriert sein (keine Wildcards).
- Bei Host/Port-Aenderung: neu registrieren und neue Client-Credentials setzen.

View File

@ -0,0 +1,135 @@
/*
wlkns-dev-standards
Component Theme: Watchtower
Adapts standard components to the Sci-Fi/Dark aesthetic.
*/
/* =========================
Inputs & Forms
========================= */
input, select, textarea {
background: rgba(10, 14, 20, 0.6) !important;
border-color: rgba(255, 255, 255, 0.15) !important;
color: var(--color-text) !important;
transition: all 0.2s ease;
}
input:focus, select:focus, textarea:focus {
border-color: var(--color-accent) !important;
box-shadow: 0 0 15px var(--wt-glow);
}
/* =========================
Buttons
========================= */
.button {
text-transform: uppercase;
letter-spacing: 0.05em;
font-weight: 600;
border-radius: 999px !important; /* Pill shape */
}
.button.primary {
box-shadow: 0 0 15px var(--wt-glow);
color: #081015; /* Dark text on bright accent */
}
.button.secondary {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.2);
color: var(--color-text);
}
.button.secondary:hover {
border-color: var(--color-text);
background: rgba(255,255,255,0.05);
}
.button.danger {
box-shadow: 0 0 10px rgba(255, 94, 94, 0.4);
color: #1b0d0d;
}
/* =========================
Tables
========================= */
table {
border-collapse: separate;
border-spacing: 0 4px; /* Space between rows */
}
thead th {
border-bottom: 1px solid var(--color-accent);
text-transform: uppercase;
letter-spacing: 0.1em;
font-size: 0.75rem;
color: var(--color-accent);
background: transparent;
}
tbody tr {
background: rgba(255, 255, 255, 0.03);
transition: transform 0.2s;
}
tbody tr:hover {
background: rgba(255, 255, 255, 0.06);
transform: scale(1.01);
}
tbody td {
border: none;
}
tbody td:first-child {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
tbody td:last-child {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
/* =========================
Alerts & Toasts
========================= */
.alert, .toast {
background: rgba(10, 14, 20, 0.95);
backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.alert.success, .toast.success {
border-color: var(--color-success);
box-shadow: 0 0 10px rgba(0, 224, 143, 0.2);
color: var(--color-text);
}
.alert.warning, .toast.warning {
border-color: var(--color-warning);
color: var(--color-text);
}
.alert.error, .toast.error {
border-color: var(--color-error);
box-shadow: 0 0 10px rgba(255, 94, 94, 0.2);
color: var(--color-text);
}
/* =========================
Pagination
========================= */
.pagination .page {
background: transparent;
border: 1px solid rgba(255,255,255,0.1);
color: var(--color-text-muted);
}
.pagination .page.active {
background: var(--color-accent);
color: #081015;
border-color: var(--color-accent);
box-shadow: 0 0 10px var(--wt-glow);
}

View File

@ -0,0 +1,69 @@
/*
wlkns-dev-standards
Theme: Watchtower (Dark Glow)
Version: v1.0
Based on: minecraft-watchtower UI
*/
:root {
/* =========================
Core Palette (Watchtower)
========================= */
--wt-bg-dark: #0b0f14;
--wt-bg-panel: #10151d;
--wt-accent: #00e08f;
--wt-warning: #ffb454;
--wt-danger: #ff5e5e;
--wt-text: #e6edf5;
--wt-text-dim: #9aa7b8;
--wt-glow: rgba(0, 224, 143, 0.35);
/* =========================
Mapping -> Standard Tokens
========================= */
/* Farben – Identity & Status */
--color-primary: #1a2230; /* Deep Blue/Grey from Gradient */
--color-accent: var(--wt-accent);
--color-success: var(--wt-accent); /* Watchtower uses accent as success */
--color-warning: var(--wt-warning);
--color-error: var(--wt-danger);
/* Farben – Neutrals (Dark Mode Override) */
--color-bg: var(--wt-bg-dark);
--color-surface: var(--wt-bg-panel);
--color-border: rgba(255, 255, 255, 0.08); /* Subtle white border */
--color-text: var(--wt-text);
--color-text-muted: var(--wt-text-dim);
/* Typografie (Optional: Falls Space Grotesk geladen wird) */
--font-ui: 'Space Grotesk', 'Inter', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
/* Radius & Spacing */
--radius-sm: 4px;
--radius-md: 12px; /* Watchtower uses larger radii */
--radius-lg: 16px;
/* Shadows becomes Glows in this theme */
--shadow-sm: 0 0 10px rgba(0,0,0,0.5);
--shadow-glow: 0 0 15px var(--wt-glow);
}
/* Global Theme Overrides */
body {
background: radial-gradient(circle at top, #1a2230 0%, #0b0f14 55%), linear-gradient(135deg, #0b0f14, #101623 60%);
min-height: 100vh;
}
/* Noise Texture helper class */
.bg-noise {
position: fixed;
inset: 0;
pointer-events: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
mix-blend-mode: soft-light;
z-index: -1;
}