Self-contained HTML-Kanban als operative Single Source of Truth für alle laufenden Projekte. Visualisiert das Ringsystem. Stack: Vanilla HTML/CSS/JS, localStorage, kein Build, kein Backend Server: ~/dev/kanban/server.sh (Python http.server auf Port 8765) Spec: ~/dev/kanban/SPEC.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
538 lines
22 KiB
Markdown
538 lines
22 KiB
Markdown
# Kanban — Spec & Architektur
|
||
|
||
**Datei:** `/Users/robinchoice/dev/kanban/index.html` (eine Datei, kein Build)
|
||
**Server:** `/Users/robinchoice/dev/kanban/server.sh` — static-file server aus `~` auf Port 8765
|
||
**Aufruf:** `http://localhost:8765/dev/kanban/index.html` (Server muss laufen für MD-Viewer; sonst funktioniert das Board trotzdem)
|
||
**State:** Browser `localStorage`
|
||
|
||
---
|
||
|
||
## Zweck
|
||
|
||
Single Source of Truth für alle laufenden Projekte. Self-contained HTML mit Kanban-Methodik (3 Spalten, Expedite-Swimlane, Class of Service, WIP-Limits, Little's Law, Monte Carlo).
|
||
Visualisiert das Ringsystem von Robin (Ring 0–3, vier Workspace-Gruppen, ~16 Boards).
|
||
|
||
---
|
||
|
||
## Layout
|
||
|
||
```
|
||
┌──────────────┬──────────────────────────────────────┬──────────────┐
|
||
│ SIDEBAR │ MAIN (Overview / Board / Analytics) │ IDEEN │
|
||
│ links │ │ rechts │
|
||
│ │ │ │
|
||
│ Gruppen │ • Header (Titel, Goal, Pills) │ • Input │
|
||
│ + Boards │ • Tabs │ • Filter │
|
||
│ + Aktionen │ • View-Body │ • Liste │
|
||
│ 210 px │ flex:1 │ 280 px │
|
||
└──────────────┴──────────────────────────────────────┴──────────────┘
|
||
```
|
||
|
||
Banner oben (rot/amber) wenn auf `file://` statt `localhost:8765` — mit Switch-Button.
|
||
|
||
---
|
||
|
||
## Drei Views (Tabs in der Reihenfolge: Overview · Board · Analytics)
|
||
|
||
### Overview (Default)
|
||
|
||
Hero-Block + 5 Sektionen, alle Felder editierbar:
|
||
|
||
| Element | Quelle | Edit |
|
||
|---|---|---|
|
||
| Hero-Icon (96×96, rounded) | `overview.icon` (path) | bei Bild-Fail Emoji-Fallback in Board-Farbe |
|
||
| Hero-Name | `board.name` | im Board-Header editierbar |
|
||
| Hero-Tagline (lila, kursiv) | `overview.tagline` | Click + tippen |
|
||
| Hero-Description (2-3 Sätze) | `overview.description` | Click + tippen |
|
||
| Badges: Ring, Gruppe, Typ | live + `overview.type` | type editierbar |
|
||
| Launch-Cards Grid | `overview.launches[]` | **Single-Click öffnet URL** (oder MD-Viewer wenn `.md`). **Doppelklick auf Text editiert.** `×` löscht. |
|
||
| Was bisher geschah | `overview.summary` | Click + tippen |
|
||
| Tech-Stack | `overview.stack[]` | Pill mit `×`, `+ Tech` Input |
|
||
| Hosting · IDs · Pfade | `overview.info[]` | Label + Value editierbar, Copy-Btn, `×`, `+ Zeile` |
|
||
| 🔒 Secrets · Keys | `overview.secrets[]` | Label + Value editierbar, masked-Toggle (Auge), Copy-Btn, `×`, `+ Secret` |
|
||
| ⌘ Quick-Commands | `overview.commands[]` | Label + Cmd editierbar, Copy-Btn, `×`, `+ Command` |
|
||
|
||
### Board
|
||
|
||
3-Spalten-Kanban + Expedite-Swimlane darüber.
|
||
|
||
| Spalte | Farbe | WIP-Limit |
|
||
|---|---|---|
|
||
| Ready | amber | — |
|
||
| In Progress | blau | per Board (Pill im Header editierbar) |
|
||
| Done | grün | — |
|
||
|
||
**Expedite-Swimlane:** horizontale Reihe über dem Board mit 3 Zonen (deckungsgleich mit Spalten). Tasks mit `cos:'expedite'` erscheinen NUR in der Zone, nicht im normalen col-body. Drag zwischen Zonen behält Expedite. Drag in col-body demotet. Drag von col-body in Zone promoted.
|
||
|
||
**Karten-Aktionen** (sichtbar bei Hover, oben rechts):
|
||
- ⚑ Blocker togglen (`task.blocked`) — Karte rot
|
||
- ↗ Promote-to-Board — öffnet Add-Board-Modal mit Task-Titel vorbelegt
|
||
- × Löschen
|
||
|
||
**Auto-Aging:** Karte > SLE-Tage in einer Spalte → roter Glow + "ÜBERFÄLLIG"-Label. Done-Karten werden nicht alt gezeigt.
|
||
|
||
**Add-Card:** `+ Karte…` Input am Spalten-Ende. Enter fügt hinzu, Esc blurt.
|
||
|
||
### Analytics
|
||
|
||
| KPI | Berechnung | Farbe |
|
||
|---|---|---|
|
||
| WIP | `count(wip)` gegen `wipLimit` | rot/amber/blau |
|
||
| Cycle Time ⌀ | `WIP / Throughput × 7` (Tage) | blau |
|
||
| Queue ETA | `(WIP+Ready) / Throughput × 7` (Tage bis Queue leer) | teal |
|
||
| Flow Efficiency | `WIP / (WIP+Ready) × 100%` | grün/amber/rot |
|
||
| Remaining | `WIP + Ready` | neutral |
|
||
|
||
**Throughput-Quelle:** automatisch `realThroughput()` aus Done-Cards der letzten 14 Tage (mit `task.doneAt`). Fallback `board.throughput` wenn keine History. Status-Pill ("↻ Real" grün vs. "⊘ Statisch" grau).
|
||
|
||
**Monte Carlo:** 8.000 Runs, Varianz ±60%, gibt P50/P75/P85/P95 Wochen + Datum. Live-Input für Throughput-Override.
|
||
|
||
**Active Blockers:** alle Tasks mit `task.blocked === true`.
|
||
|
||
**SLE:** vergleicht Cycle Time mit `board.sle.days`.
|
||
|
||
---
|
||
|
||
## Sidebar (links)
|
||
|
||
Gruppen-Sections, dynamisch aus `GROUPS` + `BOARDS` gerendert. Meta-Gruppe (Ring 0) ist visuell hervorgehoben (lila Gradient, Glow, `◉`-Bullet).
|
||
|
||
| Element | Verhalten |
|
||
|---|---|
|
||
| Gruppen-Section | Drop-Zone für Board-Drag (board.group ändern) |
|
||
| Gruppen-Header (`s-group`) | draggable — Reihenfolge der Gruppen ändern (persistiert in `kanban_groups`) |
|
||
| Nav-Item (Board) | Klick = aktivieren; draggable in andere Gruppe oder vor andere Nav-Items (Reihenfolge in `kanban_board_order`) |
|
||
| Ring-Badge (R0/R1p/R1w/R2/R3/?) | Klick togglet durch Ring-Werte |
|
||
| Badge (Count) | `remaining(b)` mit Color-Code (rot=Blocker, blau=WIP, grau=neutral) |
|
||
| `×` (nur user-erstellt) | löscht das Board |
|
||
|
||
**Unten:**
|
||
- `+ Board` → Modal: Name, Goal, Gruppe (oder + Neue Gruppe), Farb-Picker (8 Optionen)
|
||
- `+ Gruppe` → `prompt()` für Namen; leere Gruppen werden gezeigt
|
||
- `↺ Reset` → aktuelles Board auf DEFAULTS zurück; bei user-erstellten Boards: löschen
|
||
|
||
---
|
||
|
||
## Ideen-Pinnwand (rechts)
|
||
|
||
| Element | Verhalten |
|
||
|---|---|
|
||
| Input + Enter | neue Idee am Anfang einfügen, Tag aus aktivem Filter |
|
||
| Filter-Buttons (Alle/Projekt/Erkenntnis/Später) | filtern Liste + setzen Default-Tag |
|
||
| Idee-Card | hover-Buttons: `→` (Promote-Modal) und `✕` (löschen); **draggable** auf col-body → erstellt Task |
|
||
| Drop-Zonen (erscheinen beim Card-Drag aus Board) | 📂 Projekt / 💡 Erkenntnis / 🕒 Später / ○ ohne Label — droppen entfernt Task aus Board und legt Idee an |
|
||
|
||
**Seed:** 35 Ideen (v1=20 Projekt, v2=15 Erkenntnis, v3=+16 aus _archive). Versionierung via `kanban_ideas_seeded` Key.
|
||
|
||
---
|
||
|
||
## Datenmodell
|
||
|
||
### Task
|
||
```js
|
||
{
|
||
t: 'Titel', // required
|
||
blocked: true, // optional — Karte rot, ⚑ aktiv
|
||
cos: 'expedite' | 'fixed', // optional — Class of Service
|
||
movedAt: 1779580800000, // Timestamp letzter Spaltenwechsel (für Aging)
|
||
doneAt: 1779580800000, // Timestamp bei Wechsel nach Done (für Throughput)
|
||
age: 14, // optional — manuell überschriebenes Aging (rare)
|
||
note: 'Notiz', // optional — graue Sub-Zeile
|
||
}
|
||
```
|
||
|
||
### Board
|
||
```js
|
||
{
|
||
name: 'Döner-App',
|
||
goal: 'Beschreibung',
|
||
group: 'Code', // Sidebar-Gruppe
|
||
color: '#f87171', // Dot-Farbe
|
||
ring: '0' | '1p' | '1w' | '2' | '3' | '?',
|
||
wipLimit: 3, // editierbar via Pill
|
||
throughput: 2, // editierbar via Pill (Fallback wenn keine Done-History)
|
||
sle: { days: 14, p: 85 }, // days editierbar via Pill
|
||
cols: [
|
||
{ id: 'ready', label: 'Ready', tasks: [...] },
|
||
{ id: 'wip', label: 'In Progress', tasks: [...] },
|
||
{ id: 'done', label: 'Done', tasks: [...] },
|
||
],
|
||
focus: 'Fixstern-Text', // editierbar im Header
|
||
overview: { // optional
|
||
icon: 'assets/...png',
|
||
tagline: '...',
|
||
description: '...',
|
||
summary: '...',
|
||
type: 'ios-app' | 'web' | 'meta' | ...,
|
||
launches: [{label, sub, url, icon}],
|
||
stack: ['...'],
|
||
info: [{label, value}],
|
||
secrets: [{label, value, masked}],
|
||
commands: [{label, cmd}],
|
||
},
|
||
userCreated: true, // nur bei UI-erstellten Boards
|
||
}
|
||
```
|
||
|
||
### Idea
|
||
```js
|
||
{
|
||
id: 1013,
|
||
text: '...',
|
||
tag: 'projekt' | 'erkenntnis' | 'spaeter', // optional
|
||
created: '17.05.' | 'archive/...' | 'journal/...',
|
||
}
|
||
```
|
||
|
||
### State-Keys in localStorage
|
||
|
||
| Key | Inhalt |
|
||
|---|---|
|
||
| `kanban_v2` | `{[boardId]: {cols, focus, [overrides], [userCreated-Meta]}}` |
|
||
| `kanban_groups` | `['Meta','Code',...]` |
|
||
| `kanban_board_order` | `{[group]: [id1, id2, ...]}` |
|
||
| `kanban_ideas` | `[Idea, ...]` |
|
||
| `kanban_ideas_seeded` | `'v3'` |
|
||
|
||
---
|
||
|
||
## Default-Boards
|
||
|
||
| ID | Name | Gruppe | Ring |
|
||
|---|---|---|---|
|
||
| ringsystem | Ringsystem | Meta | 0 |
|
||
| kanban | Kanban (dieses Board) | Meta | 0 |
|
||
| doener | Döner-App | Code | 3 |
|
||
| musichub | Music Hub | Code | 1w |
|
||
| openclaw | OpenClaw / Rob | Code | 1w |
|
||
| docpilot | docpilot | Code | 1w |
|
||
| k4 | K4 Digital — PM-Mandat | Beruflich | 1w |
|
||
| branding | Branding & Außendarstellung | Beruflich | 1w |
|
||
| psk | PSK I Zertifizierung | Beruflich | 1w |
|
||
| eu | Einzelunternehmen | Beruflich | 1w |
|
||
| pleasance | Pleasance | Web | 3 |
|
||
| mdim | mydrugismusic Website | Web | 3 |
|
||
| privat | Haushalt & Leben | Privat | 1p |
|
||
| degoogle | De-Google / FOSS Migration | Privat | 1p |
|
||
| bibliothek | Bibliothek-Pipeline | Privat | 1p |
|
||
| aikb | AI Engineering KB | Privat | 1w |
|
||
|
||
**Overview gefüllt für:** doener, kanban, ringsystem. Andere: nur Skeleton (Pilot-Modus).
|
||
|
||
---
|
||
|
||
## Tool-Agnostik
|
||
|
||
| Datei | Status |
|
||
|---|---|
|
||
| `~/.claude/AGENTS.md` | kanonisch |
|
||
| `~/.claude/CLAUDE.md` | Symlink → AGENTS.md |
|
||
| `~/dev/personal-vault/AGENTS.md` | kanonisch |
|
||
| `~/dev/personal-vault/CLAUDE.md` | Symlink → AGENTS.md |
|
||
| `~/dev/robin-work/AGENTS.md` | kanonisch |
|
||
| `~/dev/robin-work/CLAUDE.md` | Symlink → AGENTS.md |
|
||
|
||
**Backup:** `~/.claude/CLAUDE.md.bak` (alte Datei vor der Symlink-Migration)
|
||
|
||
Skills tool-agnostisch über `~/.skills/{name}.md` mit Symlinks aus tool-spezifischen Verzeichnissen (Claude: `~/.claude/skills/{name}/SKILL.md`; OpenCode: `~/.config/opencode/commands/{name}.md`).
|
||
|
||
---
|
||
|
||
## Local-Server
|
||
|
||
```
|
||
~/dev/kanban/server.sh
|
||
```
|
||
|
||
Startet `python3 -m http.server 8765 --bind 127.0.0.1` aus `~/`.
|
||
|
||
- Aufruf: `~/dev/kanban/server.sh` (Vordergrund) oder `nohup ~/dev/kanban/server.sh &` (Hintergrund persist)
|
||
- Stop: `pkill -f "http.server 8765"`
|
||
- Logs: `/tmp/kanban-server.log` (wenn via nohup gestartet)
|
||
|
||
Benötigt nur für **MD-Viewer** und localhost-URLs. Board-Funktion funktioniert auch ohne Server unter `file://`. Aber dann erscheint ein Warn-Banner oben.
|
||
|
||
---
|
||
|
||
## MD-Viewer
|
||
|
||
Klick auf Launch-Card mit `.md`-URL → Modal mit gerendertem Markdown.
|
||
|
||
Mini-Parser inline: Headings (h1-h3), Bold, Italic, inline Code, Code-Blocks, Listen (ul/ol), Tables, Blockquotes, Hr, Links.
|
||
|
||
Fallback wenn `fetch()` scheitert (CORS): Anleitung mit drei Optionen (Extension / Server / Tab).
|
||
|
||
---
|
||
|
||
## Wichtige JS-Funktionen
|
||
|
||
### Render
|
||
| Funktion | Beschreibung |
|
||
|---|---|
|
||
| `show(id)` | Board wechseln |
|
||
| `setView(v)` | Tab-Switch (overview/board/analytics) |
|
||
| `renderOverview(id)` | Hero + 5 Sektionen |
|
||
| `renderBoard(id)` | Swimlane + 3 Spalten + col-add-input |
|
||
| `renderAnalytics(id)` | KPIs, Flow, Monte Carlo, Blockers, SLE |
|
||
| `renderSidebar()` | Gruppen + Boards |
|
||
| `renderIdeas()` | gefilterte Ideen mit Drag-Attrs |
|
||
| `initBadges()` | Alias renderSidebar |
|
||
| `renderMarkdown(src)` | Mini-MD-Parser |
|
||
|
||
### State
|
||
| Funktion | Beschreibung |
|
||
|---|---|
|
||
| `loadState()` / `saveState()` | BOARDS persist mit Override-Logik für Defaults |
|
||
| `loadGroups()` / `saveGroups()` | + Migration: `Meta` vorne einfügen wenn fehlend |
|
||
| `loadBoardOrder()` / `saveBoardOrder()` | per-Group-Order |
|
||
| `loadIdeas()` / `saveIdeas()` | + Seeding |
|
||
| `migrateCols(b)` | 5→3-Spalten-Migration |
|
||
| `getBoardsForGroup(g)` | geordnete Board-IDs |
|
||
|
||
### Mutations (Board)
|
||
| Funktion | Beschreibung |
|
||
|---|---|
|
||
| `addCard(boardId, colId, text)` | mit `movedAt` + ggf. `doneAt` |
|
||
| `deleteCard(boardId, colId, idx)` | |
|
||
| `toggleBlocker(boardId, colId, idx)` | `task.blocked` |
|
||
| `saveBoardSetting(key, el, min, max)` | wipLimit/throughput/sleDays |
|
||
| `saveBoardName()` / `saveBoardGoal()` | Header-Edit |
|
||
| `saveFocus()` | Fokus-Text im Header |
|
||
| `resetCurrentBoard()` | Default-Reset oder User-Board-Delete |
|
||
| `deleteBoard(id, e)` | nur user-erstellt |
|
||
| `cycleRing(boardId, e)` | togglet durch Ring-Werte |
|
||
| `promoteToBoard(boardId, colId, idx)` | Task → neues Board |
|
||
|
||
### Mutations (Overview)
|
||
| Funktion | Beschreibung |
|
||
|---|---|
|
||
| `updateOvFromEl(el)` | aus data-section/idx/prop |
|
||
| `addOvRow(section)` | leere Zeile für info/secrets/launches/commands |
|
||
| `addOvPill(section, value)` | für stack |
|
||
| `deleteOvRow(section, idx)` | |
|
||
| `enableEdit(el)` | Launch-Card-Felder Doppelklick aktiviert |
|
||
| `toggleSecretBtn(btn)` | masked toggle |
|
||
| `copyText(t, btn)` / `copyFromBtn(btn)` | Clipboard mit visual feedback |
|
||
|
||
### Mutations (Ideen)
|
||
| Funktion | Beschreibung |
|
||
|---|---|
|
||
| `addIdea()` / `deleteIdea(idx)` | |
|
||
| `filterIdeas(tag)` | + setzt Default-Tag |
|
||
| `openPromote(idx)` / `confirmPromote()` / `closePromote()` | Modal Idee→Task |
|
||
|
||
### Add-Board-Modal
|
||
| Funktion | Beschreibung |
|
||
|---|---|
|
||
| `showAddBoard()` / `closeAddBoard()` | |
|
||
| `selectAbColor(c, el)` | Farb-Picker |
|
||
| `confirmAddBoard()` | + Promote-Source-Handling |
|
||
| `showAddGroup()` | prompt()-Dialog |
|
||
|
||
### DnD
|
||
| Funktion | Beschreibung |
|
||
|---|---|
|
||
| `onDragStart/End` (Cards) | + `showIdeaDropZones(on)` |
|
||
| `onDragOver/Drop` (col-body) | demotet expedite, handelt auch Ideen-Drops |
|
||
| `onDragOverExp/onDropToExpCol` | promoted expedite |
|
||
| `onBoardDragStart/End` | Board-Drag in Sidebar |
|
||
| `onGroupDragOver/Drop` | Board → Gruppe |
|
||
| `onNavItemDragOver/Drop` | Board-Reorder innerhalb Gruppe |
|
||
| `onIdeaDragStart/End` | Idee aus Pinnwand |
|
||
| `onGroupHeaderDragStart/End` | Gruppe-Reorder |
|
||
| `onGroupSectionDragOver/Drop` | Gruppe-Drop-Target |
|
||
| `onIdeaZoneDragOver` / `onDropToIdeas` | Card → Idee |
|
||
| `onLaunchClick(e, card)` | Launch-Card öffnet URL/MD |
|
||
|
||
### Helper
|
||
| Funktion | Beschreibung |
|
||
|---|---|
|
||
| `escapeHtml(s)` | HTML-Escape |
|
||
| `liveAge(task)` | aus `movedAt` |
|
||
| `ageClass(days)` | fresh/ok/warn/old |
|
||
| `colCount(b, id)` | tasks.length |
|
||
| `remaining(b)` | ready + wip |
|
||
| `hasBlocker(b)` | any task.blocked |
|
||
| `monteCarlo(left, tp, runs)` | {p50,p75,p85,p95} |
|
||
| `realThroughput(b, days)` | aus Done-History |
|
||
| `openMD(url)` / `closeMD()` / `openMdExternal()` | MD-Viewer |
|
||
| `enableEdit(el)` | Launch-Card-Edit-Modus aktivieren |
|
||
|
||
### Globals
|
||
```js
|
||
let curId = 'doener';
|
||
let curView = 'overview'; // default
|
||
let BOARDS = {}; // runtime, mutiert
|
||
let IDEAS = [];
|
||
let GROUPS = ['Meta','Code',...];
|
||
let BOARD_ORDER = {};
|
||
let dragSrc = null; // {boardId, colId, idx} bei Card-Drag im Board
|
||
let dragBoard = null; // boardId bei Sidebar-Drag
|
||
let dragIdea = null; // idx bei Ideen-Drag
|
||
let dragGroup = null; // group bei Gruppe-Drag
|
||
let promoteSource = null; // {boardId, colId, idx} beim Task→Board
|
||
let abSelColor = '#7c6af7';
|
||
let promoteIdx = null;
|
||
let mdCurrentUrl = null;
|
||
```
|
||
|
||
---
|
||
|
||
## CSS-Variablen (Theme)
|
||
|
||
```
|
||
--bg:#0d0d0f, --surface:#16161a, --surface2:#1e1e24, --surface3:#26262e
|
||
--border:#2a2a35, --border2:#353545
|
||
--text:#e8e8f0, --text-muted:#6b6b80, --text-dim:#4a4a5a
|
||
--accent:#7c6af7 (lila), --accent-soft:#2d2550
|
||
--green:#4ade80, --amber:#fbbf24, --red:#f87171, --blue:#60a5fa
|
||
--teal:#2dd4bf, --purple:#c084fc, --orange:#fb923c
|
||
--sidebar-w:210px, --col-w:240px
|
||
```
|
||
|
||
Color-of-State Konvention:
|
||
- **Ready** = amber
|
||
- **In Progress** = blau
|
||
- **Done** = grün
|
||
- **Blocked** = rot (Border + Background-Tint)
|
||
- **Expedite** = rot (border-left + Swimlane-Background)
|
||
- **Fixed Date** = amber (border-left)
|
||
- **Aging > SLE** = roter Glow
|
||
|
||
---
|
||
|
||
## Test-Checkliste (für externe Tester-Agents)
|
||
|
||
### Layout & Navigation
|
||
- [ ] Sidebar links: alle 5 Gruppen sichtbar (Meta · Code · Beruflich · Web · Privat)
|
||
- [ ] Meta-Gruppe: lila Gradient mit `◉`-Bullet
|
||
- [ ] Klick auf jedes Board lädt korrektes Layout, Header zeigt Name, Goal, Pills (WIP-Limit/TP/SLE), Fokus-Stern
|
||
- [ ] Tab-Reihenfolge: Overview · Board · Analytics
|
||
- [ ] Default-Tab beim Start: Overview
|
||
- [ ] Banner oben wenn auf `file://` (nicht localhost:8765)
|
||
|
||
### Boards
|
||
- [ ] `+ Board` öffnet Modal mit Name (Pflicht), Goal, Gruppe-Select (+ "Neue Gruppe…"), Farb-Picker (8 Farben)
|
||
- [ ] User-Board zeigt `×` bei Hover (Default-Boards nicht)
|
||
- [ ] `+ Gruppe` legt leere Gruppe an (sichtbar mit "Leer — Board hinzufügen" Placeholder)
|
||
- [ ] Board-Drag in andere Gruppe → Group-Wechsel persistent
|
||
- [ ] Board-Drag auf konkretes Nav-Item → Reihenfolge innerhalb Gruppe persistent
|
||
- [ ] Gruppe-Header draggable → Gruppen-Reihenfolge ändert
|
||
- [ ] Ring-Badge (R0/R1p/R1w/R2/R3) togglet bei Klick durch alle Werte
|
||
- [ ] `↺ Reset`: bei Default-Board Spalten reset, bei User-Board Löschen-Confirm
|
||
- [ ] Board-Name + Goal per Klick im Header editierbar (Enter speichert, Esc revert)
|
||
|
||
### Settings (Pills im Header)
|
||
- [ ] WIP-Limit Pill editierbar (1-20)
|
||
- [ ] Throughput Pill editierbar (0.5-30, Dezimalen erlaubt)
|
||
- [ ] SLE-Tage Pill editierbar (1-180)
|
||
- [ ] Alle drei persistent nach Reload
|
||
|
||
### Karten (Board-View)
|
||
- [ ] `+ Karte…` Input: Enter fügt hinzu, Esc blurt
|
||
- [ ] Hover-Buttons: ⚑ togglet blocked (Karte rot), ↗ öffnet Promote-Modal, × löscht
|
||
- [ ] Drag col-body → col-body: verschiebt + setzt `movedAt`
|
||
- [ ] Drag col-body → exp-zone: verschiebt + setzt cos=expedite
|
||
- [ ] Drag exp-zone → exp-zone: verschiebt + bleibt expedite
|
||
- [ ] Drag exp-zone → col-body: demotet (cos entfernt)
|
||
- [ ] Drag in `done` setzt zusätzlich `doneAt`
|
||
- [ ] Karte > SLE-Tage in Spalte (außer done): rot leuchtender Glow + "ÜBERFÄLLIG"-Label
|
||
- [ ] Drag Card → eine der vier Ideen-Drop-Zonen (rechte Sidebar): erstellt Idee, entfernt Card
|
||
|
||
### Promote-to-Board
|
||
- [ ] ↗ auf Karte öffnet Modal mit Name = Task-Titel
|
||
- [ ] Hint zeigt Quell-Board und -Spalte korrekt
|
||
- [ ] Gruppe + Farbe vorbelegt mit Quell-Board
|
||
- [ ] Confirm → neues User-Board, Task aus Quelle entfernt
|
||
- [ ] Cancel → kein Board angelegt, Quell-Task bleibt
|
||
|
||
### Overview
|
||
- [ ] Hero-Block: Icon (oder Emoji-Fallback in Board-Farbe), Name, Tagline, Description, Badge-Reihe (Ring/Gruppe/Typ)
|
||
- [ ] Tagline + Description + Type per Single-Click editierbar (Click + tippen)
|
||
- [ ] Launch-Cards: **Single-Click öffnet URL** (oder MD-Viewer bei .md-URL); **Doppelklick auf Text aktiviert Edit-Modus**
|
||
- [ ] `× Entfernen` löscht Launch-Card
|
||
- [ ] `+ Launch-Card` fügt leere Card hinzu
|
||
- [ ] Was bisher geschah: per Click editierbar
|
||
- [ ] Tech-Stack-Pills: `×` löscht, `+ Tech` Input fügt hinzu
|
||
- [ ] Info-Rows: Label + Value editierbar, Copy-Btn (✓ Feedback), `×` löscht, `+ Zeile` fügt hinzu
|
||
- [ ] Secrets: Label + Value editierbar, Auge-Toggle (masked persistent), Copy-Btn, `×`, `+ Secret`
|
||
- [ ] Quick-Commands: Label + Cmd editierbar, Copy-Btn, `×`, `+ Command`
|
||
|
||
### MD-Viewer
|
||
- [ ] Voraussetzung: Aufruf via `http://localhost:8765/dev/kanban/index.html` (Server läuft)
|
||
- [ ] Klick auf `.md`-Launch-Card öffnet Modal mit gerendertem Markdown (Headings, Code, Tables, Listen)
|
||
- [ ] `↗ Tab` öffnet Roh-Inhalt in neuer Tab
|
||
- [ ] `× Schließen` oder Klick auf Overlay schließt Modal
|
||
- [ ] Bei `file://`-Aufruf: Fallback-Anleitung erscheint mit drei Optionen
|
||
|
||
### Analytics
|
||
- [ ] Tab-Wechsel ohne State-Verlust
|
||
- [ ] WIP-KPI färbt rot bei `> wipLimit`, amber bei `= wipLimit`, blau sonst
|
||
- [ ] Cycle Time, Queue ETA, Flow Efficiency mathematisch plausibel (siehe Spec oben)
|
||
- [ ] Monte Carlo Throughput-Input updated Live
|
||
- [ ] Status-Pill grün "↻ Real" wenn Done-Cards mit doneAt < 14d existieren, sonst grau "⊘ Statisch"
|
||
- [ ] Active Blockers Panel listet alle Tasks mit `blocked:true`
|
||
- [ ] Flow Distribution: 3 Balken (Ready/WIP/Done) korrekt skaliert
|
||
|
||
### Ideen
|
||
- [ ] Input + Enter fügt Idee am Anfang ein
|
||
- [ ] Filter-Buttons: ändern Anzeige UND Default-Tag für neue Ideen
|
||
- [ ] Hover-Buttons: `→` Promote-Modal (Spalten-Default = erste verfügbare, nie 'backlog'), `✕` löscht
|
||
- [ ] Drag Idee in col-body → Task entsteht, Idee verschwindet
|
||
- [ ] Drag funktioniert nur auf col-body, nicht in exp-zone
|
||
|
||
### Persistenz
|
||
- [ ] Reload behält: Boards, Spalten-States, Fokus, Ideen, Gruppen, Group-Order, alle Overrides (name/goal/wipLimit/tp/sle/overview)
|
||
- [ ] `localStorage.clear()` + Reload → alle Defaults zurück inkl. Seed-Ideen v3
|
||
- [ ] Alte 5-Spalten-States werden via `migrateCols` zu 3-Spalten konsolidiert
|
||
|
||
### Tool-Agnostik
|
||
- [ ] `~/.claude/CLAUDE.md` ist Symlink auf `AGENTS.md`
|
||
- [ ] `~/.claude/CLAUDE.md.bak` enthält den alten Inhalt vor Migration
|
||
- [ ] Ringsystem-Board zeigt alle relevanten MD-Files als Launch-Cards mit korrekten http://localhost:8765-URLs
|
||
|
||
---
|
||
|
||
## Bekannte Einschränkungen
|
||
|
||
- Karten-Sortierung INNERHALB einer Spalte nicht möglich (immer append)
|
||
- Card-Edit (Titel/Note ändern) nicht möglich — nur löschen + neu
|
||
- Gruppen können nicht umbenannt oder gelöscht werden
|
||
- Kein Card-Detail-View (kein Comments, Attachments, History)
|
||
- Kein Export
|
||
- Keine Tastatur-Shortcuts
|
||
- localStorage nicht synchronisiert — pro Browser/Gerät separat
|
||
- Keine Undo-Funktion
|
||
- CFD-Chart noch nicht implementiert (Ready-Task)
|
||
- Throughput-History akkumuliert sich erst über Zeit — bei frischem Start fallback auf statischen Wert
|
||
|
||
---
|
||
|
||
## Datei-Struktur
|
||
|
||
```
|
||
/Users/robinchoice/dev/kanban/
|
||
├── index.html # Die gesamte App
|
||
├── SPEC.md # Diese Datei
|
||
├── server.sh # Local HTTP Server (chmod +x)
|
||
└── assets/
|
||
└── doener.png # App-Icon (kopiert aus ~/dev/doener-app/iOS/.../AppIcon.appiconset/icon-1024.png)
|
||
```
|
||
|
||
---
|
||
|
||
## Setup (für neue Session / anderen Agent)
|
||
|
||
```bash
|
||
# 1. Server starten (für MD-Viewer)
|
||
nohup ~/dev/kanban/server.sh > /tmp/kanban-server.log 2>&1 &
|
||
|
||
# 2. Im Browser öffnen
|
||
open http://localhost:8765/dev/kanban/index.html
|
||
|
||
# 3. Stop wenn nötig
|
||
pkill -f "http.server 8765"
|
||
```
|
||
|
||
Wenn Server nicht laufen soll: einfach `open ~/dev/kanban/index.html` — Board funktioniert, aber MD-Viewer-Modal zeigt Fallback-Anleitung statt gerenderter Inhalte.
|