201 lines
7.6 KiB
Markdown
201 lines
7.6 KiB
Markdown
# ALICIA.md — NOVA Control Reparatur
|
||
|
||
**Auftrag:** Behebe 26 binäre Gates in `index.html`. Jedes Gate ist ein klares Ja/Nein-Kriterium — erst erfüllt, wenn nachweisbar wahr.
|
||
|
||
**Repo:** `git@git.datenhimmel.work:danielkrause/nova-control.git`
|
||
**Branch:** `master`
|
||
**Datei:** Nur `index.html` — eine Datei, kein Framework, keine Libs, kein CDN, offline.
|
||
|
||
---
|
||
|
||
## Arbeitsweise
|
||
|
||
1. **Gate für Gate.** Nicht mehrere auf einmal. Ein Gate → implementieren → testen → commit.
|
||
2. **Vor jedem Commit:** `index.html` im Browser öffnen und das Gate manuell verifizieren.
|
||
3. **Commit-Message:** `fix: P0.1 Datei-Dialog entfernt` o.ä.
|
||
4. **Push nach jeder Phase** (P0, P1, P2) — nicht nach jedem einzelnen Gate.
|
||
|
||
## Reihenfolge (P0 → P1 → P2)
|
||
|
||
### P0 — BLOCKER (zuerst, weil App sonst beim Start kaputt)
|
||
|
||
**P0.1 — Datei-Dialog**
|
||
- Zeile mit `document.getElementById('imp').click();` **löschen**
|
||
- Test: Seite laden → KEIN Datei-Dialog
|
||
|
||
**P0.2 — Command-Palette**
|
||
- `rp()` wird nie aufgerufen → `cmds` bleibt `[]`
|
||
- `rp()` auf ≥8 Befehle erweitern: Board, Streaks, Insights, Neues Task, Import, Export, Reset/Demo, 500 Tasks
|
||
- `ld()` ruft am Ende `rp()` auf, dann `inipal()` beim Öffnen der Palette
|
||
- Tasks dynamisch als anspringbare Einträge in die Liste
|
||
- Test: Cmd+K → Liste zeigt ≥8 Einträge
|
||
|
||
**P0.3 — Dark Mode**
|
||
- `:root` hat nur Hell-Werte, `[data-theme="dark"]`-Block fehlt
|
||
- CSS: `[data-theme="dark"]` mit `--bg`, `--surface`, `--text`, `--border`
|
||
- `at()`: `matchMedia('(prefers-color-scheme:dark)').addEventListener('change', ...)` für Live-Reaktion
|
||
- `localStorage` für Persistenz (existiert via `sv()`)
|
||
- Test: 🌙 klicken → Hintergrund dunkel. Reload → bleibt dunkel.
|
||
|
||
### P1 — KERN-FEATURES
|
||
|
||
**P1.1 — Maus-Drag & Drop**
|
||
- HTML5 DnD API: `draggable="true"` auf `.task`
|
||
- `dragstart`/`dragover`/`drop` Events
|
||
- Drop-Indikator (gestrichelter Rahmen oder Platzhalter)
|
||
- Inter-Spalte (Status wechselt) + Intra-Spalte (Reihenfolge)
|
||
- Nach Drop: `sv()` + `rv()`
|
||
- Test: Task von Backlog nach Aktiv ziehen. Nach Reload noch da.
|
||
|
||
**P1.2 — Tastatur-DnD**
|
||
- Fokussiertes Task: Ctrl+Alt+Pfeiltasten
|
||
- ←→: Spalte wechseln | ↑↓: Position in Spalte
|
||
- `<div aria-live="polite">` für Status-Ansagen
|
||
- Test: Nur Tastatur, Task durch alle 4 Spalten bewegen.
|
||
|
||
**P1.3 — Feld-Schema**
|
||
- `op()`-Create speichert Fälligkeit als `du`, Board liest `d`
|
||
- `du` → `d` vereinheitlichen (in Create + Edit)
|
||
- `ldDemo()` und Render prüfen: benutzen die `d`?
|
||
- Test: Task mit Datum anlegen → Reload → Datum noch da.
|
||
|
||
**P1.4 — Streak-Berechnung**
|
||
- Pro Habit: aktuelle Serie + längste Serie
|
||
- Regeln: Wert > 0 = erfüllt. Tag mit 0 = Bruch. Heute noch nicht erfüllt = kein Bruch.
|
||
- Anzeige im Streak-View
|
||
- Test: Serie bricht bei 0, läuft weiter wenn heute noch kein Wert.
|
||
|
||
**P1.5 — Export**
|
||
- `exportData()`: `{version:1, tasks, habits, theme}` als JSON-Blob → Download
|
||
- Command "Export" in Palette
|
||
- Import validiert `version` + `tasks` Array
|
||
- Test: Export → localStorage löschen → Import → identischer Zustand.
|
||
|
||
**P1.6 — Zweiter Chart + Trend-Wochen**
|
||
- `<canvas id="chart2">` für Donut (Prioritätsverteilung)
|
||
- Trend-Chart: Monate → Wochen umstellen
|
||
- Datenbasis Trend: `df` (Abschlussdatum)
|
||
- Legende, Labels, Empty-State
|
||
- Test: Insights zeigt 2 Charts. Trend in Wochen.
|
||
|
||
**P1.7 — Listener-Leak + Fokusverlust**
|
||
- `rb()`: KEIN `innerHTML` = Toolbar + alles neu
|
||
- Toolbar (Suche + Filter) EINMAL im HTML, nicht pro `rb()`
|
||
- Event-Delegation auf `#board-section` EINMAL binden
|
||
- Suche: `display:none` statt DOM-Neuaufbau
|
||
- Test: 10× Views wechseln → Modal öffnet 1×. Tippen in Suche → Fokus bleibt.
|
||
|
||
### P2 — POLITUR
|
||
|
||
**P2.1 — Heatmap 26 Wochen**
|
||
- Spalten=Wochen, Zeilen=Mo..So, 26 Wochen zurück
|
||
- Hover-Tooltip mit Datum + Wert
|
||
- Test: Kein 28-Tage-Streifen mehr, Wochen-Grid sichtbar.
|
||
|
||
**P2.2 — Responsive**
|
||
- `@media (max-width: 768px)`: Layout einspaltig
|
||
- `@media (max-width: 480px)`: Board untereinander
|
||
- `overflow-x: auto` NUR auf `.board`, nicht `body`
|
||
- Test: 360px Breite → kein Body-Scroll.
|
||
|
||
**P2.3 — prefers-reduced-motion**
|
||
- `@media (prefers-reduced-motion: reduce) { ... }`
|
||
- Animationen deaktivieren (Toast, Drag-Transitions)
|
||
- Test: OS-Einstellung "Reduzierte Bewegung" → keine Animationen.
|
||
|
||
**P2.4 — Focus-Trap**
|
||
- Modal + Palette: Tab/Shift+Tab zyklisch im Dialog
|
||
- ESC schließt + Fokus zurück auf Auslöser
|
||
- Test: Modal offen → Tab kreist. ESC → Fokus auf Button davor.
|
||
|
||
**P2.5 — Palette-Tastatur**
|
||
- Keydown auf `#pal-q` (Eingabefeld) statt `#pal-list`
|
||
- ↑/↓ navigieren Liste, Enter führt aus
|
||
- Fokus bleibt im Eingabefeld
|
||
- Test: Pfeiltasten bei Fokus im Suchfeld.
|
||
|
||
**P2.6 — Hash-Routing**
|
||
- Navigation setzt `location.hash = '#/' + view`
|
||
- `hashchange`-Event schaltet View
|
||
- Beim Laden: View aus Hash setzen
|
||
- Test: `#/insights` → Insights-View. Reload bleibt. Zurück-Button.
|
||
|
||
**P2.7 — 500 Tasks**
|
||
- `gen500()`: 500 Tasks generieren
|
||
- Command in Palette
|
||
- Performance: Batch-Rendering, kein 500× Einzel-Push
|
||
- Test: 500 Tasks → Board flüssig, Suche filtert sofort.
|
||
|
||
**P2.8 — Robustheit**
|
||
- `ld()`: `nv_t` validieren → `Array.isArray()` + try/catch → Fallback `[]`
|
||
- Import: Jeden Task auf `id`, `tl`, `st` prüfen
|
||
- Fehlerhafte Einträge → Meldung, bestehende Daten bleiben
|
||
- Test: Kaputtes JSON importieren → Fehlermeldung, keine Daten verloren.
|
||
|
||
---
|
||
|
||
## Git-Workflow
|
||
|
||
```bash
|
||
git clone git@git.datenhimmel.work:danielkrause/nova-control.git
|
||
cd nova-control
|
||
|
||
# Gate bearbeiten...
|
||
git add index.html
|
||
git commit -m "fix: P0.1 Datei-Dialog entfernt"
|
||
|
||
# Nach jeder Phase:
|
||
git push
|
||
|
||
# Nach Abschluss:
|
||
git tag v1.0 # alle 26 Gates geschlossen
|
||
git push --tags
|
||
```
|
||
|
||
---
|
||
|
||
## Constraints (unveränderlich)
|
||
|
||
### Technisch
|
||
- ❌ Keine zweite Datei (kein .css, kein .js)
|
||
- ❌ Keine externen Libs/CDNs (kein jQuery, kein React, kein Bootstrap)
|
||
- ❌ Kein Build-Step, kein npm
|
||
- ✅ CSS `<style>` im `<head>`
|
||
- ✅ JS `<script>` am Ende von `<body>`
|
||
- ✅ `localStorage` für Persistenz
|
||
- ✅ Eine HTML-Datei, die im Browser per `file://` läuft
|
||
|
||
### Coding-Regeln (bindend!)
|
||
|
||
**Variablen & Funktionen — lesbare Namen**
|
||
- ❌ `C`, `ts`, `fm`, `sv`, `ld`, `at`, `rv`, `rb`, `op`, `cl`, `rs`, `ri`, `rp`, `pf`, `ie`
|
||
- ✅ `COLUMNS`, `showToast`, `formatDate`, `saveState`, `loadState`, `applyTheme`, `renderView`, `renderBoard`, `openModal`, `closeModal`, `renderStreaks`, `renderInsights`, `registerPalette`, `previousFocus`, `isEditing`
|
||
- **Jede Variable und Funktion MUSS einen selbsterklärenden Namen haben.** Keine Abkürzungen unter 4 Zeichen.
|
||
|
||
**JavaScript**
|
||
- ✅ `const`/`let` — NIE `var`
|
||
- ✅ `===` statt `==`
|
||
- ✅ Template-Literals `` `Hallo ${name}` `` statt `'Hallo ' + name`
|
||
- ✅ Arrow-Funktionen `() => {}` wo sinnvoll
|
||
- ✅ `for...of` statt `for(var i=0;...)` wo möglich
|
||
- ❌ Kein `eval()`, kein `innerHTML` mit ungeprüftem Input
|
||
- ❌ Keine globalen Variablen (alles in IIFE oder Modul-Scope)
|
||
|
||
**CSS**
|
||
- ✅ CSS-Variablen (`var(--bg)`) nutzen — NIEMALS Farben hartkodieren
|
||
- ✅ Dark Mode NUR über `[data-theme="dark"]` und `prefers-color-scheme`
|
||
- ✅ `rem`/`em` für Schrift, `px` nur für Borders, `%`/`fr`/`vh`/`vw` für Layout
|
||
- ❌ Kein `!important`
|
||
- ❌ Keine Inline-Styles im HTML (alles im `<style>`-Block)
|
||
|
||
**HTML**
|
||
- ✅ Semantisch: `<aside>`, `<nav>`, `<main>`, `<section>`, `<dialog>` wo passend
|
||
- ✅ ARIA-Labels für interaktive Elemente ohne sichtbaren Text
|
||
- ✅ `tabindex` nur wo nötig, korrekte Reihenfolge
|
||
- ❌ Kein `<div onclick="...">` — immer `addEventListener` in JS
|
||
|
||
**Kommentare**
|
||
- ✅ Jede Funktion hat EINEN Satz darüber, was sie tut
|
||
- ✅ Komplexe Logik (Streak, DnD, Chart) hat 2-3 Zeilen Erklärung
|
||
- ❌ Keine auskommentierten Code-Blöcke
|