mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 01:21:09 +02:00
946 lines
25 KiB
Markdown
946 lines
25 KiB
Markdown
# 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-js` v2.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` - Benutzercharaktere
|
|
- `stories` - Generierte Geschichten
|
|
- `story_collections` - Sammlungen von Geschichten
|
|
- `user_settings` - Benutzereinstellungen
|
|
|
|
**Sicherheit:** Row-Level Security (RLS) für Datenzugriffskontrolle
|
|
|
|
### Authentifizierung
|
|
|
|
Mana Core Integration via `@mana-core/nestjs-integration`:
|
|
|
|
```typescript
|
|
// 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`
|
|
|
|
```typescript
|
|
// 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:**
|
|
```typescript
|
|
// drizzle.config.ts
|
|
export default {
|
|
schema: './src/schema/*',
|
|
out: './migrations',
|
|
driver: 'pg',
|
|
dbCredentials: {
|
|
connectionString: process.env.DATABASE_URL
|
|
}
|
|
};
|
|
```
|
|
|
|
### Authentifizierung
|
|
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
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 Karten
|
|
- `flashcard` - Klassische Lernkarten
|
|
- `quiz` - Multiple-Choice Quiz
|
|
- `mixed` - Gemischte Inhalte
|
|
|
|
**Schwierigkeitsgrade:**
|
|
- `beginner`
|
|
- `intermediate`
|
|
- `advanced`
|
|
|
|
### Docker-Setup
|
|
|
|
```yaml
|
|
# 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`
|
|
|
|
```typescript
|
|
// 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`:
|
|
|
|
```typescript
|
|
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-integration` Package
|
|
|
|
```
|
|
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:
|
|
|
|
```typescript
|
|
// Installation via git
|
|
"@mana-core/nestjs-integration": "git+https://github.com/mana-core/nestjs-integration.git"
|
|
```
|
|
|
|
**Bereitgestellte Features:**
|
|
- `AuthGuard` - JWT-Authentifizierung
|
|
- `@CurrentUser()` - User-Context Decorator
|
|
- `CreditClientService` - 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
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
// 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)
|
|
|
|
```bash
|
|
# Migration generieren
|
|
pnpm --filter @manacore/manadeck-database drizzle-kit generate
|
|
|
|
# Migration ausführen
|
|
pnpm --filter @manacore/manadeck-database drizzle-kit push
|
|
```
|
|
|
|
### Maerchenzauber (Supabase)
|
|
|
|
```bash
|
|
# Supabase CLI
|
|
supabase migration new <name>
|
|
supabase db push
|
|
```
|
|
|
|
---
|
|
|
|
## Umgebungsvariablen
|
|
|
|
### Maerchenzauber Backend
|
|
|
|
```env
|
|
# 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
|
|
|
|
```env
|
|
# 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
|
|
|
|
```env
|
|
# Database
|
|
DATABASE_URL=postgresql://...
|
|
|
|
# Redis
|
|
REDIS_URL=redis://localhost:6379
|
|
|
|
# PocketBase
|
|
POCKETBASE_URL=
|
|
```
|
|
|
|
---
|
|
|
|
## Lokale Entwicklung
|
|
|
|
### Maerchenzauber Backend
|
|
|
|
```bash
|
|
cd maerchenzauber/apps/backend
|
|
pnpm install
|
|
pnpm run start:dev
|
|
# Läuft auf Port 3002
|
|
```
|
|
|
|
### Manadeck Backend
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
cd uload
|
|
docker-compose up -d # PostgreSQL + Redis
|
|
pnpm install
|
|
pnpm run dev
|
|
```
|
|
|
|
---
|
|
|
|
## Zusammenfassung
|
|
|
|
Das Manacore Monorepo verwendet verschiedene Backend-Strategien:
|
|
|
|
1. **Full Backend (NestJS):** Maerchenzauber, Manadeck - Für komplexe Geschäftslogik und AI-Integration
|
|
2. **Embedded Database (PocketBase):** Uload - Für einfache CRUD-Operationen
|
|
3. **Frontend-only:** Picture, Memoro - Server-Routes in SvelteKit
|
|
4. **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)
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
// packages/shared-supabase/src/client.ts
|
|
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.
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
1. `packages/shared-database/` mit Drizzle Basis-Schema erstellen
|
|
2. Maerchenzauber von Supabase auf Drizzle migrieren
|
|
3. 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)
|
|
|
|
1. **NestJS Version angleichen** → Alle auf v11
|
|
2. **Einheitliche Health-Endpoints** → `/health`, `/health/ready`
|
|
3. **Gemeinsame ESLint/Prettier Config** → `@manacore/eslint-config-backend`
|
|
4. **Einheitliche Error-Response-Struktur:**
|
|
|
|
```typescript
|
|
// Einheitliches Error-Format für alle Backends
|
|
interface ApiError {
|
|
statusCode: number;
|
|
error: string;
|
|
message: string;
|
|
timestamp: string;
|
|
path: string;
|
|
}
|
|
```
|
|
|
|
5. **Einheitliche Logging-Struktur:**
|
|
|
|
```typescript
|
|
// 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) │
|
|
└─────────────────────┘
|
|
```
|