diff --git a/docs/CONSOLIDATION_OPPORTUNITIES.md b/docs/CONSOLIDATION_OPPORTUNITIES.md new file mode 100644 index 000000000..fab1b9d66 --- /dev/null +++ b/docs/CONSOLIDATION_OPPORTUNITIES.md @@ -0,0 +1,451 @@ +# Konsolidierungsmöglichkeiten - Monorepo Analyse + +> Erstellt: 29. Januar 2026 +> Geschätzte Gesamteinsparung: **~6.500-8.000 LOC** + +## Übersicht nach Priorität + +| Priorität | Bereich | Geschätzte Einsparung | Aufwand | +|-----------|---------|----------------------|---------| +| **KRITISCH** | Backend Metrics Migration | 350 LOC | Niedrig | +| **HOCH** | Skeleton Components | 800-1.000 LOC | Mittel | +| **HOCH** | App Settings Stores | 600-700 LOC | Mittel | +| **HOCH** | Main.ts/CORS Patterns | 1.800 LOC | Mittel | +| **MITTEL** | TypeScript Configs | 400 LOC | Niedrig | +| **MITTEL** | UI Component Cleanup | 400 LOC | Niedrig | +| **MITTEL** | Vite Configs | 300 LOC | Niedrig | +| **MITTEL** | Navigation Stores | 50 LOC | Niedrig | +| **NIEDRIG** | Drizzle Configs | 200 LOC | Niedrig | +| **NIEDRIG** | Logger Utilities | 130 LOC | Niedrig | + +--- + +## 1. Backend Patterns (NestJS) + +### 1.1 KRITISCH: Metrics Migration (350 LOC) + +**Problem:** 7 Backends haben lokale `MetricsService` Implementierungen, obwohl `@manacore/shared-nestjs-metrics` existiert. + +**Betroffene Backends:** +- `apps/chat/apps/backend/src/metrics/` (50 LOC) +- `apps/calendar/apps/backend/src/metrics/` (50 LOC) +- `apps/todo/apps/backend/src/metrics/` (68 LOC) +- `apps/contacts/apps/backend/src/metrics/` (50 LOC) +- `apps/skilltree/apps/backend/src/metrics/` (50 LOC) +- `apps/clock/apps/backend/src/metrics/` (50 LOC) +- `apps/planta/apps/backend/src/metrics/` (50 LOC) + +**Aktion:** Migriere zu `@manacore/shared-nestjs-metrics` (bereits vorhanden!) + +```typescript +// Vorher (50 LOC pro Backend) +@Injectable() +export class MetricsService implements OnModuleInit { + private readonly register: client.Registry; + // ... 45 weitere Zeilen +} + +// Nachher (5 LOC) +import { MetricsModule } from '@manacore/shared-nestjs-metrics'; +@Module({ imports: [MetricsModule.forRoot({ prefix: 'chat_' })] }) +``` + +--- + +### 1.2 HOCH: Main.ts/CORS Setup (1.800 LOC) + +**Problem:** 14 Backends haben fast identische `main.ts` mit CORS, ValidationPipe, GlobalPrefix. + +**Empfehlung:** Erstelle `@manacore/shared-nestjs-setup` + +```typescript +// packages/shared-nestjs-setup/src/bootstrap.ts +export interface BootstrapOptions { + corsOrigins?: string[]; + apiPrefix?: string; + excludeFromPrefix?: string[]; + enableMetrics?: boolean; + defaultPort?: number; +} + +export async function bootstrapApp( + AppModule: Type, + options: BootstrapOptions = {} +): Promise { + const app = await NestFactory.create(AppModule); + + // CORS (25 LOC -> 1 LOC) + setupCors(app, options.corsOrigins); + + // Validation (10 LOC -> 0 LOC) + app.useGlobalPipes(new ValidationPipe({ + whitelist: true, + transform: true, + forbidNonWhitelisted: true, + })); + + // Prefix (5 LOC -> 0 LOC) + app.setGlobalPrefix(options.apiPrefix || 'api/v1', { + exclude: options.excludeFromPrefix || ['health', 'metrics'], + }); + + return app; +} +``` + +**Vorher (85 LOC pro Backend):** +```typescript +async function bootstrap() { + const app = await NestFactory.create(AppModule); + const corsOrigins = process.env.CORS_ORIGINS?.split(',') || [...]; + app.enableCors({ origin: corsOrigins, ... }); + app.useGlobalPipes(new ValidationPipe({ ... })); + app.setGlobalPrefix('api/v1', { exclude: ['health'] }); + // ... +} +``` + +**Nachher (15 LOC):** +```typescript +import { bootstrapApp } from '@manacore/shared-nestjs-setup'; +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await bootstrapApp(AppModule, { + defaultPort: 3002, + enableMetrics: true, + }); + await app.listen(process.env.PORT || 3002); +} +bootstrap(); +``` + +--- + +### 1.3 MITTEL: Health Endpoints (170 LOC) + +**Problem:** 13 Backends haben identische Health-Controller. + +**Empfehlung:** Erstelle `@manacore/shared-nestjs-health` + +```typescript +// Vorher (14 LOC pro Backend) +@Controller('health') +export class HealthController { + @Get() + check() { + return { status: 'ok', timestamp: new Date().toISOString(), service: 'chat' }; + } +} + +// Nachher (1 LOC) +import { HealthModule } from '@manacore/shared-nestjs-health'; +@Module({ imports: [HealthModule.forRoot('chat-backend')] }) +``` + +--- + +## 2. Frontend Stores (Svelte 5) + +### 2.1 HOCH: App Settings Stores (600-700 LOC) + +**Problem:** 3 Apps (todo, calendar, contacts) haben fast identische Settings-Store Implementierungen mit localStorage Persistenz. + +**Betroffene Dateien:** +- `apps/todo/apps/web/src/lib/stores/settings.svelte.ts` (259 LOC) +- `apps/calendar/apps/web/src/lib/stores/settings.svelte.ts` (433 LOC) +- `apps/contacts/apps/web/src/lib/stores/settings.svelte.ts` (278 LOC) + +**Dupliziertes Pattern (100% identisch):** +```typescript +// Boilerplate in jedem (80-100 LOC): +- TypeScript Interface für Settings +- DEFAULT_SETTINGS Konstante +- STORAGE_KEY +- loadSettings() - localStorage laden + merge mit defaults +- saveSettings() - localStorage speichern +- let settings = $state(...) +- toggleImmersiveMode(), initialize(), set(), update(), reset(), getDefaults() +``` + +**Empfehlung:** Erstelle `createAppSettingsStore()` Factory in `@manacore/shared-stores` + +```typescript +// packages/shared-stores/src/createAppSettingsStore.ts +export function createAppSettingsStore>( + storageKey: string, + defaultSettings: T, + options?: { cloudSync?: boolean } +) { + let settings = $state(defaultSettings); + + function loadSettings(): T { /* localStorage logic */ } + function saveSettings(newSettings: T): void { /* localStorage logic */ } + + return { + get value() { return settings; }, + initialize() { settings = loadSettings(); }, + set(key: K, value: T[K]) { /* ... */ }, + update(updates: Partial) { /* ... */ }, + reset() { settings = defaultSettings; saveSettings(settings); }, + getDefaults() { return defaultSettings; }, + }; +} +``` + +**Einsparung:** ~200 LOC Boilerplate pro App = 600 LOC + +--- + +### 2.2 MITTEL: Navigation Stores (50 LOC) + +**Problem:** 9 Apps haben fast identische Navigation-Stores. + +**Pattern (5-6 LOC pro App):** +```typescript +import { writable } from 'svelte/store'; +export const isSidebarMode = writable(false); +export const isNavCollapsed = writable(false); +``` + +**Ausnahme:** Clock (36 LOC) mit localStorage Persistenz + Media Query Listeners + +**Empfehlung:** Factory in `@manacore/shared-stores` + +```typescript +export function createNavigationStore(options?: { + persist?: boolean; + mediaQueryCollapse?: string; +}) { + // ... +} +``` + +--- + +### 2.3 NIEDRIG: Theme Stores Migration + +**Problem:** 2 Apps nutzen nicht `@manacore/shared-theme`: +- `apps/storage/apps/web/src/lib/stores/theme.svelte.ts` (96 LOC - custom) +- `apps/questions/apps/web/src/lib/stores/theme.ts` (custom) + +**Aktion:** Migriere zu `createThemeStore()` aus `@manacore/shared-theme` + +--- + +## 3. UI Components + +### 3.1 HOCH: Skeleton Components (800-1.000 LOC) + +**Problem:** 31 Skeleton-Komponenten über Apps verteilt, obwohl shared-ui Primitives hat. + +**Betroffene Apps:** +- `apps/contacts/` - 11 Skeletons (925 LOC) +- `apps/calendar/` - 5 Skeletons (338 LOC) +- `apps/todo/` - 5 Skeletons + +**Shared-UI hat bereits:** +- `SkeletonBox`, `SkeletonAvatar`, `SkeletonCard`, `SkeletonGrid`, `SkeletonList`, `SkeletonRow`, `SkeletonText` + +**Empfehlung:** +1. Dokumentation für Skeleton-Komposition aus Primitives +2. Page-Level Presets erstellen: `ListPageSkeleton`, `DetailPageSkeleton`, `GridPageSkeleton` + +--- + +### 3.2 MITTEL: Sofort löschbare Duplikate (144 LOC) + +**Picture App hat lokale Kopien von shared-ui Komponenten:** + +| Datei | LOC | shared-ui Alternative | +|-------|-----|----------------------| +| `apps/picture/apps/web/src/lib/components/ui/Button.svelte` | 53 | `@manacore/shared-ui/Button` | +| `apps/picture/apps/web/src/lib/components/ui/Input.svelte` | 70 | `@manacore/shared-ui/Input` | +| `apps/picture/apps/web/src/lib/components/ui/Card.svelte` | 21 | `@manacore/shared-ui/Card` | + +**Aktion:** Lösche lokale Dateien, importiere aus shared-ui. + +--- + +### 3.3 MITTEL: AppSlider Cleanup (240 LOC) + +**Problem:** 8 Apps haben lokale `AppSlider.svelte` Kopien, obwohl shared-ui Version existiert. + +**Betroffene Apps:** calendar, chat, contacts, manadeck, manacore, picture, presi, todo + +**Aktion:** Verifiziere Import aus `@manacore/shared-ui`, lösche lokale Kopien. + +--- + +### 3.4 NIEDRIG: LanguageSelector (75 LOC) + +**Problem:** 5+ Apps haben identische LanguageSelector Implementierungen. + +**Empfehlung:** Verschiebe nach `@manacore/shared-ui/navigation/LanguageSelector.svelte` + +--- + +## 4. Konfigurationsdateien + +### 4.1 MITTEL: TypeScript Configs (400 LOC) + +**Problem:** Identische tsconfig.json in: +- 12+ NestJS Backends (95% identisch) +- 15+ SvelteKit Web Apps (99% identisch) +- 6 Expo Mobile Apps (99% identisch) +- 6+ Astro Landing Pages (95% identisch) + +**Empfehlung:** Erstelle `@manacore/shared-tsconfig` + +``` +packages/shared-tsconfig/ +├── nestjs.json +├── sveltekit.json +├── expo.json +├── astro.json +└── base.json +``` + +**Vorher (30 LOC pro App):** +```json +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + // ... 25 weitere Zeilen + } +} +``` + +**Nachher (3 LOC):** +```json +{ + "extends": "@manacore/shared-tsconfig/nestjs" +} +``` + +--- + +### 4.2 MITTEL: Vite Configs (300 LOC) + +**Problem:** 15 SvelteKit Apps haben 70% identische vite.config.ts. + +**Empfehlung:** Factory-Funktion in `@manacore/shared-vite-config` + +```typescript +// packages/shared-vite-config/src/sveltekit.ts +export function createSvelteKitConfig(options: { + port: number; + packages?: string[]; +}) { + return defineConfig({ + plugins: [sveltekit(), tailwindcss()], + server: { port: options.port, strictPort: true }, + ssr: { noExternal: options.packages || [] }, + optimizeDeps: { exclude: options.packages || [] }, + }); +} +``` + +--- + +### 4.3 NIEDRIG: Drizzle Configs (200 LOC) + +**Problem:** 12 Backends haben 90% identische drizzle.config.ts. + +**Empfehlung:** Factory-Funktion + +```typescript +// Vorher (17 LOC pro Backend) +export default defineConfig({ + schema: './src/db/schema/index.ts', + out: './src/db/migrations', + dialect: 'postgresql', + dbCredentials: { url: process.env.DATABASE_URL || '...' }, +}); + +// Nachher (5 LOC) +import { createDrizzleConfig } from '@manacore/shared-drizzle-config'; +export default createDrizzleConfig('chat'); +``` + +--- + +## 5. Utility Functions + +### 5.1 NIEDRIG: Logger Utilities (130 LOC) + +**Problem:** 2 Mobile Apps haben eigene Logger: +- `apps/manadeck/apps/mobile/utils/logger.ts` (34 LOC) +- `apps/picture/apps/mobile/utils/logger.ts` (92 LOC - erweitert) + +**Empfehlung:** Erstelle `@manacore/shared-logger` mit: +- `logger.debug/info/warn/error/success` +- `perfLogger.start/end` +- `networkLogger.request/response/error` + +--- + +### 5.2 NIEDRIG: Sleep Function Duplikat + +**Problem:** `sleep()` existiert in: +- `packages/shared-utils/src/async.ts` (8 LOC) +- `packages/shared-api-client/src/utils.ts` (3 LOC) + +**Aktion:** Entferne aus shared-api-client, importiere aus shared-utils. + +--- + +## Aktionsplan + +### Phase 1: Quick Wins (1-2 Tage, ~1.000 LOC) + +| Aufgabe | LOC | Aufwand | +|---------|-----|---------| +| Metrics zu shared-nestjs-metrics migrieren (7 Backends) | 350 | Niedrig | +| Picture UI-Komponenten löschen (Button/Input/Card) | 144 | Niedrig | +| AppSlider lokale Kopien entfernen (8 Apps) | 240 | Niedrig | +| Sleep-Duplikat entfernen | 3 | Minimal | + +### Phase 2: Stores & Configs (3-5 Tage, ~1.500 LOC) + +| Aufgabe | LOC | Aufwand | +|---------|-----|---------| +| `createAppSettingsStore()` Factory erstellen | 600 | Mittel | +| `@manacore/shared-tsconfig` Package erstellen | 400 | Niedrig | +| `@manacore/shared-vite-config` Factory erstellen | 300 | Niedrig | +| Navigation Store Factory erstellen | 50 | Niedrig | + +### Phase 3: Backend Setup (5-7 Tage, ~2.000 LOC) + +| Aufgabe | LOC | Aufwand | +|---------|-----|---------| +| `@manacore/shared-nestjs-setup` erstellen | 1.800 | Mittel | +| `@manacore/shared-nestjs-health` erstellen | 170 | Niedrig | +| Drizzle Config Factory erstellen | 200 | Niedrig | + +### Phase 4: Skeleton Refactoring (Optional, ~800 LOC) + +| Aufgabe | LOC | Aufwand | +|---------|-----|---------| +| Page-Level Skeleton Presets erstellen | 400 | Mittel | +| Bestehende Skeletons refactoren | 400 | Mittel | + +--- + +## Zusammenfassung + +| Kategorie | Geschätzte Einsparung | +|-----------|----------------------| +| Backend (NestJS) | 2.300 LOC | +| Frontend Stores | 700 LOC | +| UI Components | 1.200 LOC | +| Konfigurationen | 900 LOC | +| Utilities | 130 LOC | +| **Gesamt** | **~5.200-6.500 LOC** | + +Plus Wartungsvorteile: +- Einheitliche Patterns über alle Apps +- Single Point of Change für Updates +- Bessere Onboarding-Erfahrung für neue Entwickler +- Reduzierte Fehlerquellen durch Duplikate