# Zeitgeist App Architecture

Learning tracker app on ZimaOS. Multi-page PWA with Pomodoro timer, Anki flashcards, Notes vault, and exam manager.

## Deployment

- **Container**: `Zeitgeist` (node:20-alpine)
- **Port**: `8765` → `3000` (host → container)
- **Code location**: `/media/HDD_1TB/Zeitgeist` (bind-mount → `/app`)
- **Compose**: `/var/lib/casaos/apps/Zeitgeist/docker-compose.yml`
- **Restart**: `sudo docker restart Zeitgeist`

## File Map

| File | Role | Lines |
|------|------|-------|
| `server.js` | Express backend, /api/data GET/POST, backup rotation, image upload | 171 |
| `zeitgeist.html` | Main tracker: day cards, Pomodoro, stats view | ~1750 |
| `anki.html` | Anki flashcard system | ~2500 |
| `vault.html` | Hierarchical notes app | ~2150 |
| `pruefungsmanager.html` | LL.B. exam progress tracker (NO header-stats) | ~824 |
| `shared.js` | ZG.save(), ZG.adopt(), ZG.initTheme(), ZG.toast() | 132 |
| `shared.css` | Toast styles, reduced-motion | 35 |
| `sw.js` | PWA service worker | — |
| `manifest.json` | PWA manifest | — |

## Data Architecture

- **Storage**: `localStorage` + server sync via `ZG.save()` / `ZG.adopt()`
- **Server**: `/api/data` GET/POST — single JSON blob with timestamped keys
- **Keys**: `zeitgeist-v2` (check data), `zeitgeist-v2-notes` (slot notes), `zeitgeist-work-v2` (work mode)
- **Schema**: `{ "YYYY-MM-DD": [25, 0, 25, 40, ...] }` — array of 10 slots per day
- **Backups**: Rotating (data.json.1–10) + daily snapshots (30 kept)

## Key Functions (defined per-page, not shared)

- `dkey(date)` → `"YYYY-MM-DD"` string
- `sumRow(data, key)` → total minutes for a day
- `row(data, key)` → normalized 10-slot array
- `stats(data)` → `{ today, total, streak }`
- `weekMinutes(data)` → Mon–Sun total (added 2026-06-18)
- `today()`, `todayKey()`, `getDays()` → date helpers

## Design System

- **Fonts**: Lora (serif, headings/wordmark) + system-ui (body)
- **Colors**: Warm editorial — `#F6F5F1` bg, `#FFFFFF` cards, `#1A1917` text
- **Dark mode**: `html.dark` class, `#18171A` bg, `#222026` cards
- **Accent**: Indigo `#8B5CF6` (free-time checks), Emerald `#22C55E` (standard checks)
- **CSS vars**: `--bg`, `--card`, `--border`, `--text`, `--text-2`, `--text-3`, `--ck-std`, `--ck-free`, `--shadow-sm`, `--shadow-md`, `--r:14px`
- **Header**: Sticky, backdrop-blur, 62px + safe-area, app-switcher nav

## Header Stats Pattern

All pages except pruefungsmanager have identical header-stats HTML:
```html
<div class="header-stats">
  <div class="hstat"><div class="hstat-val green" id="s-today">0 min</div><div class="hstat-label">Heute</div></div>
  <div class="hstat"><div class="hstat-val" id="s-week">0 min</div><div class="hstat-label">Diese Woche</div></div>
  <div class="hstat"><div class="hstat-val" id="s-total">0 min</div><div class="hstat-label">Gesamt</div></div>
  <div class="hstat"><div class="hstat-val" id="s-streak">0</div><div class="hstat-label">Serie</div></div>
</div>
```

Each page has its own `updateHeaderStats()` function. When adding header features, ALL THREE pages (zeitgeist, anki, vault) must be updated. pruefungsmanager.html has its own ECTS header — never add stats there.

## Zeitgeist Page Specifics

- **View states**: `ZV = 'track'` | `'stats'` (toggled via 📊 button or `#stats` hash)
- **pastVisible**: Controls how many past days shown (default 10, "Mehr laden" button)
- **Day cards**: `.day-card` with `.is-today` (green), `.is-gold` (all 10 done), `.is-rainbow` (>180 min)
- **Checks**: 10 circles per day, left-click = 25 min, right-click/long-press = context menu (free time, note, remove)
- **Pomodoro**: 25-min timer, auto-records to first empty slot on completion, partial on stop
- **Pomodoro state**: Shared across tabs via BroadcastChannel (`zeitgeist-pomo`)

## Modification Checklist

When adding features to Zeitgeist:
1. Read all affected HTML files completely (they're large)
2. Check which pages share the pattern (header stats = 3 pages, day cards = 1 page, etc.)
3. Follow existing CSS variable naming and DOM id patterns
4. Delegate coding to kimi-k2.7-code subagent with detailed spec
5. Restart container: `sudo docker restart Zeitgeist`
6. Verify with curl against port 8765
7. Tell user to hard-refresh (Ctrl+Shift+R) — PWA caches aggressively
