chore: remove all NestJS backend references, replace with Hono/Bun

- Delete nestjs-backend.md guideline (replaced by hono-server.md)
- Delete Dockerfile.nestjs-base and Dockerfile.nestjs templates
- Delete stale BACKEND_ARCHITECTURE.md doc (NestJS-era, obsolete)
- Update CLAUDE.md, GUIDELINES.md, authentication.md to Hono/Bun first
- Update all app CLAUDE.md files: backend/ → server/, NestJS → Hono+Bun
- Update all app package.json files: @*/backend → @*/server
- Update docs: LOCAL_DEVELOPMENT, PORT_SCHEMA, ENVIRONMENT_VARIABLES,
  DATABASE_MIGRATIONS, MAC_MINI_SERVER, PROJECT_OVERVIEW
- Update scripts: generate-env.mjs, setup-databases.sh, build-app.sh
- Update CI/CD: cd-macmini.yml backend → server paths
- Update Astro docs site: @chat/backend → @chat/server

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-31 16:52:25 +02:00
parent 708299b35e
commit ab387b9b3d
43 changed files with 598 additions and 2398 deletions

View file

@ -1,945 +0,0 @@
# 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
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) │
└─────────────────────┘
```

View file

@ -246,8 +246,8 @@ pnpm --filter mana-core-auth db:generate
pnpm --filter mana-core-auth db:migrate
# chat-backend
pnpm --filter @chat/backend db:push
pnpm --filter @chat/backend db:migrate
pnpm --filter @chat/server db:push
pnpm --filter @chat/server db:migrate
```
---

View file

@ -32,7 +32,7 @@ The generator reads `.env.development` and creates app-specific `.env` files wit
|----------|--------|---------|
| Expo (mobile) | `EXPO_PUBLIC_` | `EXPO_PUBLIC_SUPABASE_URL` |
| SvelteKit (web) | `PUBLIC_` | `PUBLIC_SUPABASE_URL` |
| NestJS (backend) | None | `SUPABASE_URL` |
| Hono/Bun (server) | None | `DATABASE_URL` |
## File Locations
@ -40,19 +40,17 @@ The generator reads `.env.development` and creates app-specific `.env` files wit
- **`.env.development`** - Single source of truth, committed to git
### Generated Files (gitignored)
- `services/mana-core-auth/.env`
- `apps/chat/apps/backend/.env`
- `services/mana-auth/.env`
- `apps/chat/apps/server/.env`
- `apps/chat/apps/mobile/.env`
- `apps/chat/apps/web/.env`
- `apps/maerchenzauber/apps/backend/.env`
- `apps/maerchenzauber/apps/mobile/.env`
- `apps/maerchenzauber/apps/web/.env`
- `apps/manacore/apps/mobile/.env`
- `apps/manacore/apps/web/.env`
- `apps/memoro/apps/mobile/.env`
- `apps/memoro/apps/web/.env`
- `apps/manadeck/apps/backend/.env`
- `apps/manadeck/apps/server/.env`
- `apps/manadeck/apps/web/.env`
- `apps/*/apps/server/.env` (all apps with compute servers)
- `apps/*/apps/web/.env` (all web apps)
- `apps/*/apps/mobile/.env` (all mobile apps)
## Variable Reference
@ -98,28 +96,6 @@ The generator reads `.env.development` and creates app-specific `.env` files wit
| `CHAT_SUPABASE_URL` | Supabase project URL | - |
| `CHAT_SUPABASE_ANON_KEY` | Supabase anonymous key | - |
### Maerchenzauber Project
| Variable | Description | Default |
|----------|-------------|---------|
| `MAERCHENZAUBER_BACKEND_PORT` | Backend service port | `3003` |
| `MAERCHENZAUBER_APP_ID` | Mana Core app ID | - |
| `MAERCHENZAUBER_SUPABASE_URL` | Supabase project URL | - |
| `MAERCHENZAUBER_SUPABASE_ANON_KEY` | Supabase anonymous key | - |
| `MAERCHENZAUBER_JWT_SECRET` | JWT secret for Supabase | - |
| `MAERCHENZAUBER_AZURE_OPENAI_KEY` | Azure OpenAI key | - |
| `MAERCHENZAUBER_AZURE_OPENAI_ENDPOINT` | Azure OpenAI endpoint | - |
| `MAERCHENZAUBER_REPLICATE_API_KEY` | Replicate API key (images) | - |
### Memoro Project
| Variable | Description |
|----------|-------------|
| `MEMORO_SUPABASE_URL` | Supabase project URL |
| `MEMORO_SUPABASE_ANON_KEY` | Supabase anonymous key |
| `MEMORO_MIDDLEWARE_API_URL` | Middleware API URL |
| `MEMORO_APPID` | Mana Core app ID |
### Manacore Project
| Variable | Description |
@ -168,9 +144,9 @@ Edit `scripts/generate-env.mjs` and add your app config:
},
},
{
path: 'apps/my-project/apps/backend/.env',
path: 'apps/my-project/apps/server/.env',
vars: {
// For NestJS, no prefix needed
// For Hono/Bun servers, no prefix needed
API_KEY: (env) => env.MY_NEW_PROJECT_API_KEY,
API_URL: (env) => env.MY_NEW_PROJECT_URL,
},

View file

@ -1,35 +1,94 @@
# Local Development Guide
This guide explains how to set up and run applications locally with automatic database setup.
This guide explains how to set up and run applications locally. All apps use a **local-first architecture** with IndexedDB (Dexie.js) for reads/writes and mana-sync for background synchronization. Server-side compute (AI, file operations, RRULE expansion, etc.) is handled by lightweight **Hono/Bun servers**.
## Quick Start
For any project with a backend, use the `dev:*:full` command:
### Fastest: `dev:*:local` (recommended for daily development)
No auth service needed. Starts mana-sync + server (if any) + web:
```bash
pnpm dev:chat:full # Start chat with auth + database setup
pnpm dev:zitare:full # Start zitare with auth + database setup
pnpm dev:contacts:full # Start contacts with auth + database setup
# ... etc
pnpm dev:todo:local # sync + server + web
pnpm dev:chat:local # sync + server + web
pnpm dev:zitare:local # sync + web (no server needed)
pnpm dev:clock:local # sync + web (no server needed)
```
Guest mode works out of the box -- data lives in IndexedDB, no login required.
### Full stack: `dev:*:full` (with auth + database setup)
Use this when you need authentication, cross-device sync, or to test the full production flow:
```bash
pnpm dev:todo:full # DB setup + auth + sync + server + web
pnpm dev:chat:full # DB setup + auth + sync + server + web
pnpm dev:zitare:full # auth + sync + web
pnpm dev:calendar:full # DB setup + auth + sync + server + web
```
These commands automatically:
1. Create the database if it doesn't exist
2. Push the latest schema (Drizzle `db:push`)
3. Start the auth service (mana-core-auth)
4. Start the backend and web app with colored output
1. Create the database if it doesn't exist (for apps with Drizzle schemas)
2. Push the latest schema (`drizzle-kit push --force`)
3. Start the auth service (mana-auth)
4. Start mana-sync (Go WebSocket server)
5. Start the Hono/Bun server (if the app has one)
6. Start the web app with colored output
## Available Full Dev Commands
## Available Dev Commands
| Command | Database | Backend Port | Web Port |
|---------|----------|--------------|----------|
| `pnpm dev:chat:full` | chat | 3002 | 5173 |
| `pnpm dev:zitare:full` | zitare | 3007 | 5177 |
| `pnpm dev:contacts:full` | contacts | 3015 | 5184 |
| `pnpm dev:calendar:full` | calendar | 3014 | 5179 |
| `pnpm dev:clock:full` | clock | 3017 | 5187 |
| `pnpm dev:todo:full` | todo | 3018 | 5188 |
| `pnpm dev:picture:full` | picture | 3006 | 5175 |
### Apps with Hono/Bun Servers
These apps have server-side compute and support both `local` and `full` modes:
| App | Server Port | Web Port | `local` | `full` |
|-----|-------------|----------|---------|--------|
| Todo | 3019 | 5188 | Yes | Yes |
| Chat | 3002 | 5174 | Yes | Yes |
| Calendar | 3003 | 5179 | Yes | Yes |
| Contacts | 3004 | 5184 | Yes | Yes |
| Picture | 3006 | 5175 | Yes | Yes |
| ManaDeck | 3009 | 5176 | Yes | Yes |
| Mukke | 3010 | 5180 | Yes | Yes |
| Questions | 3011 | 5111 | Yes | Yes |
| Storage | 3016 | 5185 | Yes | Yes |
| Context | 3020 | 5192 | Yes | Yes |
| Planta | 3022 | 5191 | Yes | Yes |
| NutriPhi | 3023 | 5180 | Yes | Yes |
| Traces | 3026 | mobile | Yes | Yes |
| Presi | 3008 | 5178 | Yes | Yes |
| uLoad | 3070 | 5173 | Yes | Yes |
| News | 3071 | 5173 | Yes | Yes |
| WiseKeep | 3072 | 5173 | Yes | Yes |
| Moodlit | 3073 | 5173 | Yes | Yes |
### Apps without Servers (sync + web only)
These apps use only IndexedDB + mana-sync, no server-side compute:
| App | Web Port | `local` | `full` |
|-----|----------|---------|--------|
| Zitare | 5107 | Yes | Yes |
| Clock | 5187 | Yes | Yes |
| SkilltTree | 5195 | Yes | Yes |
| Photos | 5189 | Yes | Yes |
| CityCorners | 5196 | Yes | Yes |
| Inventar | 5190 | Yes | Yes |
| Times | 5197 | Yes | Yes |
| Calc | 5198 | Yes | Yes |
| ManaVoxel | 5028 | Yes | Yes |
### Infrastructure Ports
| Service | Port | Description |
|---------|------|-------------|
| mana-auth | 3001 | Central auth (Better Auth + EdDSA JWT) |
| mana-sync | 3050 | Data sync (Go, WebSocket, field-level LWW) |
| PostgreSQL | 5432 | Database |
| Redis | 6379 | Cache |
| MinIO API | 9000 | S3-compatible storage |
| MinIO Console | 9001 | Storage web UI |
## Prerequisites
@ -39,41 +98,65 @@ Before running any `dev:*:full` command:
# 1. Start Docker infrastructure (PostgreSQL, Redis, MinIO)
pnpm docker:up
# 2. Generate environment files (runs automatically on pnpm install)
# 2. Build mana-sync (first time only, or after Go changes)
pnpm dev:sync:build
# 3. Generate environment files (runs automatically on pnpm install)
pnpm setup:env
```
For `dev:*:local`, only mana-sync needs to be built. No Docker required unless your server uses a database.
## Database Setup Commands
### Individual Service Setup
```bash
pnpm setup:db:auth # Setup mana-core-auth database + schema
pnpm setup:db:chat # Setup chat database + schema
pnpm setup:db:zitare # Setup zitare database + schema
pnpm setup:db:contacts # Setup contacts database + schema
pnpm setup:db:calendar # Setup calendar database + schema
pnpm setup:db:clock # Setup clock database + schema
pnpm setup:db:todo # Setup todo database + schema
pnpm setup:db:picture # Setup picture database + schema
pnpm setup:db:auth # Setup mana-auth database + schema
pnpm setup:db:chat # Setup chat database + schema
pnpm setup:db:todo # Setup todo database + schema
pnpm setup:db:contacts # Setup contacts database + schema
pnpm setup:db:calendar # Setup calendar database + schema
pnpm setup:db:picture # Setup picture database + schema
pnpm setup:db:uload # Setup uload database + schema
pnpm setup:db:context # Setup context database + schema
pnpm setup:db:storage # Setup storage database + schema
pnpm setup:db:mukke # Setup mukke database + schema
pnpm setup:db:planta # Setup planta database + schema
pnpm setup:db:nutriphi # Setup nutriphi database + schema
pnpm setup:db:questions # Setup questions database + schema
pnpm setup:db:traces # Setup traces database + schema
```
### Setup All Databases
```bash
pnpm setup:db # Creates ALL databases and pushes ALL schemas
pnpm setup:db # Creates ALL databases and pushes ALL schemas
```
This is useful when setting up a fresh environment or after pulling new schema changes.
## How It Works
### Architecture
```
Guest: App -> IndexedDB (Dexie.js) -> UI (no sync)
Logged in: App -> IndexedDB -> UI -> SyncEngine -> mana-sync (Go) -> PostgreSQL
<- WebSocket push <-
```
**mana-sync** (Go, port 3050) handles WebSocket-based sync with field-level last-write-wins conflict resolution. All CRUD goes through IndexedDB first, making the UI instant regardless of network.
**Hono/Bun servers** handle operations that cannot run client-side:
- AI/LLM calls (chat, questions, picture generation)
- File operations (storage, media processing)
- RRULE expansion and reminder scheduling (todo, calendar)
- Server-side data processing (news extraction, transcription)
### Docker Init Script
On first `pnpm docker:up`, the PostgreSQL container runs `docker/init-db/01-create-databases.sql` which creates all databases:
- manacore, chat, zitare, contacts, calendar, clock, todo, manadeck
- storage, mail, moodlit, finance, inventory, techbase, voxel_lava, figgos
On first `pnpm docker:up`, the PostgreSQL container runs `docker/init-db/01-create-databases.sql` which creates all databases.
### Setup Script
@ -84,6 +167,16 @@ The `scripts/setup-databases.sh` script:
The `--force` flag auto-approves schema changes without interactive prompts.
### What each command starts
| Command pattern | What it runs |
|-----------------|-------------|
| `dev:*:local` | mana-sync + server (if any) + web |
| `dev:*:full` | DB setup + mana-auth + mana-sync + server (if any) + web |
| `dev:*:server` | Just the Hono/Bun server (`bun run --watch src/index.ts`) |
| `dev:*:web` | Just the SvelteKit web app |
| `dev:*:app` | Server + web (no sync, no auth) |
## Troubleshooting
### Database doesn't exist
@ -103,17 +196,26 @@ PGPASSWORD=devpassword psql -h localhost -U manacore -d postgres -c "CREATE DATA
If you see errors about missing tables/columns:
```bash
# Push the latest schema
pnpm --filter @chat/backend db:push --force
# Push the latest schema from the server package
pnpm --filter @chat/server db:push --force
```
### mana-sync not built
If you see `./server: No such file or directory`:
```bash
pnpm dev:sync:build
```
### Port already in use
If auth (port 3001) is already running:
If auth (port 3001) or sync (port 3050) is already running:
```bash
# Check what's using the port
lsof -i :3001
lsof -i :3050
# Kill the process if needed
kill <PID>
@ -134,23 +236,6 @@ pnpm docker:up
pnpm setup:db
```
## Apps Without Full Commands
Some apps don't have backends or don't use Drizzle:
| App | Reason |
|-----|--------|
| manacore | No backend (uses other services) |
| manadeck | Backend exists but no db:push |
| bauntown, context, maerchenzauber, memoro, news, nutriphi, presi, quote, reader, storage, wisekeep | No backends |
For these, use the regular dev commands:
```bash
pnpm dev:manacore:web
pnpm dev:manadeck:app
```
## Adding a New Application
### Step 1: Create Project Structure
@ -160,7 +245,7 @@ Create the standard project structure under `apps/`:
```
apps/newproject/
├── apps/
│ ├── backend/ # NestJS API (if needed)
│ ├── server/ # Hono/Bun server (if needed for compute)
│ ├── mobile/ # Expo React Native app
│ ├── web/ # SvelteKit web app
│ └── landing/ # Astro marketing page
@ -170,9 +255,24 @@ apps/newproject/
└── CLAUDE.md # Project documentation
```
### Step 2: Configure Backend Database (if applicable)
### Step 2: Set Up Local-First Data Layer
If your backend uses Drizzle ORM:
1. Create `apps/newproject/apps/web/src/lib/data/local-store.ts` with `createLocalStore()`
2. Create `apps/newproject/apps/web/src/lib/data/guest-seed.ts` for onboarding data
3. Use `collection.getAll()` / `collection.insert()` in stores (not API calls)
4. In layout: `await store.initialize()`, `store.startSync()` on login
### Step 3: Create Hono/Bun Server (if needed)
Only needed if your app requires server-side compute (AI, file ops, etc.).
Create `apps/newproject/apps/server/` with:
- `src/index.ts` -- Hono app entry point
- `src/config.ts` -- Port and env config
- `src/routes/health.ts` -- Health check endpoint
- `package.json` with `"name": "@newproject/server"`
### Step 4: Configure Database (if the server uses Drizzle)
1. **Add database to Docker init** (`docker/init-db/01-create-databases.sql`):
```sql
@ -181,84 +281,59 @@ If your backend uses Drizzle ORM:
```
2. **Add to setup script** (`scripts/setup-databases.sh`):
In the `setup_service()` function, add a new case:
```bash
newproject)
create_db_if_not_exists "newproject"
push_schema "@newproject/backend" "newproject"
push_schema "@newproject/server" "newproject"
;;
```
Also add to the `ALL_DATABASES` array:
```bash
ALL_DATABASES=(
...
"newproject"
)
```
And to the services loop at the bottom:
```bash
for service in auth chat ... newproject; do
```
3. **Add DATABASE_URL to `.env.development`**:
```env
NEWPROJECT_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/newproject
```
4. **Update `scripts/generate-env.mjs`** to generate the backend `.env` file.
4. **Update `scripts/generate-env.mjs`** to generate the server `.env` file.
### Step 3: Add Package.json Scripts
### Step 5: Add Package.json Scripts
Add to root `package.json`:
```json
{
"scripts": {
// Project-level dev (all apps)
"newproject:dev": "turbo run dev --filter=newproject...",
// Individual app commands
"dev:newproject:web": "pnpm --filter @newproject/web dev",
"dev:newproject:mobile": "pnpm --filter @newproject/mobile dev",
"dev:newproject:backend": "pnpm --filter @newproject/backend dev",
"dev:newproject:landing": "pnpm --filter @newproject/landing dev",
"dev:newproject:app": "turbo run dev --filter=@newproject/web --filter=@newproject/backend",
// Full dev with auto database setup
"dev:newproject:full": "./scripts/setup-databases.sh newproject && ./scripts/setup-databases.sh auth && concurrently -n auth,backend,web -c blue,green,cyan \"pnpm dev:auth\" \"pnpm dev:newproject:backend\" \"pnpm dev:newproject:web\"",
// Database shortcuts
"newproject:db:push": "pnpm --filter @newproject/backend db:push",
"newproject:db:studio": "pnpm --filter @newproject/backend db:studio",
// Setup shortcut
"dev:newproject:server": "cd apps/newproject/apps/server && bun run --watch src/index.ts",
"dev:newproject:local": "concurrently -n sync,server,web -c magenta,yellow,cyan \"pnpm dev:sync\" \"pnpm dev:newproject:server\" \"pnpm dev:newproject:web\"",
"dev:newproject:full": "./scripts/setup-databases.sh newproject && ./scripts/setup-databases.sh auth && concurrently -n auth,sync,server,web -c blue,magenta,yellow,cyan \"pnpm dev:auth\" \"pnpm dev:sync\" \"pnpm dev:newproject:server\" \"pnpm dev:newproject:web\"",
"setup:db:newproject": "./scripts/setup-databases.sh newproject"
}
}
```
### Step 4: Create Project CLAUDE.md
For apps **without** a server (sync + web only):
Create `apps/newproject/CLAUDE.md` with:
- Project overview
- Structure diagram
- Available commands
- API endpoints (if backend)
- Environment variables
- Tech stack details
```json
{
"scripts": {
"dev:newproject:web": "pnpm --filter @newproject/web dev",
"dev:newproject:local": "concurrently -n sync,web -c magenta,cyan \"pnpm dev:sync\" \"pnpm dev:newproject:web\"",
"dev:newproject:full": "concurrently -n auth,sync,web -c blue,magenta,cyan \"pnpm dev:auth\" \"pnpm dev:sync\" \"pnpm dev:newproject:web\""
}
}
```
See existing projects like `apps/chat/CLAUDE.md` for reference.
### Step 6: Create Project CLAUDE.md
### Step 5: Test the Setup
Create `apps/newproject/CLAUDE.md` with project overview, structure, commands, and API endpoints.
### Step 7: Test the Setup
```bash
# Create database and push schema
pnpm setup:db:newproject
# Quick start (no auth needed)
pnpm dev:newproject:local
# Start with full dev command
# Full stack (with auth + DB setup)
pnpm dev:newproject:full
```
@ -266,10 +341,13 @@ pnpm dev:newproject:full
- [ ] Create project structure under `apps/newproject/`
- [ ] Add `pnpm-workspace.yaml` in project root
- [ ] Add database to `docker/init-db/01-create-databases.sql`
- [ ] Add service to `scripts/setup-databases.sh`
- [ ] Add DATABASE_URL to `.env.development`
- [ ] Set up local-store with Dexie.js collections
- [ ] Create guest seed data
- [ ] Add Hono/Bun server (if compute needed)
- [ ] Add database to `docker/init-db/01-create-databases.sql` (if using Drizzle)
- [ ] Add service to `scripts/setup-databases.sh` (if using Drizzle)
- [ ] Add DATABASE_URL to `.env.development` (if using Drizzle)
- [ ] Update `scripts/generate-env.mjs` for env generation
- [ ] Add scripts to root `package.json`
- [ ] Create `CLAUDE.md` with project documentation
- [ ] Test with `pnpm dev:newproject:full`
- [ ] Test with `pnpm dev:newproject:local`

View file

@ -454,16 +454,15 @@ git pull
### Docker Base Images
Alle Apps werden auf vorgebauten Base Images aufgebaut, um Build-Zeit und Memory-Verbrauch zu reduzieren:
Alle Web-Apps werden auf einem vorgebauten Base Image aufgebaut, um Build-Zeit und Memory-Verbrauch zu reduzieren. Backend-Server verwenden `docker/Dockerfile.hono-server` (Hono + Bun) direkt.
| Base Image | Dockerfile | Verwendet von |
|------------|-----------|---------------|
| `sveltekit-base:local` | `docker/Dockerfile.sveltekit-base` | Alle SvelteKit Web-Apps |
| `nestjs-base:local` | `docker/Dockerfile.nestjs-base` | Alle NestJS Backends |
Die Base Images enthalten alle Shared Packages (`packages/`) vorinstalliert und vorgebaut. App-Dockerfiles müssen nur noch ihren app-spezifischen Code kopieren.
Das Base Image enthaelt alle Shared Packages (`packages/`) vorinstalliert und vorgebaut. App-Dockerfiles muessen nur noch ihren app-spezifischen Code kopieren.
**Base Images neu bauen** wenn sich Shared Packages ändern:
**Base Image neu bauen** wenn sich Shared Packages aendern:
```bash
./scripts/mac-mini/build-app.sh --base

View file

@ -46,23 +46,23 @@ Canonical port assignments for all ManaCore services. This is the single source
| 3024 | mana-voice-bot | Python | Voice-to-voice assistant |
| 3025-3029 | *(reserved)* | | |
## 3030-3059: App Backends
## 3030-3059: App Compute Servers
Only apps that need server-side compute (AI, external APIs, file operations).
Pure CRUD apps use mana-sync directly.
| Port | Service | Runtime | Description |
|------|---------|---------|-------------|
| 3030 | chat-backend | NestJS | AI chat, streaming, spaces |
| 3030 | chat-server | Hono/Bun | AI chat, streaming, spaces |
| 3031 | todo-server | Hono/Bun | RRULE expansion, reminders |
| 3032 | calendar-backend | NestJS | CalDAV sync, Google Calendar, notifications |
| 3033 | contacts-backend | NestJS | Google Contacts, vCard import/export |
| 3034 | storage-backend | NestJS | S3 file ops, versioning, shares |
| 3035 | picture-backend | NestJS | Replicate AI, generation orchestration |
| 3036 | manadeck-backend | NestJS | AI card generation |
| 3037 | mukke-backend | NestJS | Audio processing, BPM, ID3 tags |
| 3038 | nutriphi-backend | NestJS | Gemini meal analysis |
| 3039 | planta-backend | NestJS | Gemini plant analysis |
| 3032 | calendar-server | Hono/Bun | CalDAV sync, Google Calendar, notifications |
| 3033 | contacts-server | Hono/Bun | Google Contacts, vCard import/export |
| 3034 | storage-server | Hono/Bun | S3 file ops, versioning, shares |
| 3035 | picture-server | Hono/Bun | Replicate AI, generation orchestration |
| 3036 | manadeck-server | Hono/Bun | AI card generation |
| 3037 | mukke-server | Hono/Bun | Audio processing, BPM, ID3 tags |
| 3038 | nutriphi-server | Hono/Bun | Gemini meal analysis |
| 3039 | planta-server | Hono/Bun | Gemini plant analysis |
| 3040 | presi-server | Hono/Bun | Share links |
| 3041-3059 | *(reserved)* | | |
@ -78,28 +78,28 @@ Pure CRUD apps use mana-sync directly.
## 5000-5059: Web Frontends (SvelteKit)
| Port | Service | Corresponds to Backend |
| Port | Service | Corresponds to Server |
|------|---------|----------------------|
| 5000 | mana-web | Hub/Dashboard |
| 5010 | chat-web | 3030 chat-backend |
| 5010 | chat-web | 3030 chat-server |
| 5011 | todo-web | 3031 todo-server |
| 5012 | calendar-web | 3032 calendar-backend |
| 5012 | calendar-web | 3032 calendar-server |
| 5013 | clock-web | *(local-first only)* |
| 5014 | contacts-web | 3033 contacts-backend |
| 5015 | storage-web | 3034 storage-backend |
| 5014 | contacts-web | 3033 contacts-server |
| 5015 | storage-web | 3034 storage-server |
| 5016 | presi-web | 3040 presi-server |
| 5017 | nutriphi-web | 3038 nutriphi-backend |
| 5017 | nutriphi-web | 3038 nutriphi-server |
| 5018 | zitare-web | *(local-first only)* |
| 5019 | photos-web | *(local-first + mana-media)* |
| 5020 | skilltree-web | *(local-first only)* |
| 5021 | picture-web | 3035 picture-backend |
| 5021 | picture-web | 3035 picture-server |
| 5022 | citycorners-web | *(local-first only)* |
| 5023 | manadeck-web | 3036 manadeck-backend |
| 5024 | mukke-web | 3037 mukke-backend |
| 5023 | manadeck-web | 3036 manadeck-server |
| 5024 | mukke-web | 3037 mukke-server |
| 5025 | inventar-web | *(local-first only)* |
| 5026 | context-web | *(local-first only)* |
| 5027 | questions-web | *(local-first only)* |
| 5028 | planta-web | 3039 planta-backend |
| 5028 | planta-web | 3039 planta-server |
| 5029 | moodlit-web | *(future)* |
| 5030-5049 | *(reserved)* | |

View file

@ -412,7 +412,7 @@ nutriphi/
│ ├── mobile/ # Expo React Native App (@nutriphi/mobile)
│ ├── web/ # SvelteKit Web App (@nutriphi/web)
│ └── landing/ # Astro Landing Page (@nutriphi/landing)
├── backend/ # NestJS API Server (@nutriphi/backend)
├── server/ # Hono/Bun server (@nutriphi/server)
```
#### API Endpoints