Item #21 in the pre-launch audit suggested merging the four
config-y packages (shared-config, shared-tsconfig, shared-vite-config,
shared-drizzle-config) into a single @mana/build-config with
conditional exports. The first reality-check of the item counted
package.json declarations and reported 5 total consumer relationships.
A second reality-check while implementing — grep over actual .ts /
.svelte / .json imports — showed two of the four packages are dead:
- packages/shared-config/ (598 LOC, 4 TS files)
Declared in apps/mana/apps/web/package.json but never imported
anywhere. Stale dep from before the consolidation.
- packages/shared-tsconfig/ (5 JSON tsconfig presets)
Zero references anywhere. Not extended by any tsconfig.json,
not declared in any package.json. Pure Pre-Consolidation
leftover.
The remaining two packages were left intact:
- shared-vite-config (3 real consumers in vite.config.ts files)
- shared-drizzle-config (1 real consumer in mana-media)
They cover different toolchains (Vite SSR config vs drizzle-kit
generator config) — merging them into a single build-config would
be cosmetic, not a real reduction in complexity. Audit's "merge to
1" goal was based on the inflated consumer count and is no longer
worth doing.
Verification:
- pnpm install completes cleanly
- apps/api type-check still 0 errors
- packages/shared-hono type-check still 0 errors
Net: 4 → 2 config packages, ~700 LOC dead code removed.
Also closes item #26 (non-root pnpm-lock.yaml status) — already
done in commit 034a07d16, doc was just out of date. Audit is now
29/29 items fully processed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
35 KiB
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.
Die größten Launch-Risiken:
- Recursive Turbo-Hangs (#2) — Build-Pipeline kann steckenbleiben
- Unzureichende Tests für Auth + Encryption (#4) — User-Data-Verlust-Potenzial
- API-Inkonsistenz (#5) — Frontend-Tests brechen bei API-Änderungen
- 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 ").
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.jsonhattedev:webunddev:serverFilter auf nicht-existierende@context/web/@context/serverPackages — entfernt, nurdev:mobilebleibt (das einzige real existierende Sub-Package).apps/planta/package.jsonhattedev:web,dev:server,db:push,db:studio,db:seedFilter auf nicht-existierende@planta/web/@planta/serverPackages — entfernt.apps/planta/enthält nur ein leerespackages/shared/(siehe Audit-Item #11/#18).- Analog ist
apps/storage/undapps/questions/nur ein Stub mitpackages/shared/bzw. nichts — die CLAUDE.md-Files referenzierenapps/{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')undapp.use('*', requestLogger())registriert. Jeder Request bekommt jetztX-Request-Id-Header und wird strukturiert geloggt (request/response, Latenz, Status-Code mit Level-Mapping). Startup-console.logdurchlogger.info('mana-api starting', { port })ersetzt.packages/shared-hono/src/error.ts:errorHandlerbenutzt jetztlogger.error('unhandled', { path, method, message, stack })stattconsole.error('[error]', err). Wirkt für alle Services, dieerrorHandleraus shared-hono verwenden.packages/shared-hono/src/index.ts: Re-exportiertloggeraus@mana/shared-logger, damit Module ohne extra dependency darauf zugreifen können.- 7
console.errorAufrufe inapps/api/src/modules/{guides,planta, nutriphi,traces}/routes.tsdurchlogger.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=jsonin 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 Teststest/e2e-sync-flow.shShell-Testtest/load/Load-Test-Verzeichnis
Echte Lücken — was tatsächlich gemacht wurde:
-
✅
src/auth/sso-config.spec.ts— Wurde in der Root-CLAUDE.mdZeile 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_ORIGINSist auch inmana-auth.CORS_ORIGINSvondocker-compose.macmini.yml - Soft-Warnung für CORS-Drift in der Gegenrichtung
- Kanonische
-
✅
TRUSTED_ORIGINSals exportierte Konstante extrahiert inservices/mana-auth/src/auth/better-auth.config.ts. Der Test importiert sie direkt, statt das File zu parsen — Single Source of Truth. -
✅ Echte Config-Drift gefunden und gefixt: Der Test deckte beim ersten Run drei missing Origins in
docker-compose.macmini.ymlauf (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: Dasmana-authCORS_ORIGINSEnv indocker-compose.macmini.ymlwurde 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::TestFieldChangeRoundTriptestet nur JSON-Round-Trip derChange-Struct, NICHT die LWW-Conflict-Resolution. DierecordChange- Pfade inhandler.gowerden ü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.tsdeckt 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:
-
✅
apps/api/src/lib/responses.tserstellt mit:errorResponse(c, message, status, { code?, details? })— wire-kompatibel mit dem existierendenc.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 alsdetailsrein.listResponse(c, items)— Wrappt in{ items, count }. Frontend muss nicht mehr per-Endpoint zwischenevents/contacts/occurrencesunterscheiden.ErrorBodyundListBody<T>Types für TS-konsumierende Frontends exportiert.
-
✅ Beispielmigration in
apps/api/src/modules/research/routes.ts:validationError(c, parsed.error.issues)stattc.json({ error: 'invalid input', issues: ... }, 400)errorResponse(c, 'not found', 404, { code: 'NOT_FOUND' })stattc.json({ error: 'not found' }, 404)an zwei StellenlistResponse(c, rows)stattc.json(rows)für die Sources-Liste
-
✅ 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.tsist 29 Zeilen Orchestrierung: ruftmana-search:3021/extractzum URL-Holen, dannmana-llm:3030/chatzum Strukturieren. Kein eigenes Compute.services/mana-landing-builder/builder.service.tsist 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 inindex.tshardcoded). Hat nurstores/tags.svelte.ts.spiral/— Cross-App-Aggregator, liest Collections anderer Module viacollect.tsstatt eigene zu führen.core/— Infrastructure/Widget-Registry, keine Daten-Modul.
Plus eine kleine Anomalie:
uload/hatcollections.ts+queries.tsaber keinstores/-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:49hat// TODO: Replace with actual API call to fetch admin stats- Lines 54–63: 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-serverundapps/uload/apps/server. Beide deployed viadocker-compose.macmini.yml. - Alle anderen 17 (
calendar,chat,todo,contacts,picture,cards,planta,nutriphi,news,traces,presi,storage,music,moodlit,context,guides,questions) wurden zuapps/api/src/modules/{name}/routes.tsmigriert. Ihreapps/server/Verzeichnisse existieren nicht mehr. - Die zugehörigen
apps/{product}/CLAUDE.mdbeschreiben 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:
- 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. apps/memoro/CLAUDE.mdkomplett neu schreiben — beschreibt jetzt: Hono-Backend inapps/memoro/apps/server, Audio-Server inapps/memoro/apps/audio-server, Mobile inapps/memoro/apps/mobile, Web-Frontend inapps/mana/apps/web/src/lib/modules/memoro/(falls integriert) ODERapps/memoro/apps/webwenn standalone bleibt.apps/uload/CLAUDE.mdist OK — beschreibt korrekt eigenständigen Server.- Root
CLAUDE.mdist 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, minimaldocker-compose.test.yml(166 Z) — CI-Integration, port-isoliertdocker-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 nurpackages/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 |
games/voxelava/ |
TOT | 83 | Kein Root-package.json, eine types.ts, 3 Monate alt |
games/whopixels/ |
ZOMBIE | 3.2k | Hat package.json (nur dotenv + node-fetch), keine Build-Scripts, Legacy-Statik |
games/worldream/ |
TOT | 210 | Kein Root-package.json, eine types.ts, 3 Monate alt |
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:
export type AppStatus = 'published' | 'beta' | 'development' | 'planning';
Plus:
ManaApp.status: AppStatusPflichtfeld an jedem App-EintragManaApp.archived?: booleanseparates Flag (deckt den audit-vorgeschlagenen'archived'Wert ab)getManaAppsByStatus(status)Helper-Funktion bereits exportiert- Aktuelle Verteilung: 18
beta, 11development, 4published, 3planning
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 — Reality-Check war WIEDER ungenau
Reality-Check #2 (2026-04-09): Beim tatsächlichen Implementieren hat sich der Reality-Check #1 (der nur package.json deps zählte) als falsch herausgestellt. Echte Lage durch grep über alle .ts/.svelte/.json Files:
| Package | Behauptete Consumer (Reality-Check #1) | Echte Code-Consumer |
|---|---|---|
shared-config |
1 (mana/web) | 0 — nur als stale dep deklariert, kein Import |
shared-tsconfig |
0 (via extends) | 0 — null Files extenden es |
shared-vite-config |
3 | 3 (arcade/manavoxel/mana web vite.config.ts) |
shared-drizzle-config |
1 | 1 (mana-media/api drizzle.config.ts) |
Was tatsächlich gemacht wurde: Statt Merge in ein neues
@mana/build-config → 2 von 4 Packages waren reines Dead Code, also
gleicher Move wie #29:
- ✅
packages/shared-config/gelöscht (598 LOC, 4 TS-Files) - ✅
packages/shared-tsconfig/gelöscht (5 JSON-Configs) - ✅ Stale
"@mana/shared-config"dep ausapps/mana/apps/web/package.jsonentfernt - ❌
shared-vite-config+shared-drizzle-configbleiben getrennt — decken unterschiedliche Toolchains ab (vite vs drizzle-kit), Merge wäre kosmetisch
Verifikation: pnpm install clean, apps/api type-check 0 Errors,
packages/shared-hono type-check 0 Errors.
Ergebnis: 4 → 2 Config-Packages, ~700 LOC Dead Code zusätzlich entfernt. Das ursprüngliche "1 build-config Package" Ziel war unrealistisch und unnötig.
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.jsservices/mana-sync/test/load/sync-load.jsmit 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 — erledigt
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— existierte (242 KB), hatte eigenepnpm-workspace.yamldeclarierendapps/*undpackages/*. Aber apps/context/apps/ enthält nur nochmobile, was bereits durch das root-workspace patternapps/*/apps/*abgedeckt ist. Das nested Workspace war reine Pre-Consolidation-Legacy. - 🆕
services/mana-media/packages/client/pnpm-lock.yaml— vom Audit übersehen, echtes Anomaly
Erledigt im Commit 034a07d16 (chore(workspace): remove redundant
nested lockfiles + workspace.yaml):
apps/context/pnpm-lock.yamlgelöschtapps/context/pnpm-workspace.yamlgelöschtservices/mana-media/packages/client/pnpm-lock.yamlgelöscht- Verifiziert:
pnpm installclean (16s),apps/context/apps/mobilekorrekt im root-workspace registriert (perpnpm listconfirmed)
Item geschlossen.
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)ErrorCodeenum +ERROR_CODE_TO_HTTP_STATUSMappings- 8 Error-Klassen (Validation, Auth, NotFound, Credit, Service, RateLimit, Network, Database)
AppExceptionFilterfü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)
serviceErrorHandleraus 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:
apps/memoro/apps/serverist tot — undeklarierte Imports auf notify-client (das niemand sonst nutzt), letzte commits sind nur workspace-weite Chores. Memoro lebt jetzt unterapps/mana. Eigenes Audit-Item wert.shared-vite-config/src/index.ts:14-35noExternal-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 inpackages/existieren. Vite-SSR-Bundling-Config-Drift, harmlos aber irreführend.
Aktion: Vor dem Löschen jedes Package nochmal mit git log -- ...
grep -rfinal 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:
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:
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 fetchResponse.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')iststring | undefined. Guard mitHTTPException(400)ergänzt.storage/routes.ts:96—storage.download()aus@mana/shared-storagegibtPromise<Buffer>zurück, nicht{ body, contentType }. Code rief eine alte API auf. Auf den echten Buffer + parallelesgetMetadata()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 ✅ |
| 🟠 Phase 2 — High | 5 | 5/5 ✅ |
| 🟡 Phase 3 — Medium | 10 | 10/10 ✅ |
| 🟢 Phase 4 — Low | 7 | 7/7 ✅ |
| ➕ Bonus | 2 | 2/2 ✅ |
| Gesamt | 29 | 29/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:
- #12 Admin Mock-Daten (klein, ein TODO-Stelle)
- #14 Stale per-product CLAUDE.md (17 Files + apps/memoro/CLAUDE.md neu schreiben)
- #23 k6-Script für apps/api (optional, klein)
- #26
services/mana-media/packages/client/pnpm-lock.yamllöschen- apps/context Lockfile-Status
- #27 shared-errors entweder löschen oder Hono-Adapter neuschreiben
- #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.