mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-20 23:26:41 +02:00
Feat: New project chat, uload refactor (postgress), hosting plans, uload landingpage
This commit is contained in:
parent
559eb08d8c
commit
fcf3a344b1
123 changed files with 7106 additions and 3715 deletions
946
docs/BACKEND_ARCHITECTURE.md
Normal file
946
docs/BACKEND_ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,946 @@
|
|||
# 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) │
|
||||
└─────────────────────┘
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue