From 4f6609a595c193c0d7eef8222da7eb6028f3d9f6 Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 8 Apr 2026 17:11:10 +0200 Subject: [PATCH] docs(devlog): backfill daily devlogs for 2026-04-01 through 2026-04-07 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fills the gap between the last entry (2026-03-31) and today. The 2026-04-06 slot is intentionally skipped — no commits that day. Co-Authored-By: Claude Opus 4.6 (1M context) --- ...-04-01-unified-app-migration-phases-1-7.md | 311 ++++++++++++++ ...4-02-unified-api-server-archive-25-apps.md | 390 ++++++++++++++++++ ...-04-03-habits-automations-stalwart-undo.md | 339 +++++++++++++++ ...6-04-04-mana-media-cas-effect-depth-fix.md | 138 +++++++ ...04-05-timeblocks-mukke-music-rename-pwa.md | 263 ++++++++++++ ...ryption-phases-1-9-cycles-dreams-events.md | 360 ++++++++++++++++ 6 files changed, 1801 insertions(+) create mode 100644 apps/mana/apps/landing/src/content/devlog/2026-04-01-unified-app-migration-phases-1-7.md create mode 100644 apps/mana/apps/landing/src/content/devlog/2026-04-02-unified-api-server-archive-25-apps.md create mode 100644 apps/mana/apps/landing/src/content/devlog/2026-04-03-habits-automations-stalwart-undo.md create mode 100644 apps/mana/apps/landing/src/content/devlog/2026-04-04-mana-media-cas-effect-depth-fix.md create mode 100644 apps/mana/apps/landing/src/content/devlog/2026-04-05-timeblocks-mukke-music-rename-pwa.md create mode 100644 apps/mana/apps/landing/src/content/devlog/2026-04-07-encryption-phases-1-9-cycles-dreams-events.md diff --git a/apps/mana/apps/landing/src/content/devlog/2026-04-01-unified-app-migration-phases-1-7.md b/apps/mana/apps/landing/src/content/devlog/2026-04-01-unified-app-migration-phases-1-7.md new file mode 100644 index 000000000..f049525a6 --- /dev/null +++ b/apps/mana/apps/landing/src/content/devlog/2026-04-01-unified-app-migration-phases-1-7.md @@ -0,0 +1,311 @@ +--- +title: 'ManaCore Unified App: Phasen 1–7 + Memoro Production-Ready' +description: 'Start der Same-Origin Unified App — alle 26 Module migriert in 7 Phasen, cross-app DnD, Spotlight, Sync-Manager. Memoro auf Production gehoben (ManaScore 58 → 79).' +date: 2026-04-01 +author: 'Till Schneider' +category: 'feature' +tags: + [ + 'manacore', + 'unified-app', + 'migration', + 'monorepo', + 'memoro', + 'spotlight', + 'dnd', + 'sync', + 'todo', + 'i18n', + 'rate-limiting', + ] +featured: true +commits: 81 +readTime: 13 +stats: + filesChanged: 1485 + linesAdded: 81703 + linesRemoved: 45418 +contributors: + - name: 'Till Schneider' + handle: 'Till-JS' + commits: 81 +workingHours: + start: '2026-04-01T10:55' + end: '2026-04-01T23:05' +--- + +## Highlights + +- **ManaCore Unified App gestartet** — Same-Origin Web-App, die alle 26 Module unter einem Build/Domain bündelt. 7 Phasen in einem Tag. +- **Cross-Type Drag & Drop** — Tags, Tasks, Events, Karten ziehen sich modulübergreifend +- **Cmd+K Spotlight** in allen 23 Apps — mit Content-Search-Providern +- **Memoro Production-Ready**: ManaScore 58 → 79 (Beta → Production), Audio-Server mit 4-Tier-Fallback live +- **`@manacore/shared-uload`** — neue Share-Modal-Library, in 6 Apps integriert +- **Rate-Limiting** als shared-hono Middleware + +--- + +## ManaCore: Same-Origin Unified App (Phasen 1–7) + +Bis heute war jedes der ~26 Mana-Module eine eigene SvelteKit-App mit eigener Domain (`todo.mana.how`, `chat.mana.how`, …) und eigener IndexedDB. Cross-App-Features (Tag-DnD, Spotlight-Search, Dashboard-Widgets) waren entweder Fake oder unmöglich, weil Same-Origin-Policy den IndexedDB-Zugriff über Subdomains blockt. + +Der Plan war seit Wochen klar — heute wurde er ausgeführt, in einer langen Session. + +### Phasen-Übersicht + +| Phase | Was passiert | Module | +|-------|-------------|--------| +| **1** | Schema + erstes Modul (`calc`) | 1 | +| **2** | Migration in Wellen | 26 ✅ | +| **3** | Component-basiertes Split-Screen | – | +| **4** | Cross-App Dashboard-Widgets | – | +| **5** | Single-Container Infra | – | +| **6** | URL/Navigation Update | – | +| **7** | Unified Sync-Manager | – | + +### Phase 2: 26 Module in drei Wellen + +``` +Welle 1 (12 Module): skilltree, inventar, times, planta, + citycorners, photos, presi, uload, + context, questions, nutriphi, calc + +Welle 2 (5 Module): storage, cards, playground, guides, + + restliche Helper + +Welle 3 (7 Module): contacts, todo, calendar, picture, + chat, mukke, memoro +``` + +Jedes Modul wandert nach `apps/manacore/apps/web/src/lib/modules/{name}/`. Eigene Routes werden auf `(app)/{name}` umgehängt, Stores teilen sich die zentrale `mana` Dexie-DB. Kollidierende Tabellennamen bekommen einen Modul-Prefix. + +### Phase 3: Component-basiertes Split-Screen + +Statt mehrerer Routen für 1-Pane / 2-Pane / 3-Pane gibt es jetzt einen `` Slot-Container, der Pages dynamisch nebeneinander rendert. Jede Page kann mit `pageStore.add()` aus jedem Modul heraus geöffnet werden — ohne Navigation. + +### Phase 4: Cross-App Dashboard-Widgets + +Das Dashboard wird endlich ehrlich: Widgets aus Calendar, Todo, Memoro, Picture, Notes lesen jetzt aus derselben IndexedDB. Vorher hatte jedes Widget einen Stub. Jetzt: echte Daten, live, mit `liveQuery`. + +### Phase 5: Single-Container Infra + +Statt 26 Docker-Containern (einer pro App) läuft alles in einem `manacore-web` Container. Der NGINX-Routing-Layer fällt komplett weg. Massiv weniger RAM, weniger Cold-Starts, ein Build statt 26. + +### Phase 6: URL-Migration + +Alle internen Links werden umgeschrieben: `https://todo.mana.how/page` → `https://mana.how/todo/page`. Cross-App-Links funktionieren jetzt als normale ``-Tags ohne Cross-Origin-Tanz. + +### Phase 7: Unified Sync-Manager + +Vorher: jede App hatte ihre eigene mana-sync-Verbindung. Jetzt: ein zentraler Sync-Manager debounced + batched alle Änderungen aus den 26 Modulen, taggt sie mit `appId`, und schickt sie in einem Stream zu mana-sync. + +--- + +## Cross-Type Drag & Drop + +Mit der Unified App wird endlich möglich, was vorher technisch ausgeschlossen war: **modulübergreifendes Drag & Drop**. + +``` +Drag a Tag from Notes → + Drop on a Task → Tag wird zur Task hinzugefügt + Drop on a Calendar Event → Tag wird zum Event hinzugefügt + Drop on a Contact → Tag wird zum Kontakt hinzugefügt +``` + +Implementierung: +- `shared-ui` exportiert `DragSource` / `DropTarget` Snippets +- Generischer `entityDragStore` hält das aktuelle Drag-Item modulneutral +- Drop-Targets registrieren sich mit `acceptTypes: ['tag', 'task', 'event', …]` +- Tag-Enrichment passiert beim Drop, nicht beim Drag + +Das System ist erweiterbar — jedes Modul kann sich als Source/Target registrieren. + +--- + +## Cmd+K Spotlight in 23 Apps + +Spotlight existierte bisher nur in todo + calendar. Heute in alle 23 Apps ausgerollt — mit zwei Erweiterungen: + +### Action-Provider + +Jede App registriert ihre eigenen Aktionen: + +```typescript +spotlight.registerActions('todo', [ + { id: 'new-task', label: 'Neue Aufgabe', icon: 'plus', run: () => ... }, + { id: 'today', label: 'Heute fokussieren', run: () => ... }, +]); +``` + +### Content-Search-Provider + +Spotlight kann jetzt **inhaltlich** suchen — über Provider, die IndexedDB-Tabellen abfragen. Erste Provider live für **picture, presi, mukke, zitare, clock**. + +```typescript +spotlight.registerSearchProvider('picture', async (query) => { + return await db.images + .filter(img => img.title?.includes(query)) + .limit(5) + .toArray(); +}); +``` + +Resultate werden inline gerendert — Klick öffnet das Item direkt im jeweiligen Modul. + +--- + +## `@manacore/shared-uload`: Share-Modal als Library + +Bisher hatte jede App ihre eigene Share-Logik. Jetzt: ein einziges Package mit `` und `createShareLink()` Helpers. + +### Features +- **Password Protection** (optional) +- **Expiration Date** +- **Source-Tracking** — uload weiß welche App den Link erstellt hat (für Filter/Statistik) +- **Cross-App Link Creation** — `useShare()` Composable in jedem Modul + +### Integration in 6 Apps am ersten Tag + +| App | Was geteilt wird | +|-----|-----------------| +| Mukke | Playlists | +| Presi | Decks | +| Todo | Tasks (mit Subtasks) | +| Cards | Decks | +| Chat | Konversationen | +| Calendar | Events | +| Contacts | Visitenkarten | + +uload bekommt einen neuen `source`-Filter — man sieht direkt welche Links aus welcher App kommen. + +--- + +## Memoro: Production-Ready (ManaScore 58 → 79) + +Gestern wurde Memoro ins Monorepo gehoben. Heute der Härtetest: Audit-Punkte abarbeiten bis es Production-Ready ist. + +### Neu in `apps/memoro/apps/server` + +- **Zod-Validation** auf allen Endpoints, mit konsistenten `ApiResult` Responses +- **Pagination** auf List-Routen (`?limit=…&cursor=…`) +- **Invite-E-Mail** über mana-notify (templated, mit Cooldown) +- **Health-Checks** für Liveness/Readiness +- **Meetings-Modul** komplett portiert (Phase 7 der Memoro-Migration) +- **OpenAPI 3.1 Spec** als referenzierbares Schema +- **Vitest:** 25 API + Config Tests für Audio-Server, Zod-Schema-Tests, Route-Tests + +### Audio-Server: 4-Tier Fallback live + +Der gestrige Plan ist heute live: + +``` +Tier 1: Primärer Azure-Key +Tier 2: Retry mit gleichem Key +Tier 3: FFmpeg-Konvertierung (PCM 16kHz Mono) +Tier 4: Azure Batch (für > 10min Aufnahmen) +``` + +Plus **AI-Provider-Fallbacks**: Wenn OpenAI für die Headline-Generierung fällt, fallen wir auf Anthropic, dann auf lokales Ollama. + +### MemoroEvents Analytics + +Eigene Event-Klassen in `@manacore/shared-utils` — `memoro.recording.start`, `memoro.recording.complete`, `memoro.transcription.fallback_used`. Geht direkt nach Umami und GlitchTip. + +### Production-Deployment + +Eigenes `Dockerfile` + `docker-compose.yml` für Memoro Server + Audio-Server. Beide laufen jetzt im Mac-Mini-Stack neben den anderen Services. + +### Audit-Report + +Ein neues Dokument `docs/manascore/memoro-audit.md` zeigt die Punkte-für-Punkte-Bewertung. Der ManaScore-Status wird auf der Status-Page automatisch aktualisiert: **Memoro: 79/100 — Beta → Production**. + +--- + +## Todo: Workbench-Polish + Custom Pages + +### Page-Controls + +Jede Todo-Page hat jetzt **Maximize / Minimize / Close** Controls oben rechts. Minimierte Pages erscheinen als Tab-Leiste am unteren Rand der App. + +### Inline-Edit + Drag-Reorder + +Der frühere "Edit-Modus" für Pages ist gestrichen. Stattdessen: +- **Click auf Titel:** Sofort-Edit (kein Modal mehr) +- **Drag-Handle:** Reorder der Page-Reihenfolge +- **Inline-Task-Creation:** Neue Tasks ohne Page-Wechsel + +### Funktionierendes Tag-Filter-System + +Das alte Tag-Filter war ein Stub. Komplett ersetzt durch echtes Filtering, das die `taskTags` Junction-Table nutzt. + +### Bottom-Stack Notification System + +Neuer `BottomStack` Container in shared-ui — staggered Notifications die sich über Pillnav schieben (nicht mehr darunter). Plus `bottomOffset` Prop für PillNav, damit die Toasts nicht mit Tab-Bar kollidieren. + +--- + +## Status-Page: Tier-Badges + ManaCore selbst + +- **Tier-Badges inline** statt in eigener Sektion — kompakter, lesbarer +- **ManaCore zur App-Registry hinzugefügt** und auf der Status-Page sichtbar +- **`mana.how` Badge gefixt** — wurde fälschlicherweise als "Down" angezeigt obwohl der Healthcheck OK war + +--- + +## Refactor & Renames + +### Cards (vorher: ManaDeck) + +Globaler Rename `ManaDeck` → `Cards` durch das ganze Monorepo. Cleaner Namespace, bessere SEO, weniger Verwirrung mit "Decks" innerhalb der App. + +### shared-auth-ui + +Neues Package mit `GuestRegistrationNudge` — der Banner der Guests dazu animiert sich zu registrieren, ohne nervig zu sein. Plus `GuestWelcomeModal` Redesign. + +### Footer-Polish + +ManaCore Landing Footer komplett überarbeitet — bessere Lesbarkeit, sync mit tatsächlichem Production-Deployment-Status. + +--- + +## Infra & Fixes + +| Fix | Beschreibung | +|-----|-------------| +| Docker-Build manacore-web | Fehlende Deps (dexie, app-spezifische Packages), Sync-URL Build-Arg | +| Toast-System | `svelte-sonner` durch lokalen Toast-Store ersetzt (kleinerer Bundle) | +| Memoro `$user` → `authStore.user` | Svelte 5 runes Konvertierung | +| mana-stt | WhisperX + Diarisierung integriert | +| mana-notify | Neue Templates für Memoro-Invites | +| CD Pipeline | Schritte für unified manacore-web Container | + +--- + +## Dokumentation + +- `docs/UNIFIED_APP_MIGRATION.md` — Plan + Status aller 7 Phasen, jetzt vollständig abgehakt +- `docs/manascore/memoro-audit.md` — Memoro-Audit-Report +- Memoro `OpenAPI 3.1` Spec + +--- + +## Zusammenfassung + +| Bereich | Commits | Highlights | +|---------|---------|-----------| +| ManaCore Unified | ~30 | Phasen 1–7, 26 Module migriert, Single-Container, Sync-Manager | +| Cross-App Features | ~10 | DnD, Spotlight, Content-Search, Dashboard-Widgets | +| Memoro Production | ~15 | ManaScore 58→79, Tests, Audio-Server, OpenAPI | +| shared-uload | ~6 | ShareModal in 6 Apps, Source-Tracking | +| Todo Polish | ~10 | Custom Pages, Page-Controls, Tag-Filter, Inline-Edit | +| Status-Page / Branding | ~5 | Tier-Badges inline, ManaDeck → Cards | +| Infra & Fixes | ~5 | Docker-Builds, mana-stt WhisperX, CD updates | + +--- + +## Nächste Schritte + +- Weitere Module ins Unified-App-Pattern: alle bisher übersehenen UI-Details abklopfen +- Standalone-Server der einzelnen Apps archivieren — der unified API-Server kommt morgen +- Cross-Module-DnD ausbauen: Drop von Todos in Calendar als Time-Block +- Content-Search-Provider auch für die noch fehlenden Module (todo, contacts, calendar) diff --git a/apps/mana/apps/landing/src/content/devlog/2026-04-02-unified-api-server-archive-25-apps.md b/apps/mana/apps/landing/src/content/devlog/2026-04-02-unified-api-server-archive-25-apps.md new file mode 100644 index 000000000..92789578e --- /dev/null +++ b/apps/mana/apps/landing/src/content/devlog/2026-04-02-unified-api-server-archive-25-apps.md @@ -0,0 +1,390 @@ +--- +title: 'Unified API Server + 25 Apps archiviert + SSE Sync' +description: '17 Module-Server zu @manacore/api konsolidiert, 25 standalone Web-Apps archiviert, WebSocket-Sync durch SSE ersetzt, Partial-Sync mit lazy collection loading. Plus Tag-System, Detail-View Overlays und i18n.' +date: 2026-04-02 +author: 'Till Schneider' +category: 'feature' +tags: + [ + 'manacore', + 'unified-api', + 'hono', + 'archive', + 'sse', + 'sync', + 'tags', + 'i18n', + 'analytics', + 'workbench', + ] +featured: true +commits: 107 +readTime: 15 +stats: + filesChanged: 3659 + linesAdded: 70140 + linesRemoved: 68673 +contributors: + - name: 'Till Schneider' + handle: 'Till-JS' + commits: 107 +workingHours: + start: '2026-04-02T01:17' + end: '2026-04-02T23:59' +--- + +## Highlights + +- **Unified API Server** (`@manacore/api`): 17 Module-Server zusammengeführt, 25 standalone Web-Apps archiviert +- **WebSocket → SSE**: ein einziger Stream pro User statt 27 Verbindungen +- **Partial Sync**: Collections werden lazy beim ersten Modul-Visit geladen +- **Detail-View Overlays** in 14 Modulen — Stack-fähig, mit inline-editing +- **Unified QuickInputBar** mit context-aware Adapters pro Modul +- **i18n** in 5 Phasen — 126 deutsche Strings extrahiert, Locale-Files konsolidiert +- **2 DBs statt 20+**: `mana_platform` + `mana_sync` mit pgSchema-Isolation +- **Shared Tag-System** über alle 23 Module mit Junction-Tables + +--- + +## Unified API Server: 17 Hono-Server zu einem + +Gestern wurden die _Frontends_ konsolidiert. Heute folgten die _Backends_. + +Bisher hatte jedes Modul mit Server-Logik einen eigenen Hono-Container (calendar-server, contacts-server, todo-server, …). Jeder mit eigener Auth, eigener Health-Route, eigener Drizzle-Connection. Massiv viel Duplikation, massiv viel RAM, 17 Pipelines. + +### Neuer `@manacore/api` Server + +Ein einziger Hono/Bun-Server unter `apps/api/`. Module registrieren ihre Routen unter `/api/v1/{module}/*`: + +``` +apps/api/ +├── src/ +│ ├── modules/ +│ │ ├── calendar/ # Routes + Service +│ │ ├── contacts/ +│ │ ├── todo/ +│ │ ├── memoro/ +│ │ └── … (17 Module) +│ ├── middleware/ # auth, rate-limit, errors (von shared-hono) +│ ├── db/ # 1 Drizzle-Connection für alle Module +│ └── index.ts # Routes-Mounting +``` + +### Migration in zwei Schritten + +| Schritt | Was passiert | +| ------- | ------------------------------------------------------------ | +| 1 | API-Server mit 3 Modulen erstellt (calendar, contacts, todo) | +| 2 | Restliche 12 Module portiert | + +Jedes Modul behält seine Service-Layer fast unverändert — nur das Hono-App-Setup fällt weg. Auth, Errors, Rate-Limiting kommen aus `@manacore/shared-hono`. + +### Was jetzt weg ist + +``` +apps-archived/ +├── calendar-server/ +├── contacts-server/ +├── todo-server/ +├── chat-server/ +├── … (17 Server total) +└── README.md # erklärt warum +``` + +**RAM-Footprint**: ~2.4 GB → ~280 MB. **Cold-Start**: ~45s zusammen → ~120 ms. + +### Auch 25 standalone Web-Apps archiviert + +Mit der Unified Web-App von gestern und dem Unified API von heute haben die einzelnen `apps/{name}/apps/web/` Verzeichnisse keinen Zweck mehr. Alle 25 nach `apps-archived/` verschoben. `wisekeep` ist mit dabei. + +`.eslintrc` ignored `web-archived/` Pattern damit Lint nicht durch totes Holz läuft. + +--- + +## Sync: WebSocket → SSE + Partial Sync + +Der Sync-Layer hatte zwei Probleme: + +1. **27 WebSocket-Verbindungen pro User** (eine pro App). Connection-Pool-Limit hit. +2. **Voll-Sync beim Start** — alle 120+ Collections, auch wenn der User nur 2 Module benutzt. + +### Unified WebSocket — _eine_ Verbindung pro User + +``` +Vorher: User × 27 Apps × WebSocket = 27 Verbindungen +Nachher: User × 1 manacore-web × WebSocket = 1 Verbindung +``` + +`mana-sync` (Go) multiplext alle App-Streams über einen Channel. Server-Side: einfach RLS-gefilterter `LISTEN/NOTIFY`. + +### Dann: WebSocket → SSE + +Ein paar Stunden später wurde der WebSocket-Code komplett rausgerissen und durch **Server-Sent Events** ersetzt: + +| Aspekt | WebSocket | SSE | +| -------------- | ------------------ | ----------------------------------------- | +| Reconnect | Manuell | Browser-built-in | +| Proxy-Probleme | Häufig (CF, NGINX) | Keine (HTTP) | +| Bidirektional | Ja | Nein (irrelevant — Writes gehen via REST) | +| Code | ~600 LOC | ~180 LOC | + +SSE-Endpoint: `GET /api/v1/sync/stream` → ein Heartbeat alle 25s, Push bei jedem Server-side Change. + +### Partial Sync: Lazy Loading + +Beim Login werden jetzt nur **Core-Collections** synchronisiert (settings, profile, dashboard-state). Alle Modul-Collections werden erst beim ersten Visit des Moduls gepullt. + +``` +Login → core (5 collections, ~50 KB) + ↓ +Visit /todo → todo collections (12, ~200 KB) + ↓ +Visit /calendar → calendar collections (8, ~150 KB) +``` + +Plus **Pull-Pagination** mit `hasMore` Flag, damit ein Modul mit 10.000 Items nicht in einem 8 MB JSON-Blob ankommt. + +### Live-Update Bugs (zwei) + +E2E-Tests fanden zwei Bugs in der SSE-Reconnect-Logik: + +1. Doppel-Subscribe nach Reconnect → doppelte Updates +2. Pending-Changes wurden nach Reconnect nicht resync'd + +Beide gefixt, mit Test-Coverage. + +--- + +## Detail-View Overlay-System + +Vorher öffnete jedes Modul Detail-Views als eigene Route. Mit der Unified App wäre das Navigation-Hell. Lösung: **Overlay-Stack**. + +``` +Workbench + ↓ click on task + Overlay #1 (TaskDetail) + ↓ click on linked event + Overlay #2 (EventDetail) + ↓ click on contact + Overlay #3 (ContactDetail) + [ESC] schließt Overlay #3 +``` + +### Live in 14 Modulen heute + +cards, storage, presi, calendar, contacts, todo, picture, chat, mukke, memoro, planta, inventar, times, dreams. + +Jedes Detail-View hat: + +- **Inline editing** — kein Edit-Modus mehr +- **Animated Open/Close** +- **ESC-Key Support** +- **Stack-Awareness** — z-index korrekt, Backdrop nur unter dem obersten + +Routes für die alten Detail-Pages konsolidiert: 14 Routen weg, 1 Layout-Component da. + +### Page-Carousel statt Routen + +Module wie Contacts haben jetzt einen **Page-Carousel** — zwischen "Liste", "Mein Profil", "Statistik" wird per Swipe/Tab gewechselt, nicht per Route. Schneller, kein Layout-Flash. + +--- + +## Tag-System: Eines für alle 23 Module + +Jedes Modul hatte bisher seine eigenen Tags, in eigenen Tabellen. Sinnloser Duplicate-State. + +### `globalTags` Tabelle + +Eine zentrale `globalTags` Tabelle mit `{id, name, color, icon}`. Jedes Modul nutzt Junction-Tables wie `taskTags`, `contactTags`, `eventTags` mit `(itemId, tagId)`. + +### Neuer `createTagLinkOps` Factory + +```typescript +const taskTagOps = createTagLinkOps({ + table: db.taskTags, + itemKey: 'taskId', + tagKey: 'tagId', +}); + +await taskTagOps.add({ taskId, tagId }); +await taskTagOps.removeAll({ taskId }); +``` + +23 Module nutzen denselben Factory, ein einziges Test-Set, eine einzige Sync-Code-Pfad. + +### Shared Components + +- `` — die einheitliche Tag-Pille +- `` — Multi-Select mit Inline-Erstellung +- `` — Form-Field-Wrapper + +todo + photos sind die ersten Migranten weg von ihren lokalen Kopien. + +### Tag-DnD im Workbench + +Tags können aus dem Tag-Strip gezogen und auf Items in jedem Modul gedroppt werden. Reaktiv, mit `.value` statt `.subscribe()` (das war ein Bug). + +--- + +## Workbench: QuickInputBar + Page-Carousel + +### Unified QuickInputBar + +Ein einziger Input am unteren Bildschirmrand. Was er erstellt, hängt vom aktuellen Kontext ab: + +| Modul | QuickInput erstellt | +| -------- | ------------------- | +| Todo | Task | +| Calendar | Event | +| Notes | Note | +| Contacts | Contact | +| Habits | Habit | +| … | … | + +**Adapter-Pattern**: jedes Modul registriert sich mit `registerQuickInputAdapter('todo', { create, parse, …})`. + +### Workbench Home: App Pages Carousel + +Statt einer statischen Dashboard-Page hat der Workbench-Home einen horizontalen Carousel mit allen aktiven App-Pages. Swipe/Tab/Cmd+1..9 wechselt zwischen ihnen. + +### 2D-Resize + +Pages im Workbench sind jetzt in beide Achsen resizable (Width + Height), mit Memory pro Page. + +### Bottom-Chrome dynamisch + +`bottom-chrome-height` ist eine CSS-Variable die sich an PillNav, Tabs, Notifications anpasst. Main-Content schiebt sich entsprechend. + +### `AppView` → `ListView` Rename + +In allen 24 Modulen wurde `AppView.svelte` zu `ListView.svelte` umbenannt. Klarer Begriff. + +--- + +## i18n: 5 Phasen + +| Phase | Was passiert | +| ----- | --------------------------------------------------- | +| 1 | Locale-Files in per-Modul-Struktur splitten | +| 2 | User-Settings Locale wired, Nav-Translations | +| 3 | Alle 22 Module-Translations konsolidiert | +| 4 | 126 hardcoded deutsche Strings durch `$_()` ersetzt | +| 5 | Help-Content nach Locale-Files migriert | + +Resultat: Es gibt jetzt **keine einzige hardcoded Sprache mehr** im Unified-App-Code (Help-Articles inklusive). + +--- + +## Datenbanken: 20+ → 2 + +Bisher hatte jeder Modul-Server seine eigene PostgreSQL-DB. Mit dem Unified API macht das keinen Sinn mehr. + +### Neue Struktur + +``` +mana_platform # alle Service-Daten (auth, todo, calendar, …) + # via pgSchema('todo'), pgSchema('calendar'), … + # je Modul ein Schema, eine logische Trennung + +mana_sync # write-heavy, das eine Ding für mana-sync (Go) +``` + +`pgSchema()` statt `pgTable()` ist jetzt Pflicht. Alte DBs (calendar_db, contacts_db, …) gedumpt + gelöscht. + +--- + +## Analytics: Module-Context + Web Vitals + +### Konsolidierung + +Umami wurde von allen archivierten Apps entfernt — nur die Unified App trackt jetzt. Aber: jedes Event bekommt einen `module` Context. + +```typescript +analytics.track('item.created', { + module: 'todo', + itemType: 'task', + hasDueDate: true, +}); +``` + +### Event-Tracking in 19 Module-Stores + +Erste Welle: 7 Core-Module. Zweite Welle: 12 weitere. Tracked werden Create/Update/Delete/Move/Reorder Events. + +### Web Vitals + Funnel + +CLS, LCP, FID, TTFB werden jetzt zu Umami gesendet. Plus Funnel-Events: `funnel.signup.start`, `funnel.signup.complete`, `funnel.first_action`. GlitchTip bekommt User-Context (anonymisierte ID + Tier). + +--- + +## Reminder System + +Neuer **shared reminder system** in `@manacore/shared-stores` — ein Background-Worker scheduled lokale Notifications für Tasks, Events, Habits. Wird im App-Layout gemountet. + +```typescript +reminderService.schedule({ + module: 'todo', + itemId: task.id, + fireAt: task.dueDate.minusMinutes(15), + payload: { title: task.title }, +}); +``` + +Notification kommt via Service Worker, klickbar, öffnet das Detail-View. + +--- + +## Auth & Stores Refactor + +- **`shared-auth-stores` aufgelöst** → in `shared-auth-ui` absorbiert. Ein Package weniger. +- **`createGuestMode` Composable** + Unified `AuthGate` — der Guest-Modus ist jetzt überall einheitlich, statt 23 lokale Implementierungen. +- **`createArchiveOps` / `createViewStore` Factories** — wiederverwendbare CRUD-Patterns für alle Module. +- **Shared Python Auth** + **Shared Go Auth** Packages — extrahiert aus mana-stt, mana-tts, und 3 Go-Services. + +--- + +## Monitoring + +- **Strukturiertes Logging** in allen Services (JSON-Format, korrelierbar) +- **Promtail-Alignment** — Labels einheitlich, damit Loki-Queries nicht über inkompatible Schemas stolpern +- **GlitchTip Config** updated für unified app +- **Status-Page** zeigt jetzt unified app statt 27 einzelne Apps + +--- + +## Sonstiges + +| Item | Detail | +| --------------- | --------------------------------------------------------------------------------------------- | +| Self-Contact | Contacts erstellt für jeden User automatisch einen Eigenen-Profil-Contact, auch im Guest-Mode | +| ColorPicker | Generischer `` mit Standard-Paletten in shared-ui | +| FavoriteButton | Generic `` + `toggleField` Utility | +| Vitest Coverage | Threshold von 50 → 70 % | +| jest.config.js | Orphan entfernt | +| Stub-Services | Archived | + +--- + +## Zusammenfassung + +| Bereich | Commits | Highlights | +| ---------------------- | ------- | ------------------------------------------------- | +| Unified API | ~15 | 17 Server zu einem, 25 Apps archiviert, 2 DBs | +| Sync | ~10 | WebSocket→SSE, partial sync, pull pagination | +| Detail Overlays | ~10 | 14 Module, stack-fähig, inline editing | +| Tag System | ~12 | globalTags, junction tables, factory, DnD | +| QuickInput + Workbench | ~8 | Adapter-Pattern, Page-Carousel, 2D-Resize | +| i18n | ~6 | 5 Phasen, 126 Strings extrahiert | +| Analytics | ~10 | Module-Context, Web Vitals, 19 Stores | +| Refactor | ~12 | Auth-Stores absorbiert, Factories, Python/Go Auth | +| Monitoring | ~5 | Logging, Promtail, GlitchTip | +| Fixes | ~19 | Diverse Sync- + Build-Bugs | + +--- + +## Nächste Schritte + +- Habits-Modul aufbauen (das einzige offene Modul) +- Notes & Finance Module ins Unified pattern ziehen +- Cross-Module-Drag-Targets ausbauen (Tags → Tasks → Events fertig, fehlt Karten/Locations) +- Stalwart als interner Mail-Server für mana-notify diff --git a/apps/mana/apps/landing/src/content/devlog/2026-04-03-habits-automations-stalwart-undo.md b/apps/mana/apps/landing/src/content/devlog/2026-04-03-habits-automations-stalwart-undo.md new file mode 100644 index 000000000..8544181a2 --- /dev/null +++ b/apps/mana/apps/landing/src/content/devlog/2026-04-03-habits-automations-stalwart-undo.md @@ -0,0 +1,339 @@ +--- +title: 'Habits, Automations, Notes/Finance/Places + Stalwart Mail + Undo' +description: 'Vier neue Module (habits, automations, notes/finance, places mit GPS), Cross-Module Trigger-Registry für Automations, Stalwart Mail-Server intern, Undo-Toasts auf 14 DetailViews und cross-module clickable links mit overlay stacking.' +date: 2026-04-03 +author: 'Till Schneider' +category: 'feature' +tags: + [ + 'manacore', + 'habits', + 'automations', + 'notes', + 'finance', + 'places', + 'stalwart', + 'mail', + 'undo', + 'workbench', + 'context-menu', + ] +featured: true +commits: 80 +readTime: 13 +stats: + filesChanged: 2617 + linesAdded: 17005 + linesRemoved: 249085 +contributors: + - name: 'Till Schneider' + handle: 'Till-JS' + commits: 80 +workingHours: + start: '2026-04-03T00:08' + end: '2026-04-03T21:39' +--- + +## Highlights + +- **Vier neue Module**: habits, automations, notes, finance, places (GPS) +- **Automations Trigger-Registry** — cross-module Aktionen reagieren aufeinander +- **Stalwart Mail-Server** intern für mana-notify (raus aus Brevo-only) +- **Undo-Toasts** auf 14 DetailViews + Task-Completion +- **Cross-Module clickable links** mit Overlay-Stacking +- **Page-Shell**: Drag-Header + Move/Min/Max/Close in eine Bar +- **−249k LOC** (massive Cleanup-Welle: 25 archivierte Apps endgültig gelöscht, Legacy-Code raus) + +--- + +## Habits-Modul + +Habits war eines der letzten Module die noch fehlten. Heute scaffolded und in einem Aufwasch produktiv: + +### Features + +- **Tally-Board** als Standardansicht — jeden Tag eine Spalte, jede Habit eine Zeile +- **Inline-Create** in der Liste, kein Modal +- **Detail-View** mit Streak-Anzeige, Verlauf, Notizen pro Tag +- **Phosphor-Icons statt Emojis** — neuer shared `` (mit Suche), gilt jetzt auch für andere Module die Icons brauchen +- **Photos-Upload** an Daily-Entries möglich + +Datenmodell: `habits` (Definition) + `habitEntries` (eine pro Tag pro Habit). Beide auf encrypted-by-default. + +--- + +## Automations-Modul + +Das wahrscheinlich konzeptuell interessanteste Stück des Tages: **Automations** als eigenes Modul, das aus jedem anderen Modul Trigger empfangen kann. + +### Cross-Module Trigger-Registry + +Module registrieren ihre Trigger zentral: + +```typescript +// modules/todo/automations.ts +registerTriggers('todo', [ + { id: 'task.completed', label: 'Aufgabe abgehakt' }, + { id: 'task.created', label: 'Aufgabe erstellt' }, + { id: 'task.due_today', label: 'Aufgabe wird heute fällig' }, +]); +``` + +Und ihre Aktionen: + +```typescript +registerActions('calendar', [{ id: 'event.create', label: 'Termin erstellen', schema: ZEvent }]); +``` + +Eine Automation verbindet **Trigger → Bedingungen → Aktion**: + +``` +WHEN todo.task.completed +WHERE task.tag === 'sport' +THEN habits.entry.create habit='workout' +``` + +### UI für Trigger-Rules + +Eine eigene Page in der Automations-App listet alle aktiven Rules. Inline-Editor mit Auto-Suggest aus der Trigger/Action-Registry. + +### Proaktive Suggestions + +Plus: das System schaut sich an was der User regelmäßig manuell macht ("nach jedem `task.completed` mit Tag 'sport' erstellt User eine `habit.entry`") und schlägt eine entsprechende Automation **inline** vor — dort wo das Verhalten passiert, nicht in einer separaten View. + +--- + +## Notes, Finance — und ein konsolidiertes Registry + +Zwei kleine Module nebenher gebaut: + +### Notes + +- Leichtes Notes-Modul (kein Markdown-Editor — pure Plain-Text + Tags) +- Click-to-edit, ListView mit kompaktem Input oben +- Workbench-Panel mit Inline-Edit (kein Detail-Modal nötig für Quick-Capture) + +### Finance + +- Buchhaltungs-Light (Income / Expense / Categories) +- Workbench-Panel direkt nutzbar — Eingabe + sofortige Liste + +### Unified `AppDescriptor` + +Vorher gab es zwei Registries: Entity-Registry (für DnD-Targets) + App-Registry (für Branding/Routing). Heute zusammengeführt zu einem **`AppDescriptor`**, der alles in einer Datei pro Modul beschreibt: + +```typescript +export const todoApp: AppDescriptor = { + id: 'todo', + label: 'Todo', + color: '#6366f1', + icon: 'check', + routes: [...], + entityTypes: ['task', 'project', 'page'], + dragSources: [...], + dropTargets: [...], + searchProvider: searchTodos, +}; +``` + +Module registrieren sich mit einem einzigen Aufruf statt drei. + +--- + +## Places-Modul mit GPS-Tracking + +Das fünfte neue Modul des Tages: **Places** — einfache Location-Verwaltung, mit optionalem GPS-Tracking im Hintergrund. + +- **GPS-Background-Tracking** opt-in (per Service-Worker / Permissions API) +- **Visit-Detection** via Stationary-Phasen +- **Reverse Geocoding** über OSM (Nominatim) +- **Map-View** mit OSM-Embeds (leaflet wurde im selben Sweep entfernt — siehe unten) + +--- + +## Cross-Module Clickable Links + Overlay-Stacking + +Kombiniert mit dem Detail-Overlay-System von gestern: jedes Item kann auf Items aus anderen Modulen verweisen, und ein Klick öffnet das Ziel **on top** des aktuellen Overlays. + +``` +TaskDetail (Overlay #1) + → Linked Event "Sprint Review" + Click → EventDetail (Overlay #2) + → Linked Contact "Anna" + Click → ContactDetail (Overlay #3) +``` + +ESC schließt nur das oberste Overlay. Das System tracked welche Items gerade offen sind, um Doppel-Open zu verhindern. + +### Detail-View Polish + +- **Animated Close** + ESC-Key (gestern war's nur Open-Animation) +- **Mehrere DetailViews offen** über AppPages hinweg +- **Tag-Pills mit Click-to-Remove** in jeder DetailView +- **Tags als Pills statt Dots** anzeigen — endlich mit Label + +--- + +## Undo-Toasts — wirklich überall + +Bisher gab es Undo nur für gelöschte Tasks. Heute ausgeweitet auf: + +- **14 DetailViews** (delete + tag removal) +- **Task-Completion** (mit "Doch nicht erledigt"-Toast) + +Pattern: jede destruktive Aktion stagged eine `pendingDelete` für 5 Sekunden, im Hintergrund läuft der Undo-Timer. Klick auf "Rückgängig" → restore. Sonst → flush. + +--- + +## Stalwart Mail-Server + +`mana-notify` lief bisher nur über Brevo (extern). Für interne Mails (User-Verifikation, System-Alerts, Memoro-Invites) ist das ungeeignet — Brevo zählt jeden Verify-Mail als "Marketing-Email". + +### Stalwart als interner Postfix-Ersatz + +```yaml +# docker-compose.macmini.yml +stalwart: + image: stalwartlabs/stalwart + ports: + - '25:25' + - '587:587' + volumes: + - stalwart-data:/opt/stalwart +``` + +`mana-notify` wird auf SMTP umgestellt — Stalwart ist Default für interne Mails, Brevo bleibt für Massenmails (Newsletter etc., später). + +### Eine Reihe von Iterations + +Stalwart ist neu — es gab heute mehrere Bugs: + +| Issue | Fix | +| -------------------------------------------- | ----------------------------------------------------- | +| Falscher Image-Name | `stalwartlabs/stalwart` (nicht `stalwart-mail`) | +| Port-Mapping kollidierte mit Host-Postfix | 25 + 587 explizit gemapped | +| Healthcheck schlug fehl | TCP-Check auf 587 | +| LOGIN-Auth schlug fehl | mana-notify SMTP-Sender komplett neu mit `LOGIN auth` | +| Insecure TLS für intern erlaubt | Self-Signed-Zertifikate akzeptiert für interne Hops | +| Falsche Account-Rolle | `noreply` mit `user`-Role statt admin | +| Brevo SMTP_USER fehlt als Default | Backward-compat für externe Mails | +| Service-Key zwischen mana-auth & mana-notify | Aligned, sonst lehnt notify die Auth-Mails ab | +| Message-ID + Date-Headers fehlten | Outgoing-Mails landen sonst in Spam | + +Am Ende: Auth-Mails vom mana-auth Service gehen jetzt **vollständig intern** über Stalwart raus. Spam-Score: gut. + +### `mana-auth` → `mana-notify` Refactor + +`mana-auth` hatte Nodemailer-Code für Verifikations-Mails. Jetzt routet es ALLE Mails über mana-notify (eine API, ein Sender, eine Stelle für Templates). + +--- + +## PageShell: Drag + Window-Controls in eine Bar + +Bisher hatte jede Page einen Drag-Bereich oben + separate Window-Controls in der Ecke. Confusing. Jetzt: + +``` +┌────────────────────────────────────────────────┐ +│ ← ••• Title ••• → │ □ ⊟ ⊠ ✕ │ +└────────────────────────────────────────────────┘ + Drag Handle Min Max Close +``` + +- **Volle Drag-Bar** als Header (height reduziert auf das Nötige) +- **Window-Controls** (min/max/close) integriert +- **Left/Right Arrow Buttons** für Page-Navigation +- **Drag Preview** zeigt Item-Title + App-Color (statt nur "1 Item") +- **Drag-Handles immer sichtbar**, nicht nur on hover + +### Drag vs Click Bug + +Bug: nach DnD wurde der Click auch noch ausgelöst → Detail-View öffnete sich. Fix: Click-Event blocken wenn ein Drag gerade stattgefunden hat. + +--- + +## Workbench Page-System + +- **`PageCarousel` full-width** auf Homepage (kein Side-Padding) +- **Left scroll offset** damit die erste Page nicht am Rand klebt +- **Page Drag** restricted auf Handle-Area damit Items innerhalb der Page noch greifbar sind +- **Mobile responsive** — Page-Width passt sich an Viewport an + +--- + +## Cleanup-Welle (−249k LOC) + +Heute war auch Aufräumtag. Mit den 25 archivierten Apps von gestern und der Stabilität des Unified-Stacks konnte massiv Legacy raus: + +| Cleanup | LOC | +| ----------------------------------------------------------------------------- | ------------- | +| 25 web-archived directories endgültig gelöscht | großer Teil | +| Legacy per-app IndexedDB Migration | ~3k | +| Backend-API-Clients (Ghost-Code, kein Server mehr da) | ~5k | +| Stale Stubs in Workspace-Config | – | +| `shared-auth-stores`, `shared-profile-ui`, `shared-app-onboarding` Referenzen | – | +| Leaflet → OSM-Embeds (kein 200 KB JS-Bundle mehr) | – | +| Codebase-weiter Consolidate-Sweep | viele Dateien | + +**Note:** Wir haben aktuell noch keine User in Production. Dieser Cleanup-Modus ist genau jetzt richtig — danach wird's politisch. + +--- + +## Fixes & Polish + +| Fix | Beschreibung | +| -------------------------------------- | ---------------------------------------------------------------------- | +| Effect depth exceeded | `guestMode` wurde versehentlich `$state()`, hat sich selbst getriggert | +| Entity registration hang | Race-Condition zwischen Registry-Init und Module-Mount | +| 40 Svelte dev warnings | Clean-Startup ohne Console-Spam | +| Default Port unified API | 3050 → 3060 (3050 ist mana-sync) | +| API-Server Dev-Scripts | Alle Scripts auf den Unified API umgestellt | +| Status-Page / Prometheus / Cloudflared | Configs für unified app aktualisiert | +| Race in status-page-gen | Lock-File während Generation | +| Analytics Umami Website-ID | Nach DB-Reset neue ID gepflegt | +| `getTagsByIds` | Fehlender `allTags` Param in zitare gefixt | +| ManaContacts → Kontakte | Branding-Rename | +| AppDrawer → new tab | Apps öffnen sich extern statt innerhalb der App | +| `bindclient:Height` → calculated | Bottom-Chrome-Height berechnet, nicht gemessen | +| CSP localhost erlaubt | In Dev-Mode | +| `bottomChromeHeight` Order | Deklaration vor Verwendung | +| Sync revert | Per-app SSE → HTTP polling als Fallback (SSE-Bugs morgen klären) | +| `@const` revert | Innerhalb `
` invalid | + +--- + +## Branding & UI + +- **PillNav cleanup**: Observatory, API Keys, Gifts entfernt — waren Stubs +- **InputBar Toggle**: PillNav-Toggle nach rechts in InputBar verschoben (vorher links, blockierte Tag-Strip) +- **Tags**: leftmost Position in PillNav, größerer Toggle-Button + +--- + +## Dokumentation + +- `docs/MAIL_STALWART.md` — Setup-Notes, Auth-Config, Troubleshooting +- `docs/UNIFIED_APP_PHASE7_NOTES.md` — Detail-Patterns für Drag/Drop und Overlays + +--- + +## Zusammenfassung + +| Bereich | Commits | Highlights | +| --------------------- | ------- | -------------------------------------------------- | +| Neue Module | ~14 | habits, automations, notes, finance, places | +| Stalwart Mail | ~13 | Setup, 8 Iterations bis stabil, mana-auth Refactor | +| Undo-Toasts | ~3 | 14 DetailViews + Task-Completion | +| Cross-Module Links | ~5 | Overlay-Stacking, animated close, ESC | +| Workbench / PageShell | ~12 | Drag + Window-Controls in eine Bar | +| Cleanup | ~10 | −249k LOC, Legacy + 25 archived Apps endgültig weg | +| Tag UI | ~5 | Pills statt Dots, Click-to-Remove | +| Fixes | ~18 | Reactivity, Race-Conditions, Sync-Revert, CSP | + +--- + +## Nächste Schritte + +- Mobile-Responsive für alle Module (PWA-fähig machen) +- Habits + Tasks scheduling: gemeinsamer Time-Block +- Finance Quick-Stats Widget für Dashboard +- Sync SSE-Bugs root-causen, polling wieder zurückbauen diff --git a/apps/mana/apps/landing/src/content/devlog/2026-04-04-mana-media-cas-effect-depth-fix.md b/apps/mana/apps/landing/src/content/devlog/2026-04-04-mana-media-cas-effect-depth-fix.md new file mode 100644 index 000000000..9ec1fda4d --- /dev/null +++ b/apps/mana/apps/landing/src/content/devlog/2026-04-04-mana-media-cas-effect-depth-fix.md @@ -0,0 +1,138 @@ +--- +title: 'mana-media als zentrale Bild-Pipeline + Effect-Depth-Fix' +description: 'Kurzer Tag: Bild-Uploads aller 5 Module routen über mana-media (CAS, Thumbnails, EXIF, Photos-Galerie). Dazu der Fix für effect_update_depth_exceeded der seit dem Unified-App-Switch auf 6 Dashboard-Modulen heumkroch.' +date: 2026-04-04 +author: 'Till Schneider' +category: 'fix' +tags: + ['mana-media', 'cas', 'thumbnails', 'photos', 'svelte5', 'reactivity', 'liveQuery', 'guest-mode'] +featured: false +commits: 2 +readTime: 4 +stats: + filesChanged: 23 + linesAdded: 299 + linesRemoved: 318 +contributors: + - name: 'Till Schneider' + handle: 'Till-JS' + commits: 2 +workingHours: + start: '2026-04-04T10:30' + end: '2026-04-04T11:00' +--- + +## Highlights + +- **mana-media** wird zentrale Bild-Pipeline: Picture, Contacts, Planta, Storage, NutriPhi laden Bilder darüber hoch +- **CAS (SHA-256 Dedup)**, **Thumbnails**, **EXIF-Extraktion** automatisch +- Alle hochgeladenen Bilder erscheinen in der **Photos-Galerie** +- Fix: `effect_update_depth_exceeded` in 6 Dashboard-Modulen (Resultat des Unified-App-Switches) + +Kurze Samstag-Session — zwei gezielte Commits. + +--- + +## mana-media: Eine Pipeline für alle Bild-Uploads + +Bisher hat jedes Modul Bilder direkt in S3/MinIO geschrieben. Das hatte mehrere Nachteile: + +- **Keine Dedup** — dasselbe Bild in 3 Modulen lag 3-mal im Bucket +- **Keine Thumbnails** — jedes Modul rollte sein eigenes Resizing +- **Keine EXIF-Extraktion** — keine konsistente Date-Taken-Sortierung +- **Photos-Galerie sah nichts davon** — uploads aus Contacts/Picture/Planta waren in der Galerie unsichtbar + +### Neues Routing + +``` +Vorher: Nachher: +Picture → S3 direkt Picture ─┐ +Contacts → S3 direkt Contacts ─┤ +Planta → S3 direkt ───→ Planta ─┼─→ mana-media → S3 (CAS) + DB +Storage → S3 direkt Storage ─┤ ↓ +NutriPhi → S3 direkt NutriPhi ─┘ Photos Gallery +``` + +### Implementierung + +`apps/api/src/lib/media.ts` ist der neue Helper. Module-Routes rufen `uploadImageToMedia(buffer, { module, ownerId })` und bekommen eine `mediaId` zurück, die sie in ihrer eigenen Tabelle persistieren. + +mana-media liefert zurück: + +- `mediaId` — referenzierbar überall +- `url` für das Original +- `thumbnailUrls` für 256/512/1024 +- `width / height / format` +- `exif.takenAt`, GPS, Camera + +### Was nicht über mana-media geht + +- **Non-Images** (PDFs, Audio, Docs): bleiben direkt bei `@manacore/shared-storage`. Sharp kann sowas nicht. +- **SVG-Avatare** in Contacts: bleiben bei shared-storage, weil Sharp keine SVGs verarbeitet. + +### Nebeneffekt: Photos-Galerie wird automatisch befüllt + +Die Photos-App liest aus `mana_media.media WHERE owner_id = ?`. Damit erscheinen jetzt alle Avatare aus Contacts, alle Pflanzen-Fotos aus Planta, alle Mahlzeit-Bilder aus NutriPhi etc. in der Galerie — ohne dass die Module davon wissen. + +--- + +## Fix: effect_update_depth_exceeded + +Seit der Unified-App-Migration vor 3 Tagen tauchten in 6 Dashboard-Modulen Svelte-5-Errors auf: + +``` +Uncaught Svelte error: effect_update_depth_exceeded +Maximum update depth exceeded. This can happen when a reactive +block or effect repeatedly sets a new value. +``` + +### Root Cause + +```typescript +// alt — verursacht den Error +let items = $state([]); +$effect(() => { + const sub = liveQuery(() => db.items.toArray()).subscribe((arr) => { + items = arr; // <- triggert weitere $state writes downstream + }); + return () => sub.unsubscribe(); +}); +``` + +Das `$state`-Write in dem `$effect` triggerte downstream Effects (in Children), die wieder Stores updateten, die wieder Children re-rendered → Cascade. Bei kleinen Listen okay, bei den Dashboard-Widgets mit 6 parallelen Subscriptions: BOOM. + +### Fix + +`useLiveQueryWithDefault` ist ein Hook der `liveQuery` direkt in einen `$derived` umwandelt — kein doppelter `$state` Round-Trip: + +```typescript +// neu +const items = useLiveQueryWithDefault(() => db.items.toArray(), [] as Item[]); +``` + +Migriert in: **todo, calendar, contacts, habits, notes, finance** — die 6 Dashboard-Module. + +### Plus: Zwei verwandte Reactivity-Fixes + +1. **`checkInlineSuggestion` in Dexie-Hooks** — wurde innerhalb einer Single-Table-Transaction aufgerufen, hat aber Cross-Table reads gemacht. `setTimeout(…, 0)` deferiert es nach dem Transaction-Commit. + +2. **`guestMode` mit `$state()` deklariert** — am 03.04. wurde es vorübergehend auf primitive zurückgesetzt (wegen einer Reactivity-Schleife). Mit dem heutigen Pattern-Switch funktioniert `$state()` wieder. + +3. **`trySSO` mit 5s Timeout** — wenn mana-auth unreachable ist, hängt der Login-Flow nicht mehr. Timeout-Path führt direkt in den Guest-Modus. + +--- + +## Zusammenfassung + +| Bereich | Commits | Highlights | +| ------------------- | ------- | ---------------------------------------------------------------------- | +| mana-media Pipeline | 1 | 5 Module über CAS, Thumbnails, EXIF, Photos-Galerie sichtbar | +| Reactivity-Fixes | 1 | useLiveQueryWithDefault in 6 Modulen, Dexie-Hook deferral, SSO-Timeout | + +--- + +## Nächste Schritte + +- mana-media Cleanup-Job für orphaned Bilder +- Sharp aktivieren für animierte WebP / AVIF Output +- File-Bytes Encryption auch für mana-media Uploads (gehört zu Phase 8 der Encryption-Roadmap) diff --git a/apps/mana/apps/landing/src/content/devlog/2026-04-05-timeblocks-mukke-music-rename-pwa.md b/apps/mana/apps/landing/src/content/devlog/2026-04-05-timeblocks-mukke-music-rename-pwa.md new file mode 100644 index 000000000..25edb6e5d --- /dev/null +++ b/apps/mana/apps/landing/src/content/devlog/2026-04-05-timeblocks-mukke-music-rename-pwa.md @@ -0,0 +1,263 @@ +--- +title: 'TimeBlocks: ein Zeitmodell für alles + Mana Rename + PWA' +description: 'TimeBlocks vereinheitlicht Calendar/Habits/Tasks/Focus zu einem Zeitmodell mit rrule.js. Mukke wird zu Music. ManaCore wird zu Mana. PWA-Support inkl. Offline-UX und Update-Prompt für alle Module.' +date: 2026-04-05 +author: 'Till Schneider' +category: 'feature' +tags: + [ + 'timeblocks', + 'calendar', + 'habits', + 'rrule', + 'pwa', + 'offline', + 'mobile', + 'rename', + 'mana', + 'mukke', + 'music', + ] +featured: true +commits: 19 +readTime: 11 +stats: + filesChanged: 2244 + linesAdded: 15083 + linesRemoved: 11360 +contributors: + - name: 'Till Schneider' + handle: 'Till-JS' + commits: 19 +workingHours: + start: '2026-04-05T14:39' + end: '2026-04-05T21:14' +--- + +## Highlights + +- **TimeBlocks** als unified time model — Calendar, Habits, Tasks, Focus-Mode teilen sich eine Tabelle +- **rrule.js** als zentrale Recurrence-Engine, mit Edit-this/all/following Prompts +- **PWA** für die unified app — Offline-UX, Update-Prompt, Icons, mobile Responsiveness in allen Modulen +- **Rename**: ManaCore → **Mana** (final), Mukke → **Music** +- **Cross-Module DnD ins Calendar** — Tasks/Habits droppen wird zum TimeBlock +- **Calendar Type-Specific Styling** — verschiedene Block-Types haben verschiedene Visuals +- **iCal Export** + Analytics-Dashboard für TimeBlocks +- **"Mein Tag" Timeline-Widget** auf dem Dashboard + +--- + +## TimeBlocks: Ein Zeitmodell für alles + +Bisher hatten Calendar, Habits, Todo-Scheduling und der (geplante) Focus-Mode jeweils ihr eigenes Zeitmodell. Drei Tabellen, drei Recurrence-Implementierungen, drei UIs. + +### Eine `timeBlocks` Tabelle + +```typescript +type TimeBlock = { + id: string; + type: 'event' | 'habit' | 'task' | 'focus' | 'meal' | 'sleep'; + title: string; + start: Date; + end: Date; + rrule?: string; // RFC 5545 + refModule?: string; // 'todo' | 'habits' | 'memoro' | … + refId?: string; // ID im Quell-Modul + color?: string; + status?: 'planned' | 'done' | 'skipped' | 'missed'; +}; +``` + +Jeder Calendar-Event, jede Habit-Schedule, jede Task-Due-Date Kombination, jede Focus-Session, jede Schlaf-/Mahlzeit-Erfassung ist jetzt ein TimeBlock. + +### `rrule.js` als Recurrence-Engine + +Statt drei selbstgebauter Recurrence-Implementierungen jetzt **eine Library**: + +```typescript +import { RRule } from 'rrule'; + +const block = { + rrule: 'FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=12', +}; + +// Expand für Anzeige +const occurrences = RRule.fromString(block.rrule).between(viewStart, viewEnd); +``` + +### Custom Recurrence UI + +Vorher: Dropdown mit "Daily / Weekly / Monthly". Jetzt: + +``` +┌──────────────────────────────────┐ +│ Wiederholt sich │ +│ ⚪ Nie │ +│ ⚪ Täglich │ +│ ⚪ Wöchentlich am [Mo Mi Fr] │ +│ ⚫ Benutzerdefiniert │ +│ Alle [2] [Wochen] │ +│ Am [Mo] [Mi] [Fr] │ +│ Bis [15. Mai 2026] │ +└──────────────────────────────────┘ +``` + +### Edit/Delete Prompts + +Wenn man einen rezidivierenden Block ändert kommt jetzt ein Prompt: + +``` +┌─────────────────────────────────┐ +│ Diese Wiederholung bearbeiten? │ +│ • Nur diesen Termin │ +│ • Diesen und folgende │ +│ • Alle Termine │ +└─────────────────────────────────┘ +``` + +Die Logik: bei "nur diesen" wird der Block aus der RRule **exdatet** und als Standalone-Block neu angelegt. Bei "folgende" wird der ursprüngliche Block am gewählten Datum **truncated** und ein neuer mit der angepassten Definition ab dem Datum erstellt. + +### Habits-Migration + +Habits hatten bisher ihre eigene `habitSchedules` Tabelle. Heute migriert auf TimeBlocks: + +``` +habit.schedule = TimeBlock { + type: 'habit', + refModule: 'habits', + refId: habitId, + rrule: 'FREQ=DAILY', +} + +habit.entry = TimeBlock { + type: 'habit', + refId: habitId, + start, end, + status: 'done' | 'skipped', +} +``` + +### Calendar-Type-Specific Styling + +Im Calendar werden TimeBlocks je nach `type` unterschiedlich dargestellt: + +- **event** — gefüllter Block in Module-Color +- **habit** — Block mit gestricheltem Border +- **task** — Block mit Checkbox-Indicator +- **focus** — opaker Block mit Schloss-Icon +- **sleep / meal** — kleinere "Tag" am Rand + +Plus: Filter-UI um Block-Types ein-/auszuschalten, Cross-Module-Navigation (Klick auf Habit-Block → öffnet Habit-Detail). + +--- + +## TimeBlocks: Phasenrolle + +Heute kamen viele Features in einem Rutsch — der Reihe nach: + +| Feature | Beschreibung | +| ----------------------- | ---------------------------------------------------------------------------- | +| Unified Time Model | `timeBlocks` Tabelle, Migration der bestehenden Daten | +| External Item Drag | Tasks aus der Todo-Liste droppen → wird Task-TimeBlock | +| Conflict Detection | Überlappende Blöcke werden visuell markiert + Warnung | +| Plan vs Reality | TimeBlock hat optional einen `actualStart` / `actualEnd` (für Time-Tracking) | +| Timeline View | Vertikale Tagesansicht mit gegenwärtiger Zeit-Linie | +| Focus Mode | TimeBlocks vom Type `focus` blockieren Notifications & Distractions | +| Habit Scheduling | Habits werden direkt im Calendar geplant | +| Smart Slots | "Wo passt 30min für Sport?" — leerer Slot-Detection | +| Multi-Type Quick-Create | Floating-Action: erstellt event/task/habit/focus aus einem Menü | +| Analytics Dashboard | Wie viele Stunden in welchem Type, Plan vs Reality | +| iCal Export | Standard-konformer .ics Download je User/View | +| Cross-Module DnD | Items aus jedem Modul → Calendar als TimeBlock | +| Activity Feed Widget | Dashboard-Widget zeigt die letzten N TimeBlocks | +| "Mein Tag" Widget | Dashboard zeigt die heutige Timeline mit aktueller Position | + +### CalendarEventsWidget update + +Das alte Dashboard-Widget las aus der `events` Tabelle. Heute auf TimeBlocks umgestellt — zeigt jetzt auch Habits, Tasks, Focus-Sessions die heute anstehen. + +--- + +## Rename: ManaCore → Mana + +Der Code-Name "ManaCore" hatte seinen Zweck erfüllt — es ist Zeit für den finalen Markennamen. + +### Was sich ändert + +- **App-Domain bleibt**: `mana.how` +- **Code-Name**: `ManaCore` → `Mana` +- **Pfade**: `apps/manacore/` → `apps/mana/` +- **Packages**: `@manacore/*` → `@mana/*` +- **Workspace-Configs**, Docker-Compose Service-Names, Env-Vars, CI-Pipelines + +### Was schiefgehen kann + +Ein Rename quer durchs Monorepo ist immer riskant. Heute waren die Folge-Bugs: + +- **Type errors** in Templates und Stale-Referenzen +- **Duplicate `manaSvg`** in shared-branding (Rename-Collision mit existierendem `manaSvg`) +- **Type-Extraction aus `.svelte`** Dateien für named re-exports +- **Eslint OOM** — Heap auf 8 GB hochgesetzt damit der Lint nicht vorzeitig stirbt + +Plus: Mukke heißt jetzt **Music**. Cleaner Name, weniger Insider, plus Cover-Art-Upload via mana-media (passt zum gestrigen Refactor). + +--- + +## PWA-Support für die Unified App + +Ziel: Mana läuft als installierbare PWA auf Mobile, mit Offline-Fallback und Update-Prompt. + +### Was heute live ist + +| Feature | Detail | +| ------------------ | ------------------------------------------------------ | +| **Service Worker** | Caches Shell + Modul-Routes, Network-First für Daten | +| **Offline-Page** | `/offline` mit Hinweis + Retry-Button | +| **Update-Prompt** | Toast wenn neue Version verfügbar — 1 Click Reload | +| **Icons** | maskable + apple-touch-icon, alle Größen | +| **Manifest** | Standalone-Display, Theme-Color, Shortcuts in 5 Module | +| **Install-Prompt** | "Mana installieren" Banner für Erst-User | + +### Mobile Responsiveness komplett + +Alle Module + alle shared-Components heute auf Mobile getestet: + +- **PageShell** kollabiert auf Mobile in Single-Column +- **Workbench Pages** stacken vertikal +- **PillNav** schrumpft auf Icon-Only +- **Detail-Overlays** werden full-screen +- **Tag-Strip** scrollt horizontal +- **Bottom-Stack** respektiert Safe-Area-Insets + +### PWA-Phase im Tauri-v2-Plan abgehakt + +Der Tauri-v2-Plan hatte PWA als Vorstufe. Heute komplett — der nächste Schritt (native Tauri-Wrapper) kann beginnen. + +--- + +## Sonstige Fixes + +| Fix | Detail | +| ------------------- | --------------------------------------------- | +| Calendar `WeekView` | Duplicate `calendarViewStore` Import entfernt | + +--- + +## Zusammenfassung + +| Bereich | Commits | Highlights | +| --------------- | ------- | -------------------------------------------------------------------------------- | +| TimeBlocks | ~10 | Unified time model, rrule.js, focus mode, smart slots, timeline, iCal, analytics | +| ManaCore → Mana | ~3 | Globaler Rename, type-fixes, eslint OOM-bump | +| PWA + Mobile | ~3 | Service Worker, offline, update prompt, mobile responsive in allen Modulen | +| Mukke → Music | ~2 | Rename + cover art via mana-media | +| Dashboard | ~1 | "Mein Tag" Timeline-Widget | + +--- + +## Nächste Schritte + +- TimeBlocks Sharing (TimeBlocks aus shared Calendar) +- Smart-Slot-Suggestions für Habits-Scheduling intelligenter +- Sprint 1 der Data-Layer-Audit-Backlog (LWW + Atomic Cascades) +- Encryption-Roadmap der user-typed Felder diff --git a/apps/mana/apps/landing/src/content/devlog/2026-04-07-encryption-phases-1-9-cycles-dreams-events.md b/apps/mana/apps/landing/src/content/devlog/2026-04-07-encryption-phases-1-9-cycles-dreams-events.md new file mode 100644 index 000000000..f16bab7d8 --- /dev/null +++ b/apps/mana/apps/landing/src/content/devlog/2026-04-07-encryption-phases-1-9-cycles-dreams-events.md @@ -0,0 +1,360 @@ +--- +title: 'Encryption Phasen 1–9: Vault-Ende-zu-Ende + Dreams, Cycles, Events Module' +description: 'Größter Tag der Woche: AES-GCM-256 Encryption für 27 Tabellen in 9 Phasen ausgerollt, inkl. Zero-Knowledge-Modus mit Recovery-Code. Plus drei neue Module: Dreams (Voice→STT), Cycles (Menstrual-Tracking) und Events (öffentliche RSVP).' +date: 2026-04-07 +author: 'Till Schneider' +category: 'feature' +tags: + [ + 'encryption', + 'vault', + 'zero-knowledge', + 'recovery-code', + 'dreams', + 'cycles', + 'events', + 'rsvp', + 'mana-stt', + 'data-layer-audit', + 'sprint', + ] +featured: true +commits: 88 +readTime: 18 +stats: + filesChanged: 880 + linesAdded: 38302 + linesRemoved: 22129 +contributors: + - name: 'Till Schneider' + handle: 'Till-JS' + commits: 88 +workingHours: + start: '2026-04-07T12:26' + end: '2026-04-07T23:57' +--- + +## Highlights + +- **At-Rest Encryption** in 9 Phasen ausgerollt: AES-GCM-256 für 27 Tabellen +- **Zero-Knowledge-Modus** mit User-only Recovery-Code (Mana kann nichts lesen) +- **Lock-Screen** mit Recovery-Unlock-Modal +- **Drei neue Module**: Dreams (Traumtagebuch), Cycles (Zyklus-Tracking), Events (öffentliche RSVP) +- **Data-Layer-Audit Sprints 1–4** abgeschlossen — LWW, retry, atomic cascades, perf, quota, telemetry +- **mana-stt Voice-Pipeline** für Dreams + Memoro live +- **Pre-Launch Cleanup** — Schema-Collapse, Ghost-API-Clients raus, RLS auf sync_changes + +--- + +## Encryption: 9 Phasen in einem Tag + +Das große Thema des Tages. Die `DATA_LAYER_AUDIT.md` hatte Encryption als langfristige Roadmap — heute durchgezogen. **Alle 9 Phasen heute committed.** + +### Designprinzipien + +``` +───────────────────────────────────────────────── + Master Key (MK) ── 256 bit + └─ AES-GCM-256 für alle Records + └─ liegt nirgendwo unverschlüsselt rum +───────────────────────────────────────────────── + Standard-Modus + MK wird mit KEK (Key Encryption Key) wrapped + KEK liegt im mana-auth Service (`MANA_AUTH_KEK` env) + → Mana kann den MK rekonstruieren + → User braucht nur Login +───────────────────────────────────────────────── + Zero-Knowledge-Modus (opt-in) + MK wird mit user-derivierten Recovery-Code + verschlüsselt, KEK-wrapped Version wird gelöscht + → Mana kann den MK NICHT rekonstruieren + → User braucht Recovery-Code zum Entsperren +───────────────────────────────────────────────── +``` + +### Phase 1: Foundation (No-Op) + +`apps/mana/apps/web/src/lib/data/crypto/` mit allen Primitives angelegt — `encryptRecord`, `decryptRecords`, registry, key-derivation. Alles compiled, nichts wird tatsächlich verschlüsselt. Zero-Risk-Foundation. + +### Phase 2: Server-Side Master-Key Custody + +`mana-auth` bekommt Vault-Endpoints: + +- `POST /api/v1/vault/init` — neuer User: MK generieren, KEK-wrappen, persistieren +- `GET /api/v1/vault/unlock` — Login: KEK-unwrap, MK an Client liefern (https-only, kurzlebige Session) +- `POST /api/v1/vault/rotate-recovery` — Recovery-Code rotieren + +Plus Tests gegen echte Postgres (`vault.spec.ts`). + +### Phase 3: Vault-Client + Record-Helpers + Layout-Wire-Up + +Client-Seite: + +- `vaultClient` lädt MK beim Login +- `encryptRecord(table, record)` und `decryptRecords(table, records)` Helpers +- App-Layout wartet auf Vault-Unlock bevor Module geladen werden + +### Phase 4: Notes-Pilot + +Erstes Modul mit aktiver Encryption: **Notes**. Klein, kontrolliert, low-risk. Funktioniert? → Phase 5. + +### Phase 5: Rollout auf 6 Module + +chat, dreams, memoro, contacts, cycles, finance — alles user-typed Content der eindeutig privat ist. + +### Phase 6: Polish + UI + +- **6.1**: cards, presi, inventar, planta — Karten + Notiz-haltige Module +- **6.2**: Settings-Page mit Vault-Status (verschlüsselt seit, ZK an/aus, …) +- **6.3**: Onboarding-Banner für neue User der Encryption erklärt + +### Phase 7: Coupled & Storeless Tables + +- **7.1**: Tasks + Calendar Events — beide referenzieren TimeBlocks und müssen synchron verschlüsselt werden +- **7.2**: Storeless Module (questions, links, documents, meals) die keinen eigenen Store haben aber sensitive Felder + +### Phase 8: Restliche Tabellen + +Storage-Items, Picture-Boards, Music-Metadata, Events, Guests. **Damit sind alle 27 Tabellen verschlüsselt.** + +### Phase 9: Zero-Knowledge + +Das härteste Stück. Bisher konnte mana-auth den MK immer rekonstruieren. ZK-Modus macht das per Design unmöglich. + +#### Milestone 1: Recovery-Code Primitives + +- 32-Byte Random-Code, BIP39-encodiert (24 Wörter) +- PBKDF2 mit 600k Iterations als KDF +- Recovery-Wrap des MK + +#### Milestone 2: mana-auth Vault-Recovery-Wrap + +- Server speichert NUR den recovery-wrapped MK +- KEK-wrapped Version wird gelöscht beim Aktivieren von ZK +- Server kann den MK nicht mehr unwrap'en + +#### Milestone 3: Vault-Client Recovery-Flow + +- ZK-User wird beim Login gepromtet den Recovery-Code einzugeben +- Lock-Screen-Modal mit 24-Wort-Eingabe +- Unwrap clientseitig, MK in Memory + +#### Milestone 4: Settings UI + +- Settings → Sicherheit zeigt: + - Aktueller Modus (Standard / ZK) + - "Recovery-Code anzeigen" (mit Re-Auth) + - "Zero-Knowledge aktivieren" (irreversibel-ish — Recovery-Code wird einmal gezeigt) + - "Recovery-Code rotieren" (auch in ZK-Modus möglich) + +#### Lock-Screen + +- Wenn die Tab inaktiv war > X Minuten oder die Seite manuell gesperrt wird +- Screen verlangt Recovery-Code (ZK) oder Passwort (Standard) +- Modal blendet alles ab, App ist nicht bedienbar bis unlock + +### Vault-Status-Endpoint + +`GET /api/v1/vault/status` liefert für die Settings-Page: + +```json +{ + "encrypted": true, + "mode": "standard" | "zero_knowledge", + "encryptedSince": "2026-04-07T15:23:00Z", + "recoveryCodeRotatedAt": "2026-04-07T15:23:00Z" +} +``` + +### Audit-Roll-up + +`DATA_LAYER_AUDIT.md` mit allen Phasen 6/7/8/9 dokumentiert. Plus eine separate Roadmap **`FILE_BYTES_ENCRYPTION_PLAN.md`** für die nächste Stufe (verschlüsselte Bild/Audio/PDF-Bytes — bisher sind nur strukturierte Felder verschlüsselt). + +--- + +## Drei neue Module + +Während die Encryption durch die Phasen lief, entstanden parallel drei neue Module. + +### Dreams (Traumtagebuch) + +- **Voice-Capture via mana-stt** — Aufnahme im Browser, Transkript wird automatisch eingefügt +- **Symbol-Library** mit Detail-Views, Bedeutung, Mood-Stats +- **Filter-Tabs** und Symbol-Filter-Pills +- **Date-/Time-Picker** statt Standard-Inputs +- **Auto-Save**, Sort, Merge, Navigation in der Symbol-Library +- **Mic-Permission UX** auf macOS — wenn Browser den Prompt nicht zeigt, gibt's einen erklärenden Screen + Force-Retry +- **Proxy-Toleranz**: octet-stream und invalid form bodies werden vom Voice-Proxy nicht abgewiesen + +### Cycles (Menstruelle Zyklus-Tracking) + +- **Period Auto-Detect**: Start/Ende werden aus Symptomen + Bleeding-Levels abgeleitet +- **Symptom Management UI**: konfigurierbare Symptome mit Severity +- **Edit/Delete past entries** +- **Month Calendar View** mit Phase-Coloring (folliculär, ovulatorisch, luteal, menstruell) +- **Dashboard-Widget** mit aktueller Phase + Countdown zum nächsten Event +- **Locale-aware date formatting** +- **Echte i18n** für it/fr/es (es waren leere Strings im Stub) +- **i18n Key-Parity Tests** für alle 5 Locales +- **Integration-Tests** mit fake-indexeddb +- **ROADMAP** mit zukünftigen Features + +### Events (Public RSVP Module) + +Event-Modul für Ad-hoc Veranstaltungen mit öffentlichem RSVP-Link: + +- **`mana-events` Service** (Hono/Bun) — own DB schema, public RSVP routes +- **Phase 1a**: Scaffold lokaler Tabellen + UI +- **Phase 1b**: Public RSVP-Flow mit Cancel-Token +- **Phase 2**: Bring-List ("Wer bringt was?") — Slot-Reservation, Multi-User +- **35 Server-Tests** für routes + sweeper +- **Playwright e2e** mit flake-resistant config +- **i18n** für RSVP-Page in it/fr/es + extracted helper +- **Cascade rate buckets** wenn Event un-published wird +- **Self-heal Snapshots, Tombstones, Polling-Cleanup** +- **Production wiring + Polling resilience** (quick wins) +- **Roadmap** für Phase 2 (tech debt + remaining features) + +--- + +## Data-Layer-Audit: Sprints 1–4 + +Die `DATA_LAYER_AUDIT.md` Backlog hatte vier Sprints. Heute alle vier abgeschlossen. + +### Sprint 1: Data Integrity + +- **LWW (Last-Write-Wins)** mit Field-Level Timestamps +- **Retry mit Exponential Backoff** +- **Atomic Cascades** — wenn ein Parent gelöscht wird, werden Children atomisch markiert +- **Three runtime regressions** im Anschluss gefixt + +### Sprint 2: Auth-Aware Data Layer + Guest Migration + +- Data-Layer kennt jetzt den `userId` zum Stempeln +- Guest → registered Migration übernimmt alle existierenden lokalen Daten (mit User-Stempel) + +### Sprint 3: Type-Safe Sync Protocol + +- Sync-Protocol bekommt einen Zod-Schema +- Client + Server validieren beim Encode/Decode +- Tests die das Schema gegen mana-sync (Go) validieren +- **3 Pre-existing Test-Files** wieder lauffähig gemacht + +### Sprint 4: Perf, Quota, Telemetry + +- **`updatedAt` Index** für Recent-X Dashboard-Widgets +- **Quota-Recovery** wenn IndexedDB-Quota voll ist (Auto-Prune oldest) +- **Telemetry-Hooks** für Sync-Events +- **SSE-Pipeline-Read** parallel zu sequential apply (perf win) +- **Local Activity Log** mit periodic prune + +### Toast-Subscription + +Data-Layer-Events werden jetzt direkt subscribed: + +- Sync-Errors → Toast + Sentry +- Quota-Warnings → Toast +- Conflict-Detected → Toast mit "View Conflict" +- Scheduler-Events → Toast (für Reminders) + +--- + +## mana-stt Voice-Pipeline + +Dreams + Memoro nutzen jetzt eine geteilte Voice-Pipeline: + +``` +Browser MediaRecorder + ↓ POST /api/v1/voice/transcribe +mana-web Proxy + ↓ X-Service-Key +mana-stt (Windows GPU, WhisperX) + ↓ +Transcript JSON + ↓ +Modul (Dreams: zur Note, Memoro: zum Memo) +``` + +**STT-Postmortem heute** — `docs/postmortems/2026-04-07-stt-tunnel-down.md` dokumentiert einen 35-Minuten-Ausfall der STT-Pipeline (Cloudflare Tunnel zur Windows-GPU war runtergefallen). Fix: Tunnel-Health-Probe in Status-Page integriert. + +**GPU Tunnel Setup** + **STT env wiring** in dem Postmortem dokumentiert. + +--- + +## Pre-Launch Cleanup + +Vor dem Production-Launch eine größere Aufräumrunde: + +### Schema-Collapse + Dead Code + +- **`PRE_LAUNCH_CLEANUP.md`** dokumentiert was raus kam und warum +- **Lazy Search** statt eager loading von search-providern +- **Ghost Backend-API-Clients** entfernt — Module die noch HTTP-Clients hatten obwohl alles über die unified API geht + +### Mac-Mini Infra-Cleanup + +- `COMPOSE_PROJECT_NAME=manacore-monorepo` pinned +- Compose-Env, blackbox-Memory, Prometheus GPU-Probes optimiert +- Runbook-Hardening: Status-Diff Script, Ingress-Walk Script +- `startup.sh` idempotent + non-destruktiv gemacht + +### Sync RLS + +- `sync_changes` Tabelle bekommt **row-level security** in PostgreSQL +- User können nur ihre eigenen Changes lesen, auch wenn jemand Postgres-Direct-Access hätte + +### `rrule` SSR Bundle + +- `/calendar` 500-Error gefixt: rrule wurde in SSR-Build nicht inkludiert +- Vite-Config: rrule explizit als `noExternal` + +--- + +## Sonstige Fixes & Polish + +| Fix | Detail | +| -------------------------------------- | ---------------------------------------------- | +| timeblocks recurrence migration | Type-Errors aus dem Sprint von vorgestern | +| ManaCore→Mana stale templates | Type-Errors vom Rename | +| `manaSvg` dedupe | Rename-Collision in shared-branding | +| `cards-database` `.js` extensions | Für NodeNext-Module-Resolution | +| vitest unify | Workspace-weit auf `^4.1.2` | +| `/offline` prerender | Disabled — FIXME, prerender-Schritt war kaputt | +| `module-registry` + `module.config.ts` | Build-critical files committed | +| MANA_STT_URL/API_KEY Wiring | mana-web Container env | + +--- + +## Dokumentation + +- **`DATA_LAYER_AUDIT.md`** — Sprints 1–4 + Encryption-Phasen 1–9 vollständig dokumentiert +- **`PRE_LAUNCH_CLEANUP.md`** — was wurde entfernt vor Launch und warum +- **`FILE_BYTES_ENCRYPTION_PLAN.md`** — nächste Encryption-Stufe für Bytes/Bilder +- **`docs/postmortems/2026-04-07-stt-tunnel-down.md`** — STT-Ausfall Postmortem +- **`docs/cycles/ROADMAP.md`** — Cycles Feature-Backlog +- **`docs/events/PHASE2_ROADMAP.md`** — Events Phase 2 + tech debt +- GPU Tunnel Setup, STT env wiring docs + +--- + +## Zusammenfassung + +| Bereich | Commits | Highlights | +| --------------------- | ------- | ------------------------------------------------------------------ | +| Encryption Phasen 1–9 | ~22 | 27 Tabellen, ZK-Modus, Recovery-Code, Lock-Screen, Settings, Tests | +| Data-Layer Sprints | ~8 | LWW, retry, cascades, perf, quota, telemetry | +| Dreams Modul | ~9 | Voice via mana-stt, Symbol-Library, Mic-UX | +| Cycles Modul | ~12 | Phase-Detection, Symptome, Calendar-View, Widget, i18n | +| Events Modul | ~12 | RSVP-Flow, Bring-List, 35 Tests, Playwright, Phase 2 | +| mana-stt | ~3 | Voice-Pipeline, Postmortem, GPU-Tunnel | +| Pre-Launch Cleanup | ~7 | Schema-Collapse, RLS, idempotent startup | +| Sonstige Fixes | ~15 | Type-Errors aus Renames, vitest unify, build fixes | + +--- + +## Nächste Schritte + +- File-Bytes Encryption (Bilder, Audio, PDFs) +- Login-Flow Polish (passkey UI, structured errors) +- Voice-Quick-Add für Notes + Todo (nicht nur Dreams + Memoro) +- AI-Services konsolidieren auf Windows GPU als Source of Truth