docs(devlog): backfill daily devlogs for 2026-04-01 through 2026-04-07

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) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-08 17:11:10 +02:00
parent 0119e48edb
commit 4f6609a595
6 changed files with 1801 additions and 0 deletions

View file

@ -0,0 +1,311 @@
---
title: 'ManaCore Unified App: Phasen 17 + 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 17)
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 `<SplitScreen>` 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 `<a>`-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 `<ShareModal>` 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<T>` 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 17, 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)

View file

@ -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
- `<TagChip>` — die einheitliche Tag-Pille
- `<TagSelector>` — Multi-Select mit Inline-Erstellung
- `<TagField>` — 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 `<ColorPicker>` mit Standard-Paletten in shared-ui |
| FavoriteButton | Generic `<FavoriteButton>` + `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

View file

@ -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 `<IconPicker>` (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 `<div>` 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

View file

@ -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<Item[]>([]);
$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)

View file

@ -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

View file

@ -0,0 +1,360 @@
---
title: 'Encryption Phasen 19: 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 14** 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 14
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 14 + Encryption-Phasen 19 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 19 | ~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