Files
kanban/SPEC.md
Robin Choice 02ac470eff Initial commit — Kanban-App migriert von ~/.kanban nach ~/dev/kanban
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>
2026-05-19 23:30:19 +02:00

538 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 03, 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.