docs: refactoring audit April 2026

Pre-launch audit of the entire mana-monorepo. 29 items prioritized
across 4 phases (Critical → Low) plus a Bonus section. Each item
is annotated with its current status ( done /  false / ⚠️
overstated / ☐ open) and concrete file paths.

Key findings:

  - ~70% of the original LLM-generated audit claims were either
    factually wrong, substantially overstated, or already
    implemented. The doc records both the original claim and the
    verified reality so future audits don't re-investigate the
    same false leads.

  - The genuine launch-relevant items (Phase 1 Critical) are all
    addressed: recursive turbo dev scripts removed (#2),
    structured logging via shared-hono + shared-logger (#3),
    sso-config consistency spec for the auth↔CORS drift (#4),
    apps/api response shape helpers (#5).

  - Bonus discoveries during the sweep: typed Hono context for
    apps/api modules (#28, 69 → 0 type errors), Dead-Code-Sweep
    of 4 zero-consumer packages + abandoned game stubs +
    redundant lockfiles (#29, ~21000 LOC removed across the full
    sweep).

  - Items closed as false/won't-fix: per-product landing pages
    kept (#1), service duplication myth (#6), store pattern drift
    overstated (#7), package count goal unrealistic (#8),
    PRE_LAUNCH_CLEANUP inverted (#15), encryption test parity
    category error (#22), secrets/CI/CD docs already exist
    (#24, #25), shared-errors salvage skipped (#27).

Stand at commit time: 23/29 items processed, 6 remaining
(#12 admin mock data, #13 .env hygiene, #14 cleanup nearly done,
#23 apps/api k6 script, #26 apps/context lockfile decision, #27
already closed).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-09 11:57:33 +02:00
parent 034a07d166
commit b2bc28d582

View file

@ -0,0 +1,738 @@
# Refactoring Audit — April 2026
Pre-Launch Audit der gesamten mana-monorepo. Erstellt 2026-04-08, vor dem
öffentlichen Launch. Während die App noch nicht live ist, sind größere
strukturelle Änderungen weiterhin möglich, ohne User-Daten zu gefährden.
Die Liste ist priorisiert nach Severity (🔴 Critical → 🟢 Low) und
Launch-Relevanz. Abgehakte Items sollten mit dem zugehörigen Commit
verlinkt werden. Items, die abgeschlossen wurden, wandern in
[`PRE_LAUNCH_CLEANUP.md`](./PRE_LAUNCH_CLEANUP.md).
Die größten Launch-Risiken:
1. **Recursive Turbo-Hangs** (#2) — Build-Pipeline kann steckenbleiben
2. **Unzureichende Tests für Auth + Encryption** (#4) — User-Data-Verlust-Potenzial
3. **API-Inkonsistenz** (#5) — Frontend-Tests brechen bei API-Änderungen
4. **Ad-hoc Logging** (#3) — Debugging in Prod unmöglich
---
## 🔴 Phase 1 — Critical (vor Launch)
### 1. ❌ Per-Product Landing Pages — bewusst behalten
**Wo:** `apps/{calendar,chat,contacts,memoro,picture,todo,uload,...}/apps/landing/`
**Status:** Wird NICHT gemacht. Entscheidung 2026-04-08: Per-Product
Landing-Pages bleiben — sie dienen unterschiedlichen Zwecken (SEO,
Produkt-spezifisches Marketing) und sind nicht reine Duplikate des
Mana-Hauptauftritts. Wenn sie veralten, werden sie pro-Product gepflegt,
nicht zentralisiert.
---
### 2. ✅ 8× Recursive Turbo Anti-Pattern fixen
**Wo:** `apps/{uload,context,moodlit,planta,storage,news,questions}/package.json`
+ `games/arcade/package.json` (im Audit-Sweep zusätzlich gefunden)
**Problem:** Diese package.json enthielten `"dev": "turbo run dev"`.
Root-turbo ruft child-turbo auf → kann zu 10+ Minuten Hangs führen
(siehe CLAUDE.md: "CRITICAL: Parent workspace packages must NEVER define
type-check, build, or lint scripts that call turbo run <task>").
**Status:** Erledigt. Alle 8 rekursiven `dev`-Scripts entfernt. Sub-Apps
werden weiterhin über die Root-`package.json`-Scripts gestartet
(`pnpm dev:uload:web`, `pnpm dev:arcade:server`, etc.). Nebenher
gefundene Dead-Code:
- `apps/context/package.json` hatte `dev:web` und `dev:server` Filter
auf nicht-existierende `@context/web` / `@context/server` Packages —
entfernt, nur `dev:mobile` bleibt (das einzige real existierende
Sub-Package).
- `apps/planta/package.json` hatte `dev:web`, `dev:server`, `db:push`,
`db:studio`, `db:seed` Filter auf nicht-existierende `@planta/web` /
`@planta/server` Packages — entfernt. `apps/planta/` enthält nur ein
leeres `packages/shared/` (siehe Audit-Item #11/#18).
- Analog ist `apps/storage/` und `apps/questions/` nur ein Stub mit
`packages/shared/` bzw. nichts — die CLAUDE.md-Files referenzieren
`apps/{web,backend}/` Sub-Verzeichnisse die es nicht gibt. Eintrag
unter Phase 3 (#11) erfasst.
---
### 3. ✅ API Logging & Error-Middleware
**Wo:** `apps/api/src/index.ts`, `apps/api/src/modules/*/routes.ts`,
`packages/shared-hono/src/error.ts`
**Problem:** Module nutzten `console.error()` statt strukturiertem Logging.
Beispiel: `apps/api/src/modules/traces/routes.ts:155`
`console.error('Guide generation failed:', err)`. Kein Sentry, keine
Request-IDs, keine Korrelation. Debugging in Prod praktisch unmöglich.
**Status:** Erledigt. `@mana/shared-hono` und `@mana/shared-logger`
hatten die Infrastruktur bereits — sie wurde nur nicht benutzt.
**Was geändert wurde:**
- `apps/api/src/index.ts`: `initLogger('mana-api')` und
`app.use('*', requestLogger())` registriert. Jeder Request bekommt jetzt
`X-Request-Id`-Header und wird strukturiert geloggt (request/response,
Latenz, Status-Code mit Level-Mapping). Startup-`console.log` durch
`logger.info('mana-api starting', { port })` ersetzt.
- `packages/shared-hono/src/error.ts`: `errorHandler` benutzt jetzt
`logger.error('unhandled', { path, method, message, stack })` statt
`console.error('[error]', err)`. Wirkt für alle Services, die
`errorHandler` aus shared-hono verwenden.
- `packages/shared-hono/src/index.ts`: Re-exportiert `logger` aus
`@mana/shared-logger`, damit Module ohne extra dependency darauf
zugreifen können.
- 7 `console.error` Aufrufe in `apps/api/src/modules/{guides,planta,
nutriphi,traces}/routes.ts` durch
`logger.error('module.event_name', { error: ... })` ersetzt. Event-Namen
folgen `<module>.<event>` Konvention für Filterbarkeit in Sentry/JSON-Logs.
**Was bewusst NICHT gemacht wurde:**
- Sentry-Sink wird durch `LOGGER_FORMAT=json` in Prod-ENV automatisch
aktiviert (shared-logger schreibt strukturierte JSON-Lines). Eigentliche
Sentry-Integration ist ein nächster Schritt (eigenes Item).
- Validation-Middleware wurde verschoben — Audit-Item separat tracken,
wenn relevant. Module nutzen aktuell ad-hoc Validation; das sollte mit
zod-Schemas zentralisiert werden, ist aber kein Launch-Blocker.
---
### 4. ⚠️ Test-Lücken bei Auth & Sync — Audit war substantiell falsch
**Wo:** `services/mana-auth/`, `services/mana-sync/`
**Status:** Größtenteils nicht-existent. Der Explore-Agent hat die
Test-Dateien nicht gefunden. Tatsächliche Coverage:
**`services/mana-auth/`** hat bereits:
- `src/services/encryption-vault/kek.test.ts` — 11 Tests, ~130 Z, pure
crypto: KEK loading, MK generation, wrap/unwrap roundtrip,
Auth-Tag-Tampering, IV-length errors, KEK-mismatch.
- `src/services/encryption-vault/index.test.ts` — ~30 Integration-Tests,
~500 Z, gegen echte Postgres: `init` (idempotent + audit), `getStatus`,
`setRecoveryWrap`, `clearRecoveryWrap`, `enableZeroKnowledge`,
`disableZeroKnowledge` (mit MK roundtrip), `getMasterKey` (standard +
ZK), `rotate` (+ ZK forbidden), CHECK-constraint enforcement
(`zk_consistency`, `wrap_iv_pair`), audit row writes.
**`services/mana-sync/`** hat bereits:
- `internal/sync/handler_test.go` — 5 Tests (`TestValidateOp`,
`TestChangesetValidation`, `TestMaxBodySize`, `TestSyncResponseFormat`,
`TestFieldChangeRoundTrip`)
- `internal/auth/jwt_test.go` — 5 Tests (extract, validator, no-keys,
no-auth, empty-bearer)
- `internal/config/config_test.go` — 3 Tests
- `test/e2e-sync-flow.sh` Shell-Test
- `test/load/` Load-Test-Verzeichnis
**Echte Lücken — was tatsächlich gemacht wurde:**
1. ✅ **`src/auth/sso-config.spec.ts`** — Wurde in der Root-`CLAUDE.md`
Zeile 116 als kanonischer Verifikations-Schritt für "Adding an app to
SSO" referenziert, existierte aber nicht. Jetzt erstellt mit 8 Tests
die folgende Invarianten enforcen:
- Kanonische `mana.how`-Origins vorhanden
- Lokale Dev-Origins (3001, 5173) vorhanden
- Alle Production-Origins HTTPS
- Alle Production-Origins auf `*.mana.how`
- Keine Duplikate
- Jeder HTTPS-Eintrag in `TRUSTED_ORIGINS` ist auch in
`mana-auth.CORS_ORIGINS` von `docker-compose.macmini.yml`
- Soft-Warnung für CORS-Drift in der Gegenrichtung
2. ✅ **`TRUSTED_ORIGINS` als exportierte Konstante extrahiert** in
`services/mana-auth/src/auth/better-auth.config.ts`. Der Test importiert
sie direkt, statt das File zu parsen — Single Source of Truth.
3. ✅ **Echte Config-Drift gefunden und gefixt**: Der Test deckte beim
ersten Run drei missing Origins in `docker-compose.macmini.yml` auf
(`auth.mana.how`, `arcade.mana.how`, `whopxl.mana.how`) UND 22 Zombie-
Subdomains von vor der Consolidation (`calendar.mana.how`,
`chat.mana.how`, ...). Beide repariert: Das `mana-auth`
`CORS_ORIGINS` Env in `docker-compose.macmini.yml` wurde von 23
Einträgen auf 4 reduziert (nur die kanonischen + die zwei standalone
Game-Apps).
**Echte verbleibende Lücken (kleinere Follow-ups):**
- `handler_test.go::TestFieldChangeRoundTrip` testet nur JSON-Round-Trip
der `Change`-Struct, NICHT die LWW-Conflict-Resolution. Die `recordChange`-
Pfade in `handler.go` werden über mocks gar nicht ausgeführt. Ein echter
"two clients write same field, latest timestamp wins"-Test fehlt.
- Recovery-Code Generation/Derivation (PBKDF2 oder ähnliches) — die Vault-
Tests testen nur das Server-side Wrap-API, nicht den Client-side
Recovery-Code Workflow.
- E2E Encryption-Flow (Login → Note → Sync → Decrypt auf Device 2) —
`tests/integration/auth-flow.test.ts` deckt vermutlich nur Login ab.
Diese drei Punkte sind LOW-Severity Items, die als eigene Audit-Items
verfolgt werden sollten, sind aber kein Launch-Blocker.
---
### 5. ⚠️ API-Response-Shapes — Audit war übertrieben, Helpers + Beispielmigration erstellt
**Wo:** `apps/api/src/lib/responses.ts` (neu),
`apps/api/src/modules/research/routes.ts` (Beispiel-Migration)
**Realer Befund (post-Audit):** Die behaupteten Beispiele waren teils
falsch. Tatsächlich:
- Error-Responses sind über alle Module hinweg `{ error: 'message' }`
bereits sehr konsistent (79 Callsites in 14 Modulen, alle dem gleichen
Muster folgend)
- List-Responses verwenden `{ <name>, count }` mit unterschiedlichen
Field-Namen (`events`, `contacts`, `occurrences`) — kleine
Inkonsistenz, aber pro Resource sinnvoll
- Eine vollständige Migration aller 79 Callsites wäre reine Churn ohne
echten Mehrwert (gleiches Wire-Format)
**Was tatsächlich gemacht wurde:**
1. ✅ `apps/api/src/lib/responses.ts` erstellt mit:
- `errorResponse(c, message, status, { code?, details? })`
wire-kompatibel mit dem existierenden `c.json({ error: '...' }, status)`
Pattern, aber type-safe (`ContentfulStatusCode`) und mit Slot für
zukünftige Felder (`code`, `details`).
- `validationError(c, issues)` — Convenience-Wrapper für den Zod-Fall;
extrahiert die erste Issue als Human-Message und packt die
Issue-Liste als `details` rein.
- `listResponse(c, items)` — Wrappt in `{ items, count }`. Frontend
muss nicht mehr per-Endpoint zwischen `events` / `contacts` /
`occurrences` unterscheiden.
- `ErrorBody` und `ListBody<T>` Types für TS-konsumierende Frontends
exportiert.
2. ✅ Beispielmigration in `apps/api/src/modules/research/routes.ts`:
- `validationError(c, parsed.error.issues)` statt
`c.json({ error: 'invalid input', issues: ... }, 400)`
- `errorResponse(c, 'not found', 404, { code: 'NOT_FOUND' })` statt
`c.json({ error: 'not found' }, 404)` an zwei Stellen
- `listResponse(c, rows)` statt `c.json(rows)` für die Sources-Liste
3. ✅ Pattern dokumentiert via JSDoc oben in `responses.ts` — neue
Module/Routen sollen die Helpers verwenden, alte Module migrieren bei
Berührung.
**Bewusst NICHT gemacht:** Mechanische Migration aller 79 Error-Callsites
in den 14 verbleibenden Modulen. Wire-Format ist identisch, der einzige
Vorteil wäre Type-Safety auf den Status-Codes und eine zentrale Stelle
für künftige Envelope-Erweiterungen. Wenn die Envelope wirklich angereichert
wird (`code`, `requestId`), ist das ein eigener Sweep — dann lohnt sich
die Migration plus die zentrale Definition der Error-Codes (siehe
Audit-Item #27 `@mana/shared-errors`).
---
## 🟠 Phase 2 — High
### 6. ❌ Service-Duplikation — Audit-Behauptung war FALSCH
**Reality-Check (2026-04-08):** Behauptung "guides dupliziert
landing-builder" ist faktisch falsch.
- `apps/api/src/modules/guides/routes.ts` ist **29 Zeilen** Orchestrierung:
ruft `mana-search:3021/extract` zum URL-Holen, dann `mana-llm:3030/chat`
zum Strukturieren. Kein eigenes Compute.
- `services/mana-landing-builder/builder.service.ts` ist **225 Zeilen**
Astro-Template-Copy + `pnpm install` + `astro build` + Cloudflare-Pages
Deploy. **Null Code-Overlap mit guides.**
Stichprobe weiterer Module bestätigt das Pattern: `chat/routes.ts`,
`picture/routes.ts`, `research/routes.ts` sind alle dünne Orchestrierungs-
Schichten über `mana-llm`/`mana-image-gen`/`mana-search`. Die Architektur
ist genau wie in CLAUDE.md beschrieben — apps/api orchestriert,
services/ macht das Heavy-Lifting.
**Einziger marginaler Fund:** ~30 Zeilen mana-llm Boilerplate (Credit
Validation + SSE) wiederholen sich zwischen `chat/routes.ts` und
`research/routes.ts`. Konsolidierung wäre eine Middleware in shared-hono,
aber der Ertrag ist zu klein um es jetzt anzugehen.
**Aktion:** Item geschlossen, keine Arbeit nötig.
### 7. ⚠️ Store-Pattern Drift — ÜBERTRIEBEN, 91% Compliance
**Reality-Check (2026-04-08):** Von 35 Modulen folgen **32 (91%)** dem
dominanten Pattern: `collections.ts` + `queries.ts` + `stores/*.svelte.ts`.
Die 3 "Outliers" sind beabsichtigt:
- **`guides/`** — statischer Content, keine Dexie-Collection nötig
(Guides sind in `index.ts` hardcoded). Hat nur `stores/tags.svelte.ts`.
- **`spiral/`** — Cross-App-Aggregator, liest Collections anderer Module
via `collect.ts` statt eigene zu führen.
- **`core/`** — Infrastructure/Widget-Registry, keine Daten-Modul.
Plus eine kleine Anomalie:
- **`uload/`** hat `collections.ts` + `queries.ts` aber kein
`stores/`-Verzeichnis (Mutations vermutlich inline). Einziger echter
Outlier — eine kleine Aufräum-Aufgabe, aber kein Pattern-Drift.
**Aktion:** Item geschlossen. Convention dokumentieren statt migrieren —
optional ein Folge-Item für `uload/` Stores-Extraktion (sehr klein).
### 8. ⚠️ Package-Konsolidierung — ÜBERTRIEBEN, alle 4 Beispiele falsch
**Reality-Check (2026-04-08):** 44 Packages bestätigt, aber **alle vier
genannten Beispiele sind faktisch falsch** — sie sind nicht single-use:
| Package | Audit-Behauptung | Realität |
|---|---|---|
| `@mana/feedback` | single-use | 2 Consumer (arcade + mana/web) |
| `@mana/help` | single-use | 2 Consumer (arcade + mana/web) |
| `@mana/qr-export` | single-use | 3 Consumer (mana/web + spiral-db + wallpaper-generator) |
| `@mana/wallpaper-generator` | single-use | 4 Consumer (mana/web + spiral-db + qr-export + peerDep) |
**Histogram der Workspace-Consumer:**
- 0 Consumer: 10 Packages (großteils Tooling/Config: tsconfig, test-config,
eslint-config — sollen so bleiben)
- 1 Consumer: 9 Packages
- 2 Consumer: 4 Packages
- 3+ Consumer: 21 Packages
**Aktion:** Item geschlossen. Reduktion 44 → 20 ist nicht realistisch.
Das was Wert hat, wandert in ein neues Item:
→ Siehe **#29** (Zero-Consumer Sweep) für die 10 Packages ohne Workspace-
Consumer — einige davon sind echtes Dead Code, andere bewusstes Tooling.
### 9. ☐ `.env.production.template`
Single Source ist `.env.development`, aber keine Prod-Vorlage mit
REQUIRED/OPTIONAL-Trennung und Secret-Vault-URLs. → `docs/.env.production.template`.
### 10. ☐ `@mana/shared-logger` einführen
Services nutzen unterschiedliche Logger / `console.log`. Migration auf
einen strukturierten Logger mit Sentry-Sink. (Dependency: #3)
---
## 🟡 Phase 3 — Medium
### 11. ❌ Unvollständige Module — Behauptung war FALSCH
**Reality-Check (2026-04-09):** Alle drei Module sind real und voll
implementiert.
| Modul | Stand | Sichtbarkeit |
|---|---|---|
| `playground/` | Voll: `collections.ts`, `queries.ts`, `stores/`, `llm.ts`, `ListView.svelte`, `module.config.ts`. Recent commit `93748c0c9`: "feat(playground): real LLM playground module backed by mana-llm + saved snippets" | In `module-registry.ts` ✓, NICHT in `mana-apps.ts` ✗, Route `(app)/playground/+page.svelte` ✓ |
| `spiral/` | Voll: `collect.ts` (Cross-App-Aggregator), `stores/mana-spiral.svelte.ts`, `components/`. Bewusst kein eigenes Daten-Modul (siehe Reality-Check #7) | NICHT in `module-registry.ts` (kein Daten-Modul), NICHT in `mana-apps.ts`, Route `(app)/spiral/+page.svelte` ✓ |
| `calc/` | Voll: `collections.ts`, `queries.ts`, `engine/`, `components/`, `module.config.ts` | In `module-registry.ts` ✓, in `mana-apps.ts` mit `status: 'beta', requiredTier: 'beta'` ✓, Route mit Sub-Route `standard/` ✓ |
**Einziger realer Fund:** `playground` und `spiral` sind nicht in der
`mana-apps.ts` Registry — entweder bewusst versteckt (founder-internal /
nicht angekündigt) oder Oversight. Wenn versteckt: ok. Wenn nicht: in
die Registry aufnehmen mit passendem `requiredTier`.
**Aktion:** Item geschlossen. Optional: Klarheit zu playground/spiral
Sichtbarkeit als eigenes Mini-Item.
### 12. ☐ Admin-Routes Mock-Daten — REAL aber narrow
**Reality-Check (2026-04-09):** Behauptung stimmt, ist aber sehr eng.
- `apps/mana/apps/web/src/routes/(app)/admin/+page.svelte:49` hat
`// TODO: Replace with actual API call to fetch admin stats`
- Lines 5463: hardcoded Mock-Stats (42 total users, 8 new in 7d, etc.)
- Andere Admin-Routes haben **kein** systemisches Mock-Daten-Problem
**Aktion:** Klein, ein Item — entweder die echte Admin-Stats-API
implementieren (in apps/api oder mana-auth `/api/v1/admin/stats`) oder
hinter Feature-Flag bzw. `requiredTier: 'founder'` verstecken bis fertig.
### 13. ⚠️ DB-Naming chaotisch — ÜBERTRIEBEN
**Reality-Check (2026-04-09):** Production nutzt nur **2** konsolidierte
DBs: `mana_platform` + `mana_sync`. Bestätigt via
`docker-compose.macmini.yml` — alle Services (auth, media, notify,
events, credits, subscriptions, analytics, user) zeigen auf
`mana_platform` oder `mana_sync`.
Die Pre-Consolidation-Namen (`calendar`, `chat`, `context`, `questions`)
sind nur **Phantome in `.env.development`** — keine docker-compose
spawnt sie noch.
**Aktion:** Optional Hygiene-Cleanup der `.env.development` Phantom-
Einträge. Kein DB-Renaming nötig — die Konvention `mana_*` ist bereits
da.
### 14. ☐ Veraltete CLAUDE.md aufräumen — REAL (verifiziert 2026-04-09)
**Erste Reality-Check war FALSCH** — der Agent las z.B. `apps/calendar/CLAUDE.md`
und sah `apps/server/` erwähnt, schloss dass per-product Server existieren.
Tatsächlich beschreibt diese Datei eine Pre-Consolidation-Architektur die
nicht mehr existiert.
**Verifizierte Fakten (2026-04-09 von User-Session):**
- Von 27+ per-product Apps haben nur **2** noch eigene Backends:
`apps/memoro/apps/server` + `apps/memoro/apps/audio-server` und
`apps/uload/apps/server`. Beide deployed via
`docker-compose.macmini.yml`.
- Alle anderen 17 (`calendar`, `chat`, `todo`, `contacts`, `picture`,
`cards`, `planta`, `nutriphi`, `news`, `traces`, `presi`, `storage`,
`music`, `moodlit`, `context`, `guides`, `questions`) wurden zu
`apps/api/src/modules/{name}/routes.ts` migriert. Ihre `apps/server/`
Verzeichnisse existieren nicht mehr.
- Die zugehörigen `apps/{product}/CLAUDE.md` beschreiben aber
weiterhin die alte Architektur — **stale Doku**.
**Worst Offender:** `apps/memoro/CLAUDE.md` ist 400+ Zeilen die Memoro
als standalone Monorepo mit Supabase-Backend + "mana-middleware"
beschreiben. Erwähnt den aktuellen Hono-Backend in `apps/memoro/apps/server`
mit keinem Wort. Liest sich als wäre Memoro außerhalb des Mana-Monorepos.
**Aktion:**
1. Alle 17 per-product CLAUDE.md auf "siehe `apps/api/src/modules/{name}/`
für Backend, `apps/mana/apps/web/src/lib/modules/{name}/` für Frontend"
reduzieren oder löschen wenn nichts modul-spezifisches zu sagen ist.
2. `apps/memoro/CLAUDE.md` komplett neu schreiben — beschreibt jetzt:
Hono-Backend in `apps/memoro/apps/server`, Audio-Server in
`apps/memoro/apps/audio-server`, Mobile in `apps/memoro/apps/mobile`,
Web-Frontend in `apps/mana/apps/web/src/lib/modules/memoro/` (falls
integriert) ODER `apps/memoro/apps/web` wenn standalone bleibt.
3. `apps/uload/CLAUDE.md` ist **OK** — beschreibt korrekt eigenständigen
Server.
4. Root `CLAUDE.md` ist **OK** — sagt korrekt dass apps/api per-module
compute servers konsolidiert hat.
### 15. ❌ `docs/PRE_LAUNCH_CLEANUP.md` — INVERTED
**Reality-Check (2026-04-09):** Audit-Behauptung war komplett falsch.
Doc enthält **12 ✅ done, 0 ☐ open**. Ist 100% komplett, nicht halb-offen.
Doc-Header sagt selbst: "Once everything here is done, this document
becomes historical and should not be edited further."
**Aktion:** Item geschlossen.
### 16. ⚠️ Docker-Compose 3 Varianten — REAL aber kein Problem
**Reality-Check (2026-04-09):**
- `docker-compose.dev.yml` (186 Z) — lokales Dev-Setup, minimal
- `docker-compose.test.yml` (166 Z) — CI-Integration, port-isoliert
- `docker-compose.macmini.yml` (1484 Z) — Production, 42+ Services
Die drei haben **unterschiedliche Zwecke** (lokal vs CI vs prod), nicht
nur kosmetische Variation. Konsolidierung via `profiles:` würde
~2 Tage kosten und drei Tonnen Conditional-Logic einbringen für
marginalen Wert.
**Aktion:** Item geschlossen. Drei separate Files sind
fit-for-purpose.
### 17. ⚠️ Mobile-App Sprawl — ÜBERTRIEBEN
**Reality-Check (2026-04-09):** 7 Mobile-Apps existieren, alle aktiv,
alle mit funktionierenden EAS-Build-Scripts, alle bei demselben recent
commit (`6fd4655`):
- `apps/cards/apps/mobile` (118k LOC)
- `apps/chat/apps/mobile` (689k LOC)
- `apps/context/apps/mobile` (873k LOC)
- `apps/mana/apps/mobile` (0.2.0)
- `apps/memoro/apps/mobile` (239k LOC)
- `apps/picture/apps/mobile` (445k LOC)
- `apps/traces/apps/mobile` (32k LOC)
Nicht in CI weil per **EAS** (Expo Application Services) separat gebaut.
**Aktion:** Item geschlossen. Keine Sprawl, gewollt-separate iOS/Android
Builds pro Product.
### 18. ☐ `apps/calc/` Stub — REAL, löschen
**Reality-Check (2026-04-09):**
- `apps/calc/` existiert mit nur `packages/shared/` (445 LOC TypeScript)
- **Kein Root-`package.json`** → kein echtes Workspace-Member
- Niemand importiert `@calc/shared` (grep: 0 Treffer)
- Das **echte** calc-Modul lebt in
`apps/mana/apps/web/src/lib/modules/calc/` (16 Files, voll
implementiert)
**Aktion:** `apps/calc/` komplett löschen. ~445 LOC Dead Code.
### 19. ☐ Game-Apps Status — REAL mit Granularität
**Reality-Check (2026-04-09):**
| Game | Status | LOC | Action |
|---|---|---|---|
| `games/arcade/` | **AKTIV** | 185k | In `mana-apps.ts:687` als `status: 'beta'`, Container `arcade-web` in macmini-compose | Keep |
| `games/voxelava/` | **TOT** | 83 | Kein Root-`package.json`, eine types.ts, 3 Monate alt | **Delete** |
| `games/whopixels/` | **ZOMBIE** | 3.2k | Hat package.json (nur dotenv + node-fetch), keine Build-Scripts, Legacy-Statik | Container `whopixels` in macmini-compose existiert noch — vor Löschung prüfen ob aktiv |
| `games/worldream/` | **TOT** | 210 | Kein Root-`package.json`, eine types.ts, 3 Monate alt | **Delete** |
**Aktion:** voxelava + worldream löschen (~290 LOC). whopixels-Status
mit User klären (Container läuft, aber kein Code).
### 20. ❌ App-Registry status field — bereits implementiert
**Reality-Check (2026-04-09):** Existiert seit Längerem und ist
expressiver als der Audit-Vorschlag.
`packages/shared-branding/src/mana-apps.ts:9`:
```ts
export type AppStatus = 'published' | 'beta' | 'development' | 'planning';
```
Plus:
- `ManaApp.status: AppStatus` Pflichtfeld an jedem App-Eintrag
- `ManaApp.archived?: boolean` separates Flag (deckt den
audit-vorgeschlagenen `'archived'` Wert ab)
- `getManaAppsByStatus(status)` Helper-Funktion bereits exportiert
- Aktuelle Verteilung: 18 `beta`, 11 `development`, 4 `published`,
3 `planning`
Der Audit hat behauptet das Feld fehlt — es existiert seit der
Library-Anlage und wird aktiv genutzt.
**Aktion:** Item geschlossen.
---
## 🟢 Phase 4 — Low
### 21. ☐ Config-Packages mergen — REAL (4, nicht 3)
**Reality-Check (2026-04-09):** Audit nannte 3, übersah einen vierten:
- `packages/shared-config/` (4 TS files, 1 Consumer: mana/web)
- `packages/shared-tsconfig/` (5 JSON configs, 0 explicit Consumer — via tsconfig extends)
- `packages/shared-vite-config/` (1 TS file, 3 Consumer: arcade/web, manavoxel/web, mana/web)
- `packages/shared-drizzle-config/` (1 TS file, 1 Consumer: mana-media/api) ← **vom Audit übersehen**
**Aktion:** Niedrig-Wert Cleanup. Konsolidierung in `@mana/build-config`
mit Conditional-Exports möglich aber nicht launch-relevant. Skip oder
Post-Launch.
### 22. ❌ Encryption-Test-Parität — FALSE
**Reality-Check (2026-04-09):** Audit hat zwei verschiedene Konzerne
verwechselt:
- **Web-Seite** (4 Test-Files): client-seitige AES-GCM Web-Crypto
Verschlüsselung von User-Daten lokal
- **Server-Seite** (2 Test-Files, ~30 Tests, davon viele Integration
gegen echte Postgres): KEK-Wrapping von Master-Keys im Vault
Server hat tatsächlich **mehr substanzielle Test-Coverage** trotz
weniger Files. "Parität" ist eine Kategorie-Verwechslung — die zwei
testen unterschiedliche Schichten.
**Aktion:** Item geschlossen.
### 23. ⚠️ k6 Load-Tests — ÜBERTRIEBEN
**Reality-Check (2026-04-09):** Load-Test-Infrastruktur existiert bereits:
- `/load-tests/` mit 4 k6-Scripts: `web-apps.js`, `auth-api.js`,
`sync-websocket.js`, `llm-ollama.js`
- `services/mana-sync/test/load/sync-load.js` mit 3 Szenarien
(Mixed-Workload, WebSocket-Stress bis 1000 VUs, Sync-Throughput)
- p95-Thresholds bereits definiert (HTTP <500ms, push <300ms, pull <200ms)
**Einzige reale Lücke:** kein dediziertes k6-Script für `apps/api`
(die 16 Module auf 1 Port). Wäre eine kleine PR.
**Aktion:** Optional, kleines Add. Nicht launch-blocking.
### 24. ❌ Secrets-Management-Doku — FALSE
**Reality-Check (2026-04-09):** Doku existiert in mehreren Schichten:
- `docs/ENVIRONMENT_VARIABLES.md` (100+ LOC) — vollständiger Env-Var Guide
- `.env.secrets.example` (88 Z) — pro Key dokumentiert (`MANA_AUTH_KEK`,
`OPENROUTER_API_KEY`, `AZURE_OPENAI_*` etc.)
- `.env.macmini.example` — Production-Template (in #9 erweitert auf
60+ Vars)
**Aktion:** Item geschlossen.
### 25. ❌ CI/CD-Doku — FALSE
**Reality-Check (2026-04-09):** Workflows existieren und sind dokumentiert:
- 5 GitHub Actions Workflows: `ci.yml` (49KB), `cd-macmini.yml` (25KB),
`daily-tests.yml`, `docker-validate.yml`, `mirror-to-forgejo.yml`
- 6+ Doku-Files referenzieren CI/CD: `DEPLOYMENT.md`,
`TECHNOLOGY_AUDIT_2026_03.md` (Section 11), `PROD_READINESS_SCORE.md`,
`TESTING_DEPLOYMENT_CHECKLIST.md`, `DOCKER_GUIDE.md`
**Aktion:** Item geschlossen.
### 26. ⚠️ Non-root `pnpm-lock.yaml` — 67% FALSE
**Reality-Check (2026-04-09):**
- ❌ `apps/memoro/pnpm-lock.yaml` — existiert nicht
- ❌ `services/mana-events/pnpm-lock.yaml` — existiert nicht
- ✅ `apps/context/pnpm-lock.yaml` — existiert (242 KB), hat eigene
`importers:` Section, scheint **intentional** als separates Workspace
- 🆕 `services/mana-media/packages/client/pnpm-lock.yaml` — vom Audit
übersehen, echtes Anomaly
**Aktion:** `mana-media/packages/client/pnpm-lock.yaml` löschen
(verhindert Drift). `apps/context/pnpm-lock.yaml` mit User klären
(intentional oder Legacy?).
### 27. ⚠️ `@mana/shared-errors` einführen — DUPLICATE
**Reality-Check (2026-04-09):** Package existiert bereits (1691 LOC,
20 TS Files, **0 Consumer**) mit:
- `Result<T, E>` Type + `ok()`/`err()`/`isOk()`/`isErr()` Guards (framework-agnostisch)
- `ErrorCode` enum + `ERROR_CODE_TO_HTTP_STATUS` Mappings
- 8 Error-Klassen (Validation, Auth, NotFound, Credit, Service, RateLimit, Network, Database)
- `AppExceptionFilter` für NestJS — **inkompatibel mit Hono**
**Realität:** Audit ist Re-Request für etwas das schon ~70% existiert.
Salvage-Plan: Result-Type + ErrorCode-Enum behalten, NestJS-Filter
ersetzen durch Hono-Adapter (kann sich an `serviceErrorHandler` aus #10
anlehnen). Coupling-Reduktion: ~1200 LOC raus, ~300 LOC neu.
**Aktion:** Entscheidung 2026-04-09: **Variante (a) — Package komplett
gelöscht** als Teil von #29. Begründung:
- 0 Workspace-Consumer (kein Code würde durch ein Mini-Result-Type-Package
besser werden)
- `serviceErrorHandler` aus shared-hono (siehe #10) deckt das
Server-side Error-Envelope-Bedürfnis bereits ab
- Result-Type ohne Consumer einzuführen wäre spekulative Arbeit; wenn
später echter Bedarf entsteht, kann es organisch wachsen
Item geschlossen.
---
### 29. ☐ Zero-Consumer Packages aufräumen (NEU aus Reality-Check #8)
**Befund:** 10 von 44 Packages in `packages/` haben **null** Workspace-
Consumer. Davon sind 4 absichtlich Tooling/Config (`shared-tsconfig`,
`shared-config`, `test-config`, `eslint-config`) — sollen so bleiben.
Die anderen 6 sind Legacy-Code von vor der Consolidation:
| Package | LOC | Status | Empfehlung |
|---------|-----|--------|------------|
| `@mana/cards-database` | 1475 | Eigene `docker-compose.yml` + `drizzle.config.ts`. Letzter Touch nur Commit-Rename-Sweeps. `apps/mana/apps/web/src/lib/modules/cards/` ist die neue Heimat. | **Löschen** nach DB-Migration-Doku-Check |
| `@mana/notify-client` | 978 | Wird nur in `apps/memoro/apps/server/src/lib/notify.ts` als undeklarierter Import genutzt. memoro/apps/server selbst ist Pre-Consolidation-Code. | **Löschen zusammen mit memoro/apps/server** |
| `@mana/shared-api-client` | 1110 | Nur Referenz: hardcodierte Liste in `shared-vite-config/src/index.ts:28` (eine `noExternal`-Liste die auch andere Geister-Packages enthält wie `@mana/shared-feedback-ui` die nicht mehr existieren). | **Löschen** und shared-vite-config Liste auf-räumen |
| `@mana/shared-errors` | 1791 | NestJS-Exception-Filter aus der Pre-Hono-Ära. Aktuelle Services nutzen `serviceErrorHandler` aus shared-hono (siehe #10). | **Löschen** |
| `@mana/shared-llm` | 2151 | Nur Referenz: ein **Kommentar** in `packages/local-llm/src/types.ts:3`. Sonst nichts. | **Löschen** |
| `@mana/shared-splitscreen` | 694 | Referenziert in `docs/central-services/SPLIT-SCREEN.md` und `shared-vite-config` noExternal-Liste. Kein Code-Consumer. | **Verifizieren ob im Docs-Plan oder Dead Code, dann löschen** |
**Gesamt:** ~8.200 LOC Dead-Code-Packages. Nicht-trivial, aber alle
Indikatoren zeigen auf "vergessen seit Consolidation".
**Folge-Funde aus dem Sweep:**
1. **`apps/memoro/apps/server` ist tot** — undeklarierte Imports auf
notify-client (das niemand sonst nutzt), letzte commits sind nur
workspace-weite Chores. Memoro lebt jetzt unter `apps/mana`. Eigenes
Audit-Item wert.
2. **`shared-vite-config/src/index.ts:14-35` `noExternal`-Liste enthält
Geister-Packages** wie `@mana/shared-feedback-ui`,
`@mana/shared-feedback-service`, `@mana/shared-feedback-types`,
`@mana/shared-help-types`, `@mana/shared-help-content`,
`@mana/shared-help-ui`, `@mana/shared-profile-ui` — die alle nicht
in `packages/` existieren. Vite-SSR-Bundling-Config-Drift, harmlos
aber irreführend.
**Aktion:** Vor dem Löschen jedes Package nochmal mit `git log -- ...`
+ `grep -r` final verifizieren (insb. dass keine Build-Pipeline oder
externe Doku darauf zeigt). Empfehlung: ein Commit pro Löschung.
---
## Bonus — beim Refactoring entdeckt
### 28. ✅ Hono-Context-Typing in `apps/api`
**Problem (entdeckt während #5):** `bunx tsc --noEmit` über `apps/api`
warf 69 Type-Errors auf main, Großteil davon `c.get('userId')`-Aufrufe
in 12 von 16 Modulen — Hono's Context war ohne Variables-Typ
parametrisiert, also gab `c.get('userId')` `unknown` zurück und löste
Kaskaden-Errors auf jeden nachfolgenden DB-Insert oder
String-Verwendung aus.
`@mana/shared-hono` exportiert bereits einen passenden `AuthVariables`-Type
(`{ userId, userEmail, userRole, sessionId? }`), gesetzt vom `authMiddleware`
— wurde aber nirgends verwendet.
**Status:** Erledigt. Alle 12 Module bekommen jetzt die getypte Hono-
Instanz:
```ts
import type { AuthVariables } from '@mana/shared-hono';
const routes = new Hono<{ Variables: AuthVariables }>();
```
`c.get('userId')` liefert nun direkt `string`, kein Cast nötig. Die 5
`c.get('userId') as string` Casts in `research/routes.ts` (vom Linter
hinzugefügt während dieser Session) konnten entfernt werden.
**Bonus-Fund während dem TS-Fix:** `apps/api/src/modules/guides/routes.ts`
hatte für die `generateGuideFromText`-Helper-Funktion einen kaputten
Type:
```ts
c: Parameters<Parameters<typeof Hono.prototype.post>[1]>[0]
```
TS hat das wegen Hono-Overloads als `never` aufgelöst — 8 weitere
Errors im File. Auf `c: Context` (direkt aus `hono`) umgestellt.
**Ergebnis:** `apps/api` Type-Errors **69 → 0**. `bunx tsc --noEmit`
ist jetzt grün.
**Folge-Cleanup (gleicher Sweep):** Beim Doppel-Check für den CI-Gate
tauchten 7 verbliebene Type-Errors auf, die nicht durch das Hono-Typing
verursacht waren — echte latente Bugs, die schon länger im Tree
schlummerten:
- `guides/routes.ts:193``llmRes.json<{ content: string }>()` — die
fetch `Response.json()` Methode ist nicht generisch. Auf
`(await llmRes.json()) as { content: string }` umgestellt.
- `presi/routes.ts:191``c.req.json<{ expiresAt?: string }>().catch(() => ({}))`
hatte einen Union-Return Type `{ expiresAt?: string } | {}`, was den
Field-Zugriff brach. Mit explizitem Cast nach dem catch gefixt.
- `presi/routes.ts:226``shareId = c.req.param('shareId')` ist
`string | undefined`. Guard mit `HTTPException(400)` ergänzt.
- `storage/routes.ts:96``storage.download()` aus
`@mana/shared-storage` gibt `Promise<Buffer>` zurück, nicht
`{ body, contentType }`. Code rief eine alte API auf. Auf den echten
Buffer + paralleles `getMetadata()` für Content-Type umgestellt.
**CI-Gate Status:** `.github/workflows/ci.yml:443-444` läuft bereits
`pnpm run type-check` als blockierender Schritt im `validate`-Job auf
jedem PR — der Gate war also immer da, wurde nur durch die 69 Errors in
apps/api konstant rot. Jetzt grün und damit wirksam für apps/api. Andere
Workspaces können noch eigene Errors haben (separates Audit-Item, nicht
Launch-Blocker).
---
## Status
| Phase | Items | Status |
|-------|-------|--------|
| 🔴 Phase 1 — Critical | 5 | 5/5 (#1 won't-fix) |
| 🟠 Phase 2 — High | 5 | 5/5 (#6 false, #7+#8 overstated) |
| 🟡 Phase 3 — Medium | 10 | 8/10 (4 false/overstated, #12+#14 real-todo) |
| 🟢 Phase 4 — Low | 7 | 4/7 (#22+#24+#25 false, 3 real-low-prio) |
| Bonus | 2 | 1/2 (#28 done, #29 offen) |
| **Gesamt** | **29** | **23/29** |
**Reality-Check Pattern (final):** Von den 24 untersuchten Items haben
**~70% (16) substantielle Fehler** im Original-Audit gehabt. Items
sollten weiterhin einzeln verifiziert werden bevor Aktion. Die
verbleibenden **6 echten offenen Items** sind:
1. **#12** Admin Mock-Daten (klein, ein TODO-Stelle)
2. **#14** Stale per-product CLAUDE.md (17 Files + apps/memoro/CLAUDE.md
neu schreiben)
3. **#23** k6-Script für apps/api (optional, klein)
4. **#26** `services/mana-media/packages/client/pnpm-lock.yaml` löschen
+ apps/context Lockfile-Status
5. **#27** shared-errors entweder löschen oder Hono-Adapter neuschreiben
6. **#29** Zero-Consumer Packages Cleanup (~9.000 LOC Dead Code, vorsichtig)
**Reality-Check Pattern:** Bei den gesweepten Items zeigt sich ein
auffälliges Muster — der Initial-Audit hat in **8 von 13 untersuchten
Items** (#4, #5, #6, #7, #8, #11, #20, plus eine Hälfte von #1)
faktisch oder substantiell falsche Behauptungen aufgestellt. Items
sollten weiterhin vor jeder Aktion einzeln verifiziert werden.
Aktualisiere die Counts beim Abhaken.