Package was unused — no imports found across the entire codebase. All apps have migrated to direct PostgreSQL (Drizzle ORM) for backends and mana-core-auth API for mobile/web clients. Removes package and all documentation references. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
25 KiB
Backend-Architektur im Manacore Monorepo
Diese Dokumentation beschreibt die Backend-Implementierungen aller Projekte im Manacore Monorepo.
Übersicht
Das Monorepo enthält 6 Hauptprojekte mit unterschiedlichen Backend-Architekturen:
| Projekt | Backend-Typ | Datenbank | Status |
|---|---|---|---|
| Maerchenzauber | NestJS v10 | Supabase (PostgreSQL) | Aktiv |
| Manadeck | NestJS v11 | PostgreSQL + Drizzle ORM | Aktiv |
| Uload | NestJS v11 | PostgreSQL + Drizzle ORM | Aktiv |
| Picture | Kein Backend | - | Frontend-only |
| Memoro | Kein Backend | - | Frontend-only |
| Manacore | Kein Backend (extern) | - | Externes Backend |
1. Maerchenzauber
Pfad: /maerchenzauber/apps/backend
Zweck: KI-gestützte Kindergeschichten-Generierung mit benutzerdefinierten Charakteren.
Technologie-Stack
- Framework: NestJS 10.0.0
- Datenbank: Supabase (PostgreSQL)
- ORM:
@supabase/supabase-jsv2.81.1 - AI-Services: Azure OpenAI, Google Gemini, Replicate
Architektur
apps/backend/
├── src/
│ ├── character/ # Charakter-Modul
│ │ ├── character.controller.ts
│ │ ├── character.service.ts
│ │ └── character.repository.ts
│ ├── story/ # Story-Modul
│ │ ├── story.controller.ts
│ │ ├── story.service.ts
│ │ └── pipelines/ # Story-Generierung-Pipelines
│ ├── core/ # Kern-Services
│ │ └── services/
│ │ └── prompting.service.ts
│ ├── settings/ # Benutzereinstellungen
│ ├── health/ # Health-Checks
│ └── feedback/ # Feedback-Modul
Datenbank-Schema
Tabellen:
characters- Benutzercharakterestories- Generierte Geschichtenstory_collections- Sammlungen von Geschichtenuser_settings- Benutzereinstellungen
Sicherheit: Row-Level Security (RLS) für Datenzugriffskontrolle
Authentifizierung
Mana Core Integration via @mana-core/nestjs-integration:
// Beispiel: Geschützter Endpoint
@UseGuards(AuthGuard)
@Get('characters')
async getCharacters(@CurrentUser() user: User) {
return this.characterService.findByUser(user.id);
}
Auth-Endpoint: https://mana-core-middleware-111768794939.europe-west3.run.app
AI-Services
| Service | Verwendung | API |
|---|---|---|
| Azure OpenAI (GPT-4) | Story-Generierung | MAERCHENZAUBER_AZURE_OPENAI_ENDPOINT |
| Google Gemini | Charakter-Generierung | GOOGLE_GEMINI_API_KEY |
| Replicate (Flux) | Bildgenerierung | REPLICATE_API_TOKEN |
File Storage
- Provider: Supabase Storage
- Bucket:
maerchenzauber - Verwendung: Charakter- und Story-Bilder
Deployment
- Plattform: Google Cloud Run
- Region: europe-west3
- URL:
https://storyteller-backend-111768794939.europe-west3.run.app - Port: 3002 (Development)
2. Manadeck
Pfad: /manadeck/apps/backend
Zweck: KI-gestützte Lernkarten-Generierung (Flashcards, Quizzes, Mixed).
Technologie-Stack
- Framework: NestJS 11.0.1
- Datenbank: PostgreSQL 16
- ORM: Drizzle ORM
- AI-Service: Google Gemini API
Architektur
apps/backend/
├── src/
│ ├── api.controller.ts # Haupt-API-Endpoints
│ ├── public.controller.ts # Öffentliche Endpoints
│ ├── health.controller.ts # Health-Checks
│ ├── ai.service.ts # AI-Generierung
│ └── repositories/
│ ├── deck.repository.ts
│ ├── card.repository.ts
│ ├── user-stats.repository.ts
│ └── deck-template.repository.ts
Datenbank-Package
Das Datenbank-Schema ist in einem separaten Package ausgelagert:
Pfad: /packages/manadeck-database
// Verwendung im Backend
import { db, schema } from '@manacore/manadeck-database';
const decks = await db.query.decks.findMany({
where: eq(schema.decks.userId, userId)
});
Drizzle-Konfiguration:
// drizzle.config.ts
export default {
schema: './src/schema/*',
out: './migrations',
driver: 'pg',
dbCredentials: {
connectionString: process.env.DATABASE_URL
}
};
Authentifizierung
import { AuthGuard, CurrentUser } from '@mana-core/nestjs-integration';
@Controller('api')
@UseGuards(AuthGuard)
export class ApiController {
@Post('decks')
async createDeck(@CurrentUser() user: User, @Body() dto: CreateDeckDto) {
// Credit-Prüfung und Deck-Erstellung
}
}
Credit-System
Integration mit Mana Core Credit Service:
import { CreditClientService } from '@mana-core/nestjs-integration';
@Injectable()
export class AiService {
constructor(private creditClient: CreditClientService) {}
async generateDeck(userId: string, input: GenerateInput) {
// 1. Credit-Balance prüfen
const hasCredits = await this.creditClient.checkBalance(userId, 'DECK_CREATION');
// 2. Deck generieren
const deck = await this.generateWithGemini(input);
// 3. Credits abziehen
await this.creditClient.deduct(userId, 'DECK_CREATION');
return deck;
}
}
AI-Generierung
Unterstützte Kartentypen:
text- Textbasierte Kartenflashcard- Klassische Lernkartenquiz- Multiple-Choice Quizmixed- Gemischte Inhalte
Schwierigkeitsgrade:
beginnerintermediateadvanced
Docker-Setup
# docker-compose.yml (Lokale Entwicklung)
services:
postgres:
image: postgres:16
ports:
- "5433:5432"
environment:
POSTGRES_DB: manadeck
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
pgadmin:
image: dpage/pgadmin4
ports:
- "5050:80"
Deployment
- Docker Image: Multi-stage Build (Node 18-alpine)
- Port: 8080
- Health-Check:
/health
3. Uload
Pfad: /uload/apps/backend
Zweck: URL-Shortener mit Link-Analytics.
Technologie-Stack
- Framework: NestJS 11.0.1
- Datenbank: PostgreSQL 16
- ORM: Drizzle ORM
- Cache: Redis (optional)
Architektur
uload/apps/backend/
├── src/
│ ├── main.ts
│ ├── app.module.ts
│ ├── config/
│ │ └── validation.schema.ts
│ ├── controllers/
│ │ ├── redirect.controller.ts # GET /:code (public redirect)
│ │ ├── links.controller.ts # CRUD /api/links
│ │ ├── analytics.controller.ts # GET /api/analytics
│ │ └── health.controller.ts
│ ├── services/
│ │ ├── links.service.ts
│ │ ├── redirect.service.ts
│ │ └── analytics.service.ts
│ └── database/
│ ├── database.module.ts
│ └── repositories/
│ ├── link.repository.ts
│ └── click.repository.ts
├── Dockerfile
└── package.json
Datenbank-Package
Pfad: /packages/uload-database
// Verwendung im Backend
import { db, links, clicks, eq, desc } from '@manacore/uload-database';
const userLinks = await db.query.links.findMany({
where: eq(links.userId, userId),
orderBy: desc(links.createdAt)
});
API Endpoints
| Endpoint | Method | Auth | Beschreibung |
|---|---|---|---|
/:code |
GET | Public | Redirect zu Original-URL |
/api/links |
GET | Protected | Liste aller Links |
/api/links |
POST | Protected | Link erstellen |
/api/links/:id |
GET | Protected | Link Details |
/api/links/:id |
PATCH | Protected | Link aktualisieren |
/api/links/:id |
DELETE | Protected | Link löschen |
/api/analytics/:linkId |
GET | Protected | Link-Statistiken |
/health |
GET | Public | Health Check |
Authentifizierung
Mana Core Integration via @mana-core/nestjs-integration:
import { AuthGuard, CurrentUser } from '@mana-core/nestjs-integration';
@Controller('api/links')
@UseGuards(AuthGuard)
export class LinksController {
@Get()
async getLinks(@CurrentUser() user: any) {
return this.linksService.getLinks(user.sub);
}
}
Deployment
- Docker Image: Multi-stage Build (Node 20-alpine)
- Port: 3003
- Health-Check:
/health
4. Picture
Pfad: /picture
Zweck: Bild- und Medienverwaltung.
Architektur
Kein dediziertes Backend. Picture verwendet:
- SvelteKit Server-Routes für Backend-Logik
- Mana Core für Authentifizierung
- Shared Packages aus
/packages
picture/
├── apps/
│ ├── mobile/ # React Native Expo
│ ├── web/ # SvelteKit
│ └── landing/ # Astro
└── packages/
├── design-tokens/ # Design System
├── mobile-ui/ # Mobile UI Components
└── shared/ # Utilities
5. Memoro
Pfad: /memoro
Zweck: Legacy-Content und Memory-Preservation.
Architektur
Kein dediziertes Backend. Memoro verwendet:
- SvelteKit Server-Routes
- Mana Core für Authentifizierung
- Supabase (Legacy-Konfiguration vorhanden)
memoro/
├── apps/
│ ├── mobile/
│ ├── web/
│ └── landing/
└── supabase/ # Legacy Supabase Config
6. Manacore
Pfad: /manacore
Zweck: Core-Authentifizierung und Credit-System.
Architektur
Das Manacore-Backend ist extern gehostet und nicht Teil des Monorepos:
- URL:
https://mana-core-middleware-111768794939.europe-west3.run.app - Integration: Via
@mana-core/nestjs-integrationPackage
manacore/
├── apps/
│ ├── mobile/ # Auth-Flow UI
│ ├── web/ # Dashboard
│ └── landing/ # Marketing
Shared Packages für Backend
@manacore/manadeck-database
PostgreSQL-Datenbankschema für Manadeck.
packages/manadeck-database/
├── src/
│ ├── schema/ # Drizzle Schema
│ ├── client.ts # DB Client
│ └── index.ts # Exports
├── drizzle.config.ts
└── docker-compose.yml
@manacore/uload-database
PostgreSQL-Datenbankschema für Uload URL-Shortener.
packages/uload-database/
├── src/
│ ├── schema/
│ │ ├── users.ts
│ │ ├── links.ts
│ │ ├── clicks.ts
│ │ ├── tags.ts
│ │ ├── workspaces.ts
│ │ ├── accounts.ts
│ │ └── relations.ts
│ ├── client.ts # DB Client
│ └── index.ts # Exports
├── drizzle.config.ts
└── docker-compose.yml
@mana-core/nestjs-integration
Externe Dependency für Backend-Integration:
// Installation via git
"@mana-core/nestjs-integration": "git+https://github.com/mana-core/nestjs-integration.git"
Bereitgestellte Features:
AuthGuard- JWT-Authentifizierung@CurrentUser()- User-Context DecoratorCreditClientService- Credit-Operationen- Konfigurationsmodule
Authentifizierungs-Pattern
Alle Projekte nutzen zentrale Mana Core Authentifizierung:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │────▶│ Project Backend │────▶│ Mana Core │
│ (Web/Mobile) │ │ (NestJS/etc.) │ │ Middleware │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ │ │
▼ ▼ ▼
shared-auth AuthGuard JWT Validation
shared-auth-ui @CurrentUser Credit Service
shared-auth-stores CreditClient User Management
Frontend-Integration
// Shared Auth Store (Svelte)
import { authStore } from '@manacore/shared-auth-stores';
// Login
await authStore.login(email, password);
// Token für API-Requests
const token = authStore.getAccessToken();
Backend-Integration
// NestJS Module Setup
@Module({
imports: [
ManaCoreModule.forRoot({
serviceKey: process.env.MANA_CORE_SERVICE_KEY,
baseUrl: process.env.MANA_CORE_URL,
}),
],
})
export class AppModule {}
Datenbank-Migrationen
Manadeck (Drizzle)
# Migration generieren
pnpm --filter @manacore/manadeck-database drizzle-kit generate
# Migration ausführen
pnpm --filter @manacore/manadeck-database drizzle-kit push
Maerchenzauber (Supabase)
# Supabase CLI
supabase migration new <name>
supabase db push
Umgebungsvariablen
Maerchenzauber Backend
# Supabase
SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
# Mana Core
MANA_CORE_URL=https://mana-core-middleware-111768794939.europe-west3.run.app
MANA_CORE_SERVICE_KEY=
# AI Services
MAERCHENZAUBER_AZURE_OPENAI_ENDPOINT=
AZURE_OPENAI_API_KEY=
GOOGLE_GEMINI_API_KEY=
REPLICATE_API_TOKEN=
Manadeck Backend
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5433/manadeck
# Mana Core
MANA_CORE_URL=
MANA_CORE_SERVICE_KEY=
# AI
GOOGLE_GEMINI_API_KEY=
# Server
PORT=8080
Uload
# Database
DATABASE_URL=postgresql://...
# Redis
REDIS_URL=redis://localhost:6379
# PocketBase
POCKETBASE_URL=
Lokale Entwicklung
Maerchenzauber Backend
cd maerchenzauber/apps/backend
pnpm install
pnpm run start:dev
# Läuft auf Port 3002
Manadeck Backend
# 1. Datenbank starten
cd packages/manadeck-database
docker-compose up -d
# 2. Backend starten
cd manadeck/apps/backend
pnpm install
pnpm run start:dev
# Läuft auf Port 8080
Uload
cd uload
docker-compose up -d # PostgreSQL + Redis
pnpm install
pnpm run dev
Zusammenfassung
Das Manacore Monorepo verwendet verschiedene Backend-Strategien:
- Full Backend (NestJS): Maerchenzauber, Manadeck - Für komplexe Geschäftslogik und AI-Integration
- Embedded Database (PocketBase): Uload - Für einfache CRUD-Operationen
- Frontend-only: Picture, Memoro - Server-Routes in SvelteKit
- External Backend: Manacore - Zentrale Auth/Credit-Services
Alle Projekte teilen sich:
- Gemeinsame Authentifizierung via Mana Core
- Shared Packages für UI, Auth, Types
- Einheitliches Deployment-Pattern (Docker + Cloud Run)
Vereinheitlichungs-Roadmap
Aktuelle Fragmentierung
| Aspekt | Maerchenzauber | Manadeck | Uload |
|---|---|---|---|
| Framework | NestJS v10 | NestJS v11 | PocketBase |
| Datenbank | Supabase | PostgreSQL | PocketBase + PG |
| ORM | @supabase/js | Drizzle | Drizzle |
| Auth | Mana Core | Mana Core | PocketBase + Mana Core |
Strategie 1: Shared NestJS Backend Package
Ziel: Ein gemeinsames @manacore/shared-backend Package mit wiederverwendbaren Modulen.
packages/shared-backend/
├── src/
│ ├── auth/
│ │ ├── auth.module.ts
│ │ ├── auth.guard.ts
│ │ └── current-user.decorator.ts
│ ├── database/
│ │ ├── database.module.ts
│ │ ├── drizzle.provider.ts
│ │ └── base.repository.ts
│ ├── health/
│ │ └── health.module.ts
│ ├── credits/
│ │ └── credits.module.ts
│ └── common/
│ ├── filters/
│ ├── interceptors/
│ └── pipes/
Vorteile:
- Einheitliche Auth-Integration
- Wiederverwendbare Module
- Konsistente Error-Handling
Aufwand: Mittel
Strategie 2: Einheitliche Datenbank-Strategie
Option A: Alles auf Drizzle + PostgreSQL (Empfohlen)
// packages/shared-database/src/base-schema.ts
export const baseColumns = {
id: uuid('id').primaryKey().defaultRandom(),
createdAt: timestamp('created_at').defaultNow(),
updatedAt: timestamp('updated_at').defaultNow(),
userId: text('user_id').notNull(),
};
// Projekt-spezifische Erweiterung
// maerchenzauber/database/schema/characters.ts
import { baseColumns } from '@manacore/shared-database';
export const characters = pgTable('characters', {
...baseColumns,
name: text('name').notNull(),
traits: jsonb('traits'),
});
Migration von Supabase:
- Supabase ist PostgreSQL → Schema kann übernommen werden
- RLS-Policies in Application-Layer verschieben
- Storage → S3/Cloudflare R2
Option B: Alles auf Supabase
export const createProjectClient = (project: 'maerchenzauber' | 'manadeck' | 'uload') => {
return createClient(
process.env[`${project.toUpperCase()}_SUPABASE_URL`],
process.env[`${project.toUpperCase()}_SUPABASE_KEY`]
);
};
Vorteile Supabase:
- Eingebaute Auth (optional nutzbar)
- Storage inklusive
- Realtime-Subscriptions
- Edge Functions möglich
Nachteile Supabase:
- Vendor Lock-in
- Weniger Kontrolle über Schema
Empfehlung: Drizzle + PostgreSQL wegen Type-Safety, moderner API und keinem Vendor Lock-in.
Strategie 3: Einheitliche Monorepo Backend Struktur
Ziel-Architektur:
packages/
├── shared-backend/ # Gemeinsame NestJS Module
│ ├── auth/
│ ├── database/
│ ├── health/
│ └── credits/
├── shared-database/ # Drizzle Basis-Schema
│ ├── base-schema.ts
│ ├── migrations/
│ └── client.ts
├── maerchenzauber-database/ # Projekt-Schema
├── manadeck-database/ # ✓ Existiert bereits
└── uload-database/ # Neu
apps/
├── maerchenzauber-backend/ # Nutzt shared-backend
├── manadeck-backend/ # Nutzt shared-backend
└── uload-backend/ # Neues NestJS Backend (ersetzt PocketBase)
Strategie 4: Shared Backend als Service-Layer
Ziel: Gemeinsamer Service-Layer, projekt-spezifische Controller.
// packages/shared-backend/src/services/ai.service.ts
@Injectable()
export class BaseAiService {
constructor(
private gemini: GeminiClient,
private credits: CreditService,
) {}
protected async generateWithCredits<T>(
userId: string,
operation: string,
generator: () => Promise<T>
): Promise<T> {
await this.credits.check(userId, operation);
const result = await generator();
await this.credits.deduct(userId, operation);
return result;
}
}
// maerchenzauber/backend/src/story/story.service.ts
@Injectable()
export class StoryService extends BaseAiService {
async generateStory(userId: string, input: StoryInput) {
return this.generateWithCredits(userId, 'STORY_GENERATION', async () => {
// Projekt-spezifische Logik
});
}
}
Strategie 5: API-Gateway Pattern (Optional)
Ziel: Ein zentrales Gateway vor allen Backends.
┌─────────────────┐
│ API Gateway │
│ (Kong/Traefik) │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Maerchenzauber│ │ Manadeck │ │ Uload │
│ Backend │ │ Backend │ │ Backend │
└───────────────┘ └───────────────┘ └───────────────┘
Vorteile:
- Zentrale Auth-Validierung
- Rate Limiting
- Request Logging
- Einheitliche API-Struktur
Aufwand: Hoch - Empfohlen erst bei Skalierungsbedarf
Empfohlene Implementierungsreihenfolge
Phase 1: Shared Backend Package
Priorität: Hoch Aufwand: 2-3 Wochen
Neues Package packages/shared-backend/ mit:
- Auth Module (wraps @mana-core/nestjs-integration)
- Health Module
- Credits Module
- Base Repository Pattern
- Common Decorators, Guards, Filters
Phase 2: Datenbank-Vereinheitlichung
Priorität: Hoch Aufwand: 3-4 Wochen
packages/shared-database/mit Drizzle Basis-Schema erstellen- Maerchenzauber von Supabase auf Drizzle migrieren
- Uload PocketBase durch PostgreSQL + Drizzle ersetzen
Phase 3: Uload Backend Neubau (Optional)
Priorität: Mittel Aufwand: 2-3 Wochen
PocketBase → NestJS Migration:
- Konsistenz mit anderen Projekten
- Bessere Integration mit Mana Core
- Einheitliches Deployment
Optionen-Vergleich
| Option | Aufwand | Benefit | Empfehlung |
|---|---|---|---|
| Shared Backend Package | Mittel | Hoch | ✅ Priorität 1 |
| Drizzle überall | Mittel-Hoch | Hoch | ✅ Priorität 2 |
| Uload auf NestJS | Hoch | Mittel | ⚡ Optional |
| API Gateway | Sehr Hoch | Mittel | ⏳ Später |
Quick Wins (sofort umsetzbar)
- NestJS Version angleichen → Alle auf v11
- Einheitliche Health-Endpoints →
/health,/health/ready - Gemeinsame ESLint/Prettier Config →
@manacore/eslint-config-backend - Einheitliche Error-Response-Struktur:
// Einheitliches Error-Format für alle Backends
interface ApiError {
statusCode: number;
error: string;
message: string;
timestamp: string;
path: string;
}
- Einheitliche Logging-Struktur:
// packages/shared-backend/src/logging/logger.service.ts
@Injectable()
export class AppLogger {
log(context: string, message: string, meta?: Record<string, any>) {
console.log(JSON.stringify({
level: 'info',
context,
message,
timestamp: new Date().toISOString(),
...meta,
}));
}
}
Ziel-Architektur nach Vereinheitlichung
┌─────────────────────────────────────────────────────────────┐
│ Shared Packages │
├─────────────────┬─────────────────┬─────────────────────────┤
│ shared-backend │ shared-database │ shared-types │
│ - AuthModule │ - baseColumns │ - ApiError │
│ - HealthModule │ - drizzleClient │ - User │
│ - CreditsModule │ - migrations │ - CreditOperation │
│ - BaseRepo │ │ │
└────────┬────────┴────────┬────────┴────────┬────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Maerchenzauber │ │ Manadeck │ │ Uload │
│ Backend │ │ Backend │ │ Backend │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ NestJS v11 │ │ NestJS v11 │ │ NestJS v11 │
│ PostgreSQL │ │ PostgreSQL │ │ PostgreSQL │
│ Drizzle ORM │ │ Drizzle ORM │ │ Drizzle ORM │
│ Port: 3002 │ │ Port: 8080 │ │ Port: 3003 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└─────────────────┼─────────────────┘
▼
┌─────────────────────┐
│ Mana Core │
│ (Auth + Credits) │
└─────────────────────┘