style: auto-format codebase with Prettier

Applied formatting to 1487+ files using pnpm format:write
  - TypeScript/JavaScript files
  - Svelte components
  - Astro pages
  - JSON configs
  - Markdown docs

  13 files still need manual review (Astro JSX comments)
This commit is contained in:
Wuesteon 2025-11-27 18:33:16 +01:00
parent 0241f5554c
commit d36b321d9d
3952 changed files with 661498 additions and 739751 deletions

View file

@ -85,11 +85,13 @@ claude mcp remove supabase-maerchenzauber
Erstelle oder bearbeite die MCP-Konfigurationsdatei:
**Für lokales Scope** (nur für dich in diesem Projekt):
```bash
# .mcp.json im Projekt-Root erstellen
```
**Für User Scope** (global für alle deine Projekte):
```bash
# ~/.config/claude/mcp.json
```
@ -98,12 +100,12 @@ Erstelle oder bearbeite die MCP-Konfigurationsdatei:
```json
{
"mcpServers": {
"supabase-maerchenzauber": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc"
}
}
"mcpServers": {
"supabase-maerchenzauber": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc"
}
}
}
```
@ -179,12 +181,12 @@ Du kannst auf Datenbank-Ressourcen mit `@` verweisen:
```json
{
"mcpServers": {
"supabase-dev": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?project_ref=dyywxrmonxoiojsjmymc&features=database,development"
}
}
"mcpServers": {
"supabase-dev": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?project_ref=dyywxrmonxoiojsjmymc&features=database,development"
}
}
}
```
@ -192,12 +194,12 @@ Du kannst auf Datenbank-Ressourcen mit `@` verweisen:
```json
{
"mcpServers": {
"supabase-prod": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc&features=database"
}
}
"mcpServers": {
"supabase-prod": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc&features=database"
}
}
}
```
@ -205,12 +207,12 @@ Du kannst auf Datenbank-Ressourcen mit `@` verweisen:
```json
{
"mcpServers": {
"supabase-debug": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc&features=database,debugging"
}
}
"mcpServers": {
"supabase-debug": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc&features=database,debugging"
}
}
}
```
@ -276,12 +278,12 @@ Du kannst Umgebungsvariablen in der MCP-Konfiguration nutzen:
```json
{
"mcpServers": {
"supabase": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=${SUPABASE_PROJECT_REF}"
}
}
"mcpServers": {
"supabase": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=${SUPABASE_PROJECT_REF}"
}
}
}
```
@ -291,16 +293,16 @@ Du kannst mehrere Supabase-Projekte gleichzeitig konfigurieren:
```json
{
"mcpServers": {
"supabase-maerchenzauber-prod": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc"
},
"supabase-maerchenzauber-dev": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?project_ref=<dev-ref>"
}
}
"mcpServers": {
"supabase-maerchenzauber-prod": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc"
},
"supabase-maerchenzauber-dev": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?project_ref=<dev-ref>"
}
}
}
```
@ -310,17 +312,18 @@ Für Team-weite Konfiguration, erstelle `.mcp.json` im Projekt-Root:
```json
{
"mcpServers": {
"supabase-maerchenzauber": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc&features=database",
"description": "Märchenzauber Production DB (Read-Only)"
}
}
"mcpServers": {
"supabase-maerchenzauber": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?read_only=true&project_ref=dyywxrmonxoiojsjmymc&features=database",
"description": "Märchenzauber Production DB (Read-Only)"
}
}
}
```
**Vorteile:**
- Alle Teammitglieder nutzen die gleiche Konfiguration
- Versionskontrolle über Git
- Einheitliche Development-Experience

View file

@ -7,4 +7,4 @@ https://replicate.com/black-forest-labs/flux-1.1-pro
https://replicate.com/stability-ai/stable-diffusion-3.5-large-turbo
https://replicate.com/google/imagen-4
https://replicate.com/stability-ai/stable-diffusion-3.5-medium
https://replicate.com/google/nano-banana
https://replicate.com/google/nano-banana

View file

@ -22,6 +22,7 @@ const SYSTEM_USER_ID = '00000000-0000-0000-0000-000000000000';
```
This UUID is used consistently across:
- Database records (`user_id` field)
- Backend validation logic
- Frontend UI conditional rendering
@ -62,6 +63,7 @@ INSERT INTO public.characters (
The database uses RLS policies to allow all authenticated users to read system characters while protecting them from modification:
**Read Access Policy:**
```sql
CREATE POLICY "Users can view their own characters and system characters"
ON public.characters
@ -92,6 +94,7 @@ if (!isSystemCharacter && !isOwnCharacter) {
```
This pattern is applied in:
- `getCharacterById()` - GET /character/:id
- `updateCharacter()` - PUT /character/:id
- `deleteCharacter()` - DELETE /character/:id
@ -145,6 +148,7 @@ path: 00000000-0000-0000-0000-000000000000/characters/[filename]
```
Example URL:
```
https://dyywxrmonxoiojsjmymc.supabase.co/storage/v1/object/public/user-uploads/00000000-0000-0000-0000-000000000000/characters/1762453771144-cmngxj-large.webp
```
@ -201,9 +205,9 @@ Use Supabase MCP tools to apply the migration to both development and production
```typescript
// Example using MCP tools
await mcp__supabase__apply_migration({
project_id: "your-project-id",
name: "add_[character_name]_system_character",
query: "INSERT INTO ..."
project_id: 'your-project-id',
name: 'add_[character_name]_system_character',
query: 'INSERT INTO ...',
});
```
@ -218,6 +222,7 @@ await mcp__supabase__apply_migration({
- **Languages**: German (user_description) and English (character_description)
**Image Location**:
```
https://dyywxrmonxoiojsjmymc.supabase.co/storage/v1/object/public/user-uploads/00000000-0000-0000-0000-000000000000/characters/1762453771144-cmngxj-large.webp
```
@ -225,23 +230,27 @@ https://dyywxrmonxoiojsjmymc.supabase.co/storage/v1/object/public/user-uploads/0
## Best Practices
### Character Selection
- Choose characters with broad appeal for diverse story types
- Ensure high-quality, consistent character images
- Provide both German and English descriptions
- Make characters suitable for children's stories
### Naming Conventions
- Use descriptive, memorable names
- Consider cultural appropriateness
- Ensure uniqueness from user-created characters
### Image Requirements
- High resolution (recommended: 1024x1024 or higher)
- Consistent art style across system characters
- Child-appropriate content
- Clear, recognizable character features
### Database Management
- Always use migrations for changes
- Test in development before production
- Include rollback procedures in migrations
@ -252,6 +261,7 @@ https://dyywxrmonxoiojsjmymc.supabase.co/storage/v1/object/public/user-uploads/0
### Character Not Visible to Users
**Check RLS Policies:**
```sql
-- Verify the SELECT policy exists
SELECT * FROM pg_policies
@ -260,6 +270,7 @@ WHERE tablename = 'characters'
```
**Verify User ID:**
```sql
-- Ensure character has correct system user_id
SELECT id, name, user_id
@ -282,6 +293,7 @@ if (!isSystemCharacter && !isOwnCharacter) {
```
Check these files:
- `backend/src/character/character.controller.ts` (GET, PUT, DELETE)
- `backend/src/story/services/story-creation.service.ts` (character validation)
@ -299,18 +311,22 @@ Ensure the character object includes the `user_id` field from the API response.
## Related Files
### Backend
- `backend/src/character/character.controller.ts` - Character CRUD endpoints
- `backend/src/story/services/story-creation.service.ts` - Story creation validation
- `backend/src/core/services/supabase-data.service.ts` - Database operations
### Frontend
- `mobile/app/character/[id].tsx` - Character detail screen
- `mobile/src/utils/dataService.ts` - Character data service (removed hardcoded logic)
### Database
- Migration: `add_finnia_system_character_fixed`
- Migration: `cleanup_conflicting_character_policies`
### Documentation
- `CLAUDE.md` - Main project documentation
- This file - System characters documentation

View file

@ -1,29 +1,29 @@
# Märchenzauber - ToDos & Dokumentation
# M<EFBFBD>rchenzauber - ToDos & Dokumentation
## <¨ Bildmodell-Auswahl Feature (10.09.2025)
## <<EFBFBD> Bildmodell-Auswahl Feature (10.09.2025)
###  Was wurde implementiert
#### Backend-Änderungen
#### Backend-<EFBFBD>nderungen
1. **Datenbank-Schema**
- Neue Tabelle `user_settings` mit Spalte `image_model` erstellt
- RLS-Policies für sichere User-spezifische Einstellungen implementiert
- RLS-Policies f<EFBFBD>r sichere User-spezifische Einstellungen implementiert
- Migration-Script: `apps/backend/migrations/001_create_user_settings_table.sql`
2. **Model-Konfiguration** (`apps/backend/src/core/models/image-models.ts`)
- Drei Bildgenerierungsmodelle definiert:
- **FLUX Schnell**: Schnelle Generierung (1-2 Sek, 1 Credit)
- **FLUX Pro 1.1**: Premium-Qualität (10-15 Sek, 3 Credits)
- **Stable Diffusion XL**: Standard-Qualität (5-10 Sek, 2 Credits)
- Vollständige Replicate Model-IDs mit Versionen integriert
- **FLUX Pro 1.1**: Premium-Qualit<EFBFBD>t (10-15 Sek, 3 Credits)
- **Stable Diffusion XL**: Standard-Qualit<EFBFBD>t (5-10 Sek, 2 Credits)
- Vollst<EFBFBD>ndige Replicate Model-IDs mit Versionen integriert
3. **Settings Service** (`apps/backend/src/core/services/settings.service.ts`)
- `getUserImageModel(userId)`: Abrufen des User-spezifischen Modells
- `setUserImageModel(userId, modelId)`: Setzen eines neuen Modells
- `getAvailableImageModels()`: Liste aller verfügbaren Modelle
- `getAvailableImageModels()`: Liste aller verf<EFBFBD>gbaren Modelle
- `getImageModelInfo(modelId)`: Detailinformationen zu einem Modell
- Caching der User-Einstellungen für Performance
- Caching der User-Einstellungen f<EFBFBD>r Performance
4. **Image Service Updates** (`apps/backend/src/core/services/image-supabase.service.ts`)
- `generateImageWithReplicate()` nutzt jetzt User-spezifisches Modell
@ -35,22 +35,22 @@
- Drei Varianten aktualisiert: createCharacter, createCharacterFromImage, createCharacterSpecial
6. **Story Service Updates** (`apps/backend/src/story/services/story-creation.service.ts`)
- `generateIllustrationForPage()` nutzt User-ID für Modellauswahl
- Konsistente Modellnutzung für alle Illustrationen einer Story
- `generateIllustrationForPage()` nutzt User-ID f<EFBFBD>r Modellauswahl
- Konsistente Modellnutzung f<EFBFBD>r alle Illustrationen einer Story
7. **API Endpoints** (`apps/backend/src/settings/settings.controller.ts`)
- `GET /settings/image-models`: Verfügbare Modelle mit Metadaten
- `GET /settings/image-models`: Verf<EFBFBD>gbare Modelle mit Metadaten
- `GET /settings/user/image-model`: Aktuelles User-Modell abrufen
- `PUT /settings/user/image-model`: User-Modell ändern
- DTO für Modell-Updates: `apps/backend/src/settings/dto/image-model.dto.ts`
- `PUT /settings/user/image-model`: User-Modell <EFBFBD>ndern
- DTO f<EFBFBD>r Modell-Updates: `apps/backend/src/settings/dto/image-model.dto.ts`
#### Frontend-Änderungen
#### Frontend-<EFBFBD>nderungen
1. **Neue Settings-Seite** (`apps/mobile/app/(tabs)/(settings)/image-model.tsx`)
- Übersichtliche Card-basierte Modellauswahl
- Visual Feedback für ausgewähltes Modell
- Badges für Geschwindigkeit und Credit-Kosten
- Informative Beschreibungen für jedes Modell
- <EFBFBD>bersichtliche Card-basierte Modellauswahl
- Visual Feedback f<EFBFBD>r ausgew<65>hltes Modell
- Badges f<EFBFBD>r Geschwindigkeit und Credit-Kosten
- Informative Beschreibungen f<EFBFBD>r jedes Modell
- Loading- und Saving-States
- Error Handling mit User-Feedback
@ -59,16 +59,17 @@
- Navigation zur Modellauswahl-Seite
3. **UI Features**
- Responsive Design für verschiedene Bildschirmgrößen
- Responsive Design f<EFBFBD>r verschiedene Bildschirmgr<67><72>en
- Farbcodierte Badges (Schnell/Premium/Standard)
- Checkmark-Icon für ausgewähltes Modell
- Info-Box mit Erklärung zur Modellauswahl
- Checkmark-Icon f<EFBFBD>r ausgew<65>hltes Modell
- Info-Box mit Erkl<EFBFBD>rung zur Modellauswahl
### =' Was muss noch gemacht werden
#### Sofort erforderlich (vor Go-Live)
1. **Datenbank-Migration ausführen**   KRITISCH
1. **Datenbank-Migration ausf<73>hren** <20> KRITISCH
```bash
# In Supabase Dashboard oder via psql:
psql "postgresql://postgres.[project-id]:[password]@db.dyywxrmonxoiojsjmymc.supabase.co:5432/postgres"
@ -76,49 +77,50 @@
```
2. **Backend neu starten**
```bash
cd apps/backend
npm run dev # oder npm run start:prod für Produktion
npm run dev # oder npm run start:prod f<EFBFBD>r Produktion
```
3. **Testing**
- [ ] Modellauswahl in der App testen
- [ ] Story-Generierung mit verschiedenen Modellen testen
- [ ] Character-Erstellung mit verschiedenen Modellen testen
- [ ] Persistenz der Einstellungen prüfen
- [ ] Persistenz der Einstellungen pr<EFBFBD>fen
#### Nächste Schritte (Nice-to-have)
#### N<EFBFBD>chste Schritte (Nice-to-have)
1. **Performance & Monitoring**
- [ ] Logging für Modell-Performance (Generierungszeiten)
- [ ] Logging f<EFBFBD>r Modell-Performance (Generierungszeiten)
- [ ] Erfolgs-/Fehlerquoten pro Modell tracken
- [ ] Analytics für Modell-Präferenzen der User
- [ ] Analytics f<EFBFBD>r Modell-Pr<50>ferenzen der User
2. **User Experience**
- [ ] Modell-Empfehlungen basierend auf Use-Case
- [ ] Vorschau-Bilder für jedes Modell
- [ ] A/B Testing für optimale Default-Einstellung
- [ ] Vorschau-Bilder f<EFBFBD>r jedes Modell
- [ ] A/B Testing f<EFBFBD>r optimale Default-Einstellung
3. **Admin Features**
- [ ] Admin-Dashboard für Modell-Statistiken
- [ ] Admin-Dashboard f<EFBFBD>r Modell-Statistiken
- [ ] Modelle dynamisch aktivieren/deaktivieren
- [ ] Credit-Preise anpassen per Admin-Interface
4. **Erweiterte Features**
- [ ] Verschiedene Modelle für Characters vs. Stories
- [ ] User-Feedback zur Bildqualität erfassen
- [ ] Verschiedene Modelle f<EFBFBD>r Characters vs. Stories
- [ ] User-Feedback zur Bildqualit<EFBFBD>t erfassen
- [ ] Automatisches Fallback bei Modell-Ausfall
- [ ] Batch-Generierung mit mehreren Modellen (für Vergleich)
- [ ] Batch-Generierung mit mehreren Modellen (f<EFBFBD>r Vergleich)
### =Ê Technische Details
### =<EFBFBD> Technische Details
#### Modell-Spezifikationen
| Modell | Replicate ID | Geschwindigkeit | Credits | Use-Case |
|--------|-------------|-----------------|---------|----------|
| FLUX Schnell | `black-forest-labs/flux-schnell:5599ed30...` | 1-2s | 1 | Tests, Prototypen |
| FLUX Pro 1.1 | `black-forest-labs/flux-1.1-pro:8f06b9d3...` | 10-15s | 3 | Finale Stories |
| SDXL | `stability-ai/sdxl:39ed52f2...` | 5-10s | 2 | Standard |
| Modell | Replicate ID | Geschwindigkeit | Credits | Use-Case |
| ------------ | -------------------------------------------- | --------------- | ------- | ----------------- |
| FLUX Schnell | `black-forest-labs/flux-schnell:5599ed30...` | 1-2s | 1 | Tests, Prototypen |
| FLUX Pro 1.1 | `black-forest-labs/flux-1.1-pro:8f06b9d3...` | 10-15s | 3 | Finale Stories |
| SDXL | `stability-ai/sdxl:39ed52f2...` | 5-10s | 2 | Standard |
#### Datenbank-Schema
@ -134,22 +136,23 @@ CREATE TABLE user_settings (
### = Bekannte Issues & Fixes
1. **Import-Pfad-Fehler (GELÖST)**
1. **Import-Pfad-Fehler (GEL<EFBFBD>ST)**
- Problem: `Colors` Import-Pfad war falsch
- Lösung: Pfad von `../../../src/constants/Colors` zu `../../../constants/Colors` korrigiert
- L<EFBFBD>sung: Pfad von `../../../src/constants/Colors` zu `../../../constants/Colors` korrigiert
2. **TypeScript Strict Mode**
- Linter hat `!` zu required properties hinzugefügt
- Linter hat `!` zu required properties hinzugef<EFBFBD>gt
- DTOs nutzen jetzt strict mode compliance
### =Ý Testing Checklist
### =<EFBFBD> Testing Checklist
- [ ] **Backend API Tests**
```bash
# Modelle abrufen
curl http://localhost:3002/settings/image-models -H "Authorization: Bearer TOKEN"
# User-Modell ändern
# User-Modell <EFBFBD>ndern
curl -X PUT http://localhost:3002/settings/user/image-model \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
@ -157,55 +160,59 @@ CREATE TABLE user_settings (
```
- [ ] **Frontend Tests**
- Settings öffnen Bildgenerierung
- Modell auswählen und speichern
- App neu starten und prüfen ob Auswahl persistiert
- Settings <EFBFBD>ffnen <20> Bildgenerierung
- Modell ausw<EFBFBD>hlen und speichern
- App neu starten und pr<EFBFBD>fen ob Auswahl persistiert
- Neue Story/Character erstellen
- [ ] **Datenbank Tests**
```sql
-- User-Settings prüfen
-- User-Settings pr<EFBFBD>fen
SELECT * FROM user_settings;
-- Modell-Verteilung
SELECT image_model, COUNT(*) FROM user_settings GROUP BY image_model;
```
### =Ú Dokumentation
### =<EFBFBD> Dokumentation
- Vollständige Implementation-Dokumentation: `/IMAGE_MODEL_SELECTION_README.md`
- Vollst<EFBFBD>ndige Implementation-Dokumentation: `/IMAGE_MODEL_SELECTION_README.md`
- API-Dokumentation in den jeweiligen Controller-Dateien
- Frontend-Komponenten sind self-documenting mit TypeScript-Interfaces
### = Deployment Checklist
### =<EFBFBD> Deployment Checklist
1. [ ] Datenbank-Migration ausführen
2. [ ] Environment-Variable `MAERCHENZAUBER_REPLICATE_API_KEY` prüfen
1. [ ] Datenbank-Migration ausf<EFBFBD>hren
2. [ ] Environment-Variable `MAERCHENZAUBER_REPLICATE_API_KEY` pr<EFBFBD>fen
3. [ ] Backend deployen
4. [ ] Mobile App builden und deployen
5. [ ] Feature-Flag aktivieren (falls vorhanden)
6. [ ] Monitoring aktivieren
7. [ ] User-Kommunikation über neues Feature
7. [ ] User-Kommunikation <EFBFBD>ber neues Feature
---
## =Å Weitere TODOs (nicht related zu Bildmodell-Feature)
## =<EFBFBD> Weitere TODOs (nicht related zu Bildmodell-Feature)
### High Priority
- [ ] Story-Logbook vollständig implementieren
- [ ] Story-Logbook vollst<73>ndig implementieren
- [ ] Character-Konsistenz in Stories verbessern
- [ ] 10 Bilder pro Story generieren (aktuell nur 3)
### Medium Priority
- [ ] Mana Core Credit-System Integration vervollständigen
- [ ] Mana Core Credit-System Integration vervollst<73>ndigen
- [ ] Mehrsprachigkeit (DE/EN) konsistent umsetzen
- [ ] Performance-Optimierungen für große Story-Collections
- [ ] Performance-Optimierungen f<EFBFBD>r gro<72>e Story-Collections
### Low Priority
- [ ] Onboarding-Flow überarbeiten
- [ ] Onboarding-Flow <20>berarbeiten
- [ ] Push-Notifications implementieren
- [ ] Social-Sharing Features
---
*Letzte Aktualisierung: 10.09.2025 - Till Schneider*
_Letzte Aktualisierung: 10.09.2025 - Till Schneider_

View file

@ -26,6 +26,7 @@
Märchenzauber ist eine gut strukturierte, moderne App mit starkem technologischen Fundament (NestJS, React Native, Expo, Supabase). Die Analyse hat **62 konkrete Verbesserungsmöglichkeiten** identifiziert, die in folgende Kategorien fallen:
### Stärken der aktuellen Implementierung
- ✅ Saubere Modulstruktur (Backend + Frontend)
- ✅ Moderne Tech-Stack mit TypeScript
- ✅ Gute Komponenten-Architektur (Atomic Design)
@ -33,6 +34,7 @@ Märchenzauber ist eine gut strukturierte, moderne App mit starkem technologisch
- ✅ Responsive Design für verschiedene Bildschirmgrößen
### Hauptverbesserungspotenziale
- 🔴 **Kritisch:** Fehlende Fehlerbehandlung in mobilen Komponenten
- 🟡 **Wichtig:** Performance-Optimierungen (Caching, Lazy Loading)
- 🟢 **Nice-to-Have:** UX-Verbesserungen (Animationen, Feedback)
@ -46,6 +48,7 @@ Märchenzauber ist eine gut strukturierte, moderne App mit starkem technologisch
**Problem:** Die App verwendet nur Context API + lokale useState. Bei wachsender Komplexität wird dies zu Prop-Drilling und Re-Render-Problemen führen.
**Lösung:**
```typescript
// Empfehlung: Zustand für globalen State
import { create } from 'zustand';
@ -76,6 +79,7 @@ export const useStoryStore = create<StoryStore>()(
```
**Vorteile:**
- 🚀 Weniger Re-Renders durch selektive Subscriptions
- 💾 Automatisches Persistence
- 🧪 Bessere Testbarkeit
@ -90,6 +94,7 @@ export const useStoryStore = create<StoryStore>()(
**Problem:** Turborepo ist konfiguriert, aber `package.json` Scripts nutzen es nicht optimal.
**Lösung:**
```json
// Root package.json
{
@ -120,6 +125,7 @@ export const useStoryStore = create<StoryStore>()(
```
**Vorteile:**
- ⚡ Parallele Task-Ausführung
- 💾 Build-Caching zwischen Runs
- 🔄 Automatische Dependency-Resolution
@ -133,6 +139,7 @@ export const useStoryStore = create<StoryStore>()(
**Problem:** Types werden zwischen Mobile und Backend dupliziert.
**Aktuelle Situation:**
```typescript
// mobile/types/character.ts
export interface Character {
@ -152,6 +159,7 @@ export interface Character {
```
**Lösung:**
```typescript
// packages/shared-types/src/character.ts
export interface Character {
@ -179,6 +187,7 @@ export class CharacterDto {
```
**Vorteile:**
- ✅ Single Source of Truth
- 🔒 Type-Safety zwischen Services
- 🔄 Automatische API-Validierung
@ -194,6 +203,7 @@ export class CharacterDto {
**Problem:** `expo-image` wird verwendet, aber keine explizite Cache-Policy definiert.
**Lösung:**
```typescript
// components/atoms/OptimizedImage.tsx
import { Image, ImageContentFit } from 'expo-image';
@ -228,12 +238,13 @@ export function OptimizedImage({ uri, blurHash, size, aspectRatio = 16/9 }: Prop
```
**Zusätzlich: Preloading für Story Pages**
```typescript
// In StoryViewer beim Page Change
useEffect(() => {
// Preload next 2 pages
const nextPages = [currentPage + 1, currentPage + 2];
nextPages.forEach(pageNum => {
nextPages.forEach((pageNum) => {
const page = pages[pageNum];
if (page?.image_url) {
Image.prefetch(page.image_url);
@ -243,6 +254,7 @@ useEffect(() => {
```
**Vorteile:**
- 🚀 Schnelleres Laden (50-70% Reduktion)
- 💾 Reduzierter Daten-Traffic
- 🎨 Smooth BlurHash Transitions
@ -256,6 +268,7 @@ useEffect(() => {
**Problem:** `FlatList` rendert alle Stories, auch wenn sie nicht sichtbar sind.
**Lösung:**
```typescript
// app/stories.tsx
import { FlashList } from '@shopify/flash-list';
@ -296,6 +309,7 @@ export default function StoriesScreen() {
**Problem:** Identische Prompts führen zu redundanten AI-Calls (teuer & langsam).
**Lösung:**
```typescript
// backend/src/core/services/caching.service.ts
import { Injectable } from '@nestjs/common';
@ -326,15 +340,14 @@ export class CachingService {
}
private generateKey(prompt: string, model: string): string {
const hash = createHash('sha256')
.update(`${model}:${prompt}`)
.digest('hex');
const hash = createHash('sha256').update(`${model}:${prompt}`).digest('hex');
return `ai-prompt:${hash}`;
}
}
```
**Integration in PromptingService:**
```typescript
async createConsistentCharacterDescriptionPrompts(
story: string,
@ -369,6 +382,7 @@ async createConsistentCharacterDescriptionPrompts(
```
**Kostenersparnis (bei 1000 Stories/Monat):**
- Cache Hit Rate: ~30% (konservativ)
- AI Calls vermieden: 300/Monat
- Kosteneinsparung: **~$45-60/Monat**
@ -383,6 +397,7 @@ async createConsistentCharacterDescriptionPrompts(
**Problem:** User sieht nur "Lädt..." ohne Fortschrittsanzeige.
**Lösung:**
```typescript
// Backend: WebSocket oder SSE für Progress Updates
// Alternative: Polling-basiertes System mit story_logbooks
@ -431,6 +446,7 @@ export default function CreateStory() {
```
**Progress Steps:**
1. ✅ Charakter wird geladen (10%)
2. 📝 Geschichte wird geschrieben (30%)
3. 🎨 Illustrationen werden erstellt (70%)
@ -448,6 +464,7 @@ export default function CreateStory() {
**Problem:** Keine klare Guided Tour für neue User.
**Lösung:**
```typescript
// components/organisms/OnboardingTour.tsx
import { useEffect, useState } from 'react';
@ -459,22 +476,22 @@ const ONBOARDING_STEPS = [
title: 'Willkommen bei Märchenzauber!',
description: 'Erstelle magische Geschichten mit deinen eigenen Charakteren',
target: null,
cta: 'Los gehts!'
cta: 'Los gehts!',
},
{
id: 'create-character',
title: 'Erstelle deinen ersten Charakter',
description: 'Lade ein Foto hoch oder beschreibe deinen Charakter',
target: 'create-character-button',
cta: 'Charakter erstellen'
cta: 'Charakter erstellen',
},
{
id: 'create-story',
title: 'Schreibe deine erste Geschichte',
description: 'Beschreibe was passieren soll - die KI macht den Rest!',
target: 'create-story-button',
cta: 'Geschichte schreiben'
}
cta: 'Geschichte schreiben',
},
];
export function OnboardingTour({ onComplete }: { onComplete: () => void }) {
@ -485,7 +502,7 @@ export function OnboardingTour({ onComplete }: { onComplete: () => void }) {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 300,
useNativeDriver: true
useNativeDriver: true,
}).start();
}, [currentStep]);
@ -494,11 +511,12 @@ export function OnboardingTour({ onComplete }: { onComplete: () => void }) {
```
**Tracking:**
```typescript
posthog?.capture('onboarding_step_viewed', {
step: currentStep,
step_name: ONBOARDING_STEPS[currentStep].id,
time_spent: Date.now() - stepStartTime
time_spent: Date.now() - stepStartTime,
});
```
@ -511,6 +529,7 @@ posthog?.capture('onboarding_step_viewed', {
**Problem:** Share-Funktion vorhanden, aber kein Share-Sheet mit Preview.
**Lösung:**
```typescript
// components/molecules/ShareButton.tsx
import * as Sharing from 'expo-sharing';
@ -572,6 +591,7 @@ export function ShareButton({ story }: { story: Story }) {
```
**Zusätzlich: Deep Links für Shares**
```typescript
// app.json
{
@ -603,6 +623,7 @@ export function ShareButton({ story }: { story: Story }) {
**Problem:** App funktioniert nicht ohne Internet, auch für bereits geladene Stories.
**Lösung:**
```typescript
// src/services/offlineStorageService.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
@ -612,16 +633,13 @@ export class OfflineStorageService {
private static KEYS = {
STORIES: 'offline_stories',
CHARACTERS: 'offline_characters',
IMAGES: 'offline_images'
IMAGES: 'offline_images',
};
static async saveStoryForOffline(story: Story): Promise<void> {
const stories = await this.getOfflineStories();
const updated = [...stories.filter(s => s.id !== story.id), story];
await AsyncStorage.setItem(
this.KEYS.STORIES,
JSON.stringify(updated)
);
const updated = [...stories.filter((s) => s.id !== story.id), story];
await AsyncStorage.setItem(this.KEYS.STORIES, JSON.stringify(updated));
}
static async getOfflineStories(): Promise<Story[]> {
@ -649,20 +667,19 @@ export const dataService = {
const stories = await fetchWithAuth('/story');
// Cache for offline use
await Promise.all(
stories.map(story => OfflineStorageService.saveStoryForOffline(story))
);
await Promise.all(stories.map((story) => OfflineStorageService.saveStoryForOffline(story)));
return stories;
} catch (error) {
console.warn('Network error - falling back to offline cache');
return await OfflineStorageService.getOfflineStories();
}
}
},
};
```
**Offline Banner:**
```typescript
// components/molecules/OfflineBanner.tsx
export function OfflineBanner() {
@ -699,6 +716,7 @@ export function OfflineBanner() {
**Vorschläge:**
**A) Text-to-Speech für Geschichten**
```typescript
import * as Speech from 'expo-speech';
@ -733,6 +751,7 @@ function StoryPage({ page }: { page: StoryPage }) {
```
**B) Immersive Reading Mode**
```typescript
// Automatisches Durchblättern mit Timer
function StoryViewer({ pages }: { pages: StoryPage[] }) {
@ -769,6 +788,7 @@ function StoryViewer({ pages }: { pages: StoryPage[] }) {
```
**C) Bookmarking & Reading Progress**
```typescript
interface ReadingProgress {
storyId: string;
@ -785,7 +805,7 @@ useEffect(() => {
JSON.stringify({
currentPage,
lastReadAt: new Date().toISOString(),
completed: currentPage >= pages.length - 1
completed: currentPage >= pages.length - 1,
})
);
};
@ -816,6 +836,7 @@ useEffect(() => {
**Problem:** Character-Liste ist einfach, aber bietet keine Sortierung/Filterung.
**Lösung:**
```typescript
// app/characters.tsx
export default function CharactersScreen() {
@ -866,6 +887,7 @@ export default function CharactersScreen() {
```
**Zusätzlich: Character Stats**
```typescript
// backend: Add story_count to character response
async getUserCharacters(userId: string) {
@ -895,6 +917,7 @@ async getUserCharacters(userId: string) {
**Problem:** Responses haben unterschiedliche Formate (`Result<T>` vs. direkte Returns).
**Lösung:**
```typescript
// Standardisiertes API Response Format
export interface ApiResponse<T = any> {
@ -919,28 +942,28 @@ export class ResponseTransformInterceptor implements NestInterceptor {
const request = context.switchToHttp().getRequest();
return next.handle().pipe(
map(data => ({
map((data) => ({
success: true,
data,
meta: {
timestamp: new Date().toISOString(),
requestId: request.id,
version: '1.0'
}
version: '1.0',
},
})),
catchError(error => {
catchError((error) => {
return of({
success: false,
error: {
code: error.code || 'INTERNAL_ERROR',
message: error.message,
details: error.details
details: error.details,
},
meta: {
timestamp: new Date().toISOString(),
requestId: request.id,
version: '1.0'
}
version: '1.0',
},
});
})
);
@ -949,6 +972,7 @@ export class ResponseTransformInterceptor implements NestInterceptor {
```
**Vorteile:**
- ✅ Konsistente Responses
- 🔍 Besseres Error-Tracking mit Request-IDs
- 📊 Vereinfachte Client-Side Parsing
@ -962,6 +986,7 @@ export class ResponseTransformInterceptor implements NestInterceptor {
**Problem:** Keine Rate Limits auf teure AI-Endpoints.
**Lösung:**
```typescript
// backend/src/common/guards/rate-limit.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
@ -976,11 +1001,14 @@ export class CustomRateLimitGuard extends ThrottlerGuard {
}
protected async throwThrottlingException(context: ExecutionContext): Promise<void> {
throw new HttpException({
statusCode: 429,
message: 'Zu viele Anfragen. Bitte versuche es in ein paar Minuten erneut.',
retryAfter: 60
}, 429);
throw new HttpException(
{
statusCode: 429,
message: 'Zu viele Anfragen. Bitte versuche es in ein paar Minuten erneut.',
retryAfter: 60,
},
429
);
}
}
@ -1029,6 +1057,7 @@ export class StoryController {
**Problem:** Health Checks existieren, aber prüfen nur Basis-Status.
**Lösung:**
```typescript
// backend/src/health/health.controller.ts
import { HealthCheck, HealthCheckService, TypeOrmHealthIndicator } from '@nestjs/terminus';
@ -1040,7 +1069,7 @@ export class HealthController {
private db: TypeOrmHealthIndicator,
private supabase: SupabaseHealthIndicator,
private replicate: ReplicateHealthIndicator,
private manaCore: ManaCoreHealthIndicator,
private manaCore: ManaCoreHealthIndicator
) {}
@Get()
@ -1091,6 +1120,7 @@ export class HealthController {
```
**Monitoring Dashboard Integration:**
```typescript
// Prometheus Metrics
import { PrometheusModule } from '@willsoto/nestjs-prometheus';
@ -1116,9 +1146,7 @@ export class MetricsService {
});
recordStoryCreation(duration: number, success: boolean) {
this.storyCreationDuration
.labels(success ? 'success' : 'error')
.observe(duration);
this.storyCreationDuration.labels(success ? 'success' : 'error').observe(duration);
}
}
```
@ -1132,6 +1160,7 @@ export class MetricsService {
**Problem:** Mobile App muss pollen, um zu wissen, wann Story fertig ist.
**Lösung:**
```typescript
// backend/src/webhooks/webhook.service.ts
@Injectable()
@ -1182,6 +1211,7 @@ async createStory(params: StoryCreationParams): Promise<StoryCreationResult> {
```
**Mobile: Push Notification Handling**
```typescript
// mobile/src/services/pushNotificationService.ts
import * as Notifications from 'expo-notifications';
@ -1221,7 +1251,7 @@ export class PushNotificationService {
});
// Handle notification tap
Notifications.addNotificationResponseReceivedListener(response => {
Notifications.addNotificationResponseReceivedListener((response) => {
const { storyId, type } = response.notification.request.content.data;
if (type === 'story_completed') {
@ -1247,6 +1277,7 @@ export class PushNotificationService {
**Problem:** `updateCharacterImagesJsonb()` und ähnliche Methoden werden manuell aufgerufen.
**Lösung:**
```sql
-- backend/migrations/auto_sync_jsonb_fields.sql
@ -1312,6 +1343,7 @@ CREATE TRIGGER story_pages_sync
```
**Vorteile:**
- ✅ Automatische Konsistenz
- 🚀 Schnellere Abfragen (JSONB für Reads)
- 🔍 Relationale Integrität (für komplexe Queries)
@ -1325,6 +1357,7 @@ CREATE TRIGGER story_pages_sync
**Problem:** Search-Bar in `stories.tsx` nutzt nur `includes()` auf Titel/Prompt.
**Lösung:**
```sql
-- Add Full-Text Search columns
ALTER TABLE stories
@ -1358,6 +1391,7 @@ UPDATE stories SET search_vector =
```
**Backend API:**
```typescript
// story.controller.ts
@Get('search')
@ -1385,6 +1419,7 @@ async searchStories(query: string, userId: string): Promise<Story[]> {
```
**Mobile Integration:**
```typescript
// app/stories.tsx
const [searchQuery, setSearchQuery] = useState('');
@ -1420,6 +1455,7 @@ return (
**Problem:** Keine explizite Backup-Strategie dokumentiert.
**Empfehlung (Supabase-spezifisch):**
```bash
# Tägliche Backups via Supabase CLI
# .github/workflows/database-backup.yml
@ -1455,6 +1491,7 @@ jobs:
```
**Point-in-Time Recovery:**
```sql
-- Supabase bietet 7-Tage PITR (Pro Plan)
-- Restore zu spezifischem Zeitpunkt:
@ -1472,6 +1509,7 @@ jobs:
**Problem:** Keine End-to-End Tests.
**Lösung:**
```typescript
// mobile/e2e/createStory.test.ts (mit Detox)
describe('Story Creation Flow', () => {
@ -1530,6 +1568,7 @@ describe('Story Creation Flow', () => {
```
**Backend Integration Tests:**
```typescript
// backend/test/e2e/story.e2e-spec.ts
describe('Story API (e2e)', () => {
@ -1580,6 +1619,7 @@ describe('Story API (e2e)', () => {
**Problem:** Manual `.env` setup notwendig.
**Lösung:**
```bash
#!/bin/bash
# scripts/setup-dev.sh
@ -1629,6 +1669,7 @@ echo " Mobile: Expo Dev Client wird gestartet..."
```
**VS Code Workspace Settings:**
```json
// .vscode/settings.json
{
@ -1684,6 +1725,7 @@ echo " Mobile: Expo Dev Client wird gestartet..."
**Problem:** Keine strukturierte Logging-Strategie.
**Lösung:**
```typescript
// backend/src/common/logger/logger.service.ts
import { Injectable, LoggerService as NestLoggerService } from '@nestjs/common';
@ -1752,6 +1794,7 @@ export class LoggerService implements NestLoggerService {
```
**Structured Logging in Services:**
```typescript
// story-creation.service.ts
this.logger.log('Creating story', 'StoryCreationService', {
@ -1765,6 +1808,7 @@ this.logger.log('Creating story', 'StoryCreationService', {
```
**Log Aggregation (Optional):**
```typescript
// Integration mit Datadog/Sentry
import * as Sentry from '@sentry/node';
@ -1791,6 +1835,7 @@ Sentry.init({
**Problem:** Manche DTOs haben nur partielle Validierung.
**Lösung:**
```typescript
// story/dto/create-story.dto.ts (aktuell nur Zod)
import { IsString, IsArray, IsUUID, IsOptional, MaxLength, MinLength } from 'class-validator';
@ -1801,7 +1846,7 @@ export class CreateAnimalStoryDto {
description: 'Story description prompt',
example: 'A magical adventure in the forest',
minLength: 10,
maxLength: 2000
maxLength: 2000,
})
@IsString()
@MinLength(10, { message: 'Story description must be at least 10 characters' })
@ -1810,14 +1855,14 @@ export class CreateAnimalStoryDto {
@ApiProperty({
description: 'Character ID',
example: 'uuid-here'
example: 'uuid-here',
})
@IsUUID('4', { message: 'Invalid character ID format' })
characterId: string;
@ApiProperty({
description: 'Optional author ID',
required: false
required: false,
})
@IsOptional()
@IsUUID('4')
@ -1825,7 +1870,7 @@ export class CreateAnimalStoryDto {
@ApiProperty({
description: 'Optional illustrator ID',
required: false
required: false,
})
@IsOptional()
@IsUUID('4')
@ -1833,27 +1878,30 @@ export class CreateAnimalStoryDto {
}
// Global Validation Pipe
app.useGlobalPipes(new ValidationPipe({
whitelist: true, // Strip properties not in DTO
forbidNonWhitelisted: true, // Throw error on unknown properties
transform: true, // Auto-transform to DTO types
transformOptions: {
enableImplicitConversion: true
},
exceptionFactory: (errors) => {
const messages = errors.map(error => ({
field: error.property,
errors: Object.values(error.constraints || {}),
}));
return new BadRequestException({
message: 'Validation failed',
errors: messages,
});
},
}));
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // Strip properties not in DTO
forbidNonWhitelisted: true, // Throw error on unknown properties
transform: true, // Auto-transform to DTO types
transformOptions: {
enableImplicitConversion: true,
},
exceptionFactory: (errors) => {
const messages = errors.map((error) => ({
field: error.property,
errors: Object.values(error.constraints || {}),
}));
return new BadRequestException({
message: 'Validation failed',
errors: messages,
});
},
})
);
```
**Vorteile:**
- 🛡️ Schutz vor Injection-Attacks
- ✅ Bessere Fehler-Messages
- 📚 Automatische API-Dokumentation (Swagger)
@ -1867,6 +1915,7 @@ app.useGlobalPipes(new ValidationPipe({
**Problem:** Keine Filterung von unangemessenen Story-Prompts.
**Lösung:**
```typescript
// backend/src/moderation/moderation.service.ts
import { Injectable } from '@nestjs/common';
@ -1931,6 +1980,7 @@ async createStory(@Body() dto: CreateStoryDto) {
```
**Client-Side Handling:**
```typescript
// mobile/app/createStory.tsx
try {
@ -1960,6 +2010,7 @@ try {
**Problem:** API Keys sind statisch in `.env`.
**Empfehlung:**
```typescript
// Verwendung von Secret Manager (z.B. Google Secret Manager)
import { SecretManagerServiceClient } from '@google-cloud/secret-manager';
@ -1994,6 +2045,7 @@ export default async (): Promise<AppConfig> => {
```
**Alternative: Vault/Doppler**
```bash
# Doppler CLI für lokale Entwicklung
npx doppler run -- npm run dev
@ -2015,6 +2067,7 @@ doppler secrets download --no-file --format env > .env.production
**Ziel:** 80%+ Coverage für kritische Services
**Beispiel: Story Creation Service Tests**
```typescript
// backend/src/story/services/story-creation.service.spec.ts
describe('StoryCreationService', () => {
@ -2080,10 +2133,12 @@ describe('StoryCreationService', () => {
supabaseService.getCharacterById.mockResolvedValue(mockCharacter);
promptingService.createConsistentCharacterDescriptionPrompts.mockResolvedValue({
data: [{
characterDescription: 'A friendly brown bear',
pages: [1, 2],
}],
data: [
{
characterDescription: 'A friendly brown bear',
pages: [1, 2],
},
],
error: null,
});
imageService.generateIllustrationForPage.mockResolvedValue({
@ -2149,14 +2204,16 @@ describe('StoryCreationService', () => {
});
// Should fall back to original character description
expect(result.storyData.characters_data[0].character_description)
.toBe('Fallback description');
expect(result.storyData.characters_data[0].character_description).toBe(
'Fallback description'
);
});
});
});
```
**Coverage Script:**
```json
// package.json
{
@ -2194,6 +2251,7 @@ describe('StoryCreationService', () => {
**Problem:** Keine Tests für komplette User Journeys.
**Lösung:**
```typescript
// backend/test/integration/story-flow.integration.spec.ts
describe('Complete Story Creation Flow (Integration)', () => {
@ -2276,7 +2334,7 @@ describe('Complete Story Creation Flow (Integration)', () => {
.set('Authorization', `Bearer ${authToken}`)
.expect(200);
const createdStory = getStoriesRes.body.find(s => s.id === storyId);
const createdStory = getStoriesRes.body.find((s) => s.id === storyId);
expect(createdStory).toBeDefined();
expect(createdStory.character_id).toBe(characterId);
@ -2309,6 +2367,7 @@ describe('Complete Story Creation Flow (Integration)', () => {
**Verbesserung:** Dynamisches Pricing basierend auf Komplexität
**Lösung:**
```typescript
// backend/src/credits/pricing.service.ts
@Injectable()
@ -2400,6 +2459,7 @@ async createStory(params: StoryCreationParams) {
```
**Mobile: Show Price Before Creation**
```typescript
// app/createStory.tsx
const [estimatedPrice, setEstimatedPrice] = useState<number>(0);
@ -2441,14 +2501,15 @@ return (
**Vorschlag:**
| Tier | Preis/Monat | Credits | Features |
|------|-------------|---------|----------|
| **Free** | €0 | 5 | - 1 Charakter<br>- Basis-Modell (flux-schnell)<br>- Wasserzeichen |
| **Basic** | €9.99 | 50 | - 5 Charaktere<br>- Standard-Modelle<br>- Kein Wasserzeichen |
| **Pro** | €19.99 | 150 | - Unlimitierte Charaktere<br>- Premium-Modelle (Flux Pro, Imagen)<br>- Early Access Features<br>- Priority Support |
| **Family** | €29.99 | 300 | - Alle Pro Features<br>- Multi-User Accounts (bis zu 5)<br>- Shared Character Library |
| Tier | Preis/Monat | Credits | Features |
| ---------- | ----------- | ------- | ------------------------------------------------------------------------------------------------------------------ |
| **Free** | €0 | 5 | - 1 Charakter<br>- Basis-Modell (flux-schnell)<br>- Wasserzeichen |
| **Basic** | €9.99 | 50 | - 5 Charaktere<br>- Standard-Modelle<br>- Kein Wasserzeichen |
| **Pro** | €19.99 | 150 | - Unlimitierte Charaktere<br>- Premium-Modelle (Flux Pro, Imagen)<br>- Early Access Features<br>- Priority Support |
| **Family** | €29.99 | 300 | - Alle Pro Features<br>- Multi-User Accounts (bis zu 5)<br>- Shared Character Library |
**Implementation:**
```typescript
// backend/src/subscriptions/subscription.service.ts
@Injectable()
@ -2468,20 +2529,20 @@ export class SubscriptionService {
private getCreditsForTier(tier: string): number {
const tiers = {
'free': 5,
'basic': 50,
'pro': 150,
'family': 300,
free: 5,
basic: 50,
pro: 150,
family: 300,
};
return tiers[tier] || 0;
}
private getFeaturesForTier(tier: string): string[] {
const features = {
'free': ['1_character', 'basic_model', 'watermark'],
'basic': ['5_characters', 'standard_models', 'no_watermark'],
'pro': ['unlimited_characters', 'premium_models', 'early_access', 'priority_support'],
'family': ['all_pro', 'multi_user', 'shared_library'],
free: ['1_character', 'basic_model', 'watermark'],
basic: ['5_characters', 'standard_models', 'no_watermark'],
pro: ['unlimited_characters', 'premium_models', 'early_access', 'priority_support'],
family: ['all_pro', 'multi_user', 'shared_library'],
};
return features[tier] || [];
}
@ -2497,19 +2558,18 @@ export class SubscriptionService {
**Idee:** Credits für Shares/Referrals
**Lösung:**
```typescript
// backend/src/referrals/referral.service.ts
@Injectable()
export class ReferralService {
async trackShare(userId: string, storyId: string, platform: string): Promise<void> {
await this.supabase
.from('story_shares')
.insert({
user_id: userId,
story_id: storyId,
platform,
shared_at: new Date().toISOString(),
});
await this.supabase.from('story_shares').insert({
user_id: userId,
story_id: storyId,
platform,
shared_at: new Date().toISOString(),
});
// Award share credits (1 credit per share, max 5/day)
const sharesToday = await this.getSharesCountToday(userId);
@ -2539,6 +2599,7 @@ export class ReferralService {
```
**Mobile: Referral Code System**
```typescript
// app/settings.tsx
export default function Settings() {
@ -2578,14 +2639,14 @@ export default function Settings() {
### 🔴 Kritisch (Sofort angehen)
| # | Verbesserung | Aufwand | Impact | Grund |
|---|--------------|---------|--------|-------|
| 1 | Rate Limiting (4.2) | 0.5T | Hoch | Kostenkontrolle, Abuse Prevention |
| 2 | Input Validation (7.1) | 1T | Hoch | Security, SQL Injection Prevention |
| 3 | Content Moderation (7.2) | 1T | Hoch | Legal Compliance, Brand Safety |
| 4 | Image Caching (2.1) | 1T | Hoch | User Experience, Kosten |
| 5 | DB Backup Strategy (5.3) | 0.5T | Hoch | Datensicherheit |
| 6 | Subscription System (9.2) | 5-7T | Sehr Hoch | Revenue-kritisch |
| # | Verbesserung | Aufwand | Impact | Grund |
| --- | ------------------------- | ------- | --------- | ---------------------------------- |
| 1 | Rate Limiting (4.2) | 0.5T | Hoch | Kostenkontrolle, Abuse Prevention |
| 2 | Input Validation (7.1) | 1T | Hoch | Security, SQL Injection Prevention |
| 3 | Content Moderation (7.2) | 1T | Hoch | Legal Compliance, Brand Safety |
| 4 | Image Caching (2.1) | 1T | Hoch | User Experience, Kosten |
| 5 | DB Backup Strategy (5.3) | 0.5T | Hoch | Datensicherheit |
| 6 | Subscription System (9.2) | 5-7T | Sehr Hoch | Revenue-kritisch |
**Gesamt: ~10 Tage**
@ -2593,22 +2654,22 @@ export default function Settings() {
### 🟡 Wichtig (Nächste 1-2 Monate)
| # | Verbesserung | Aufwand | Impact | Grund |
|---|--------------|---------|--------|-------|
| 7 | State Management (1.1) | 2-3T | Hoch | Skalierbarkeit |
| 8 | Shared Types (1.3) | 2-3T | Hoch | Type Safety, DX |
| 9 | AI Caching (2.3) | 2T | Hoch | Kosteneinsparung |
| 10 | Progress Tracking (2.4) | 3T | Hoch | UX |
| 11 | Onboarding (3.1) | 2T | Hoch | User Retention |
| 12 | Story Sharing (3.2) | 2T | Hoch | Growth |
| 13 | Immersive Reading (3.4) | 3-4T | Hoch | UX |
| 14 | API Standardisierung (4.1) | 1T | Mittel | DX, Maintainability |
| 15 | Webhooks (4.4) | 2-3T | Hoch | UX |
| 16 | JSONB Auto-Sync (5.1) | 1T | Mittel | Data Consistency |
| 17 | Logging System (6.3) | 1T | Mittel | Debugging, Monitoring |
| 18 | Unit Tests (8.1) | 5-7T | Hoch | Code Quality |
| 19 | Dynamic Pricing (9.1) | 2T | Hoch | Revenue Optimization |
| 20 | Referral System (9.3) | 3T | Hoch | Growth |
| # | Verbesserung | Aufwand | Impact | Grund |
| --- | -------------------------- | ------- | ------ | --------------------- |
| 7 | State Management (1.1) | 2-3T | Hoch | Skalierbarkeit |
| 8 | Shared Types (1.3) | 2-3T | Hoch | Type Safety, DX |
| 9 | AI Caching (2.3) | 2T | Hoch | Kosteneinsparung |
| 10 | Progress Tracking (2.4) | 3T | Hoch | UX |
| 11 | Onboarding (3.1) | 2T | Hoch | User Retention |
| 12 | Story Sharing (3.2) | 2T | Hoch | Growth |
| 13 | Immersive Reading (3.4) | 3-4T | Hoch | UX |
| 14 | API Standardisierung (4.1) | 1T | Mittel | DX, Maintainability |
| 15 | Webhooks (4.4) | 2-3T | Hoch | UX |
| 16 | JSONB Auto-Sync (5.1) | 1T | Mittel | Data Consistency |
| 17 | Logging System (6.3) | 1T | Mittel | Debugging, Monitoring |
| 18 | Unit Tests (8.1) | 5-7T | Hoch | Code Quality |
| 19 | Dynamic Pricing (9.1) | 2T | Hoch | Revenue Optimization |
| 20 | Referral System (9.3) | 3T | Hoch | Growth |
**Gesamt: ~35-40 Tage**
@ -2616,16 +2677,16 @@ export default function Settings() {
### 🟢 Nice-to-Have (Backlog)
| # | Verbesserung | Aufwand | Impact | Anmerkung |
|---|--------------|---------|--------|-----------|
| 21 | Monorepo Optimization (1.2) | 1T | Mittel | DX |
| 22 | FlashList (2.2) | 0.5T | Mittel | Performance |
| 23 | Offline Mode (3.3) | 2T | Mittel | Edge Case |
| 24 | Character Filters (3.5) | 1-2T | Mittel | UX |
| 25 | Health Checks (4.3) | 1T | Mittel | Ops |
| 26 | Full-Text Search (5.2) | 1T | Mittel | UX |
| 27 | Dev Setup Script (6.2) | 0.5T | Mittel | DX |
| 28 | API Key Rotation (7.3) | 1T | Hoch | Security (long-term) |
| # | Verbesserung | Aufwand | Impact | Anmerkung |
| --- | --------------------------- | ------- | ------ | -------------------- |
| 21 | Monorepo Optimization (1.2) | 1T | Mittel | DX |
| 22 | FlashList (2.2) | 0.5T | Mittel | Performance |
| 23 | Offline Mode (3.3) | 2T | Mittel | Edge Case |
| 24 | Character Filters (3.5) | 1-2T | Mittel | UX |
| 25 | Health Checks (4.3) | 1T | Mittel | Ops |
| 26 | Full-Text Search (5.2) | 1T | Mittel | UX |
| 27 | Dev Setup Script (6.2) | 0.5T | Mittel | DX |
| 28 | API Key Rotation (7.3) | 1T | Hoch | Security (long-term) |
**Gesamt: ~10 Tage**
@ -2634,6 +2695,7 @@ export default function Settings() {
## Zusammenfassung
### Quick Wins (< 1 Tag, Hoher Impact)
1. ✅ Rate Limiting (0.5T)
2. ✅ Input Validation (1T)
3. ✅ Content Moderation (1T)
@ -2645,6 +2707,7 @@ export default function Settings() {
---
### MVP Next Steps (1-2 Wochen)
1. Subscription System implementieren (5-7T)
2. State Management modernisieren (2-3T)
3. AI Caching aufsetzen (2T)
@ -2655,6 +2718,7 @@ export default function Settings() {
---
### Long-Term Roadmap (3-6 Monate)
1. **Q1:** Kritische Verbesserungen + Subscription
2. **Q2:** UX Verbesserungen + Testing
3. **Q3:** Growth Features (Referrals, Sharing)
@ -2687,4 +2751,4 @@ Dieses Dokument sollte als lebendes Dokument behandelt werden. Nach Implementier
**Ende des Dokuments**
*Erstellt mit ❤️ für Märchenzauber*
_Erstellt mit ❤️ für Märchenzauber_

View file

@ -3,7 +3,9 @@
## 🔴 What We Tried (That Didn't Work)
### Attempt 1: Git Config URL Rewriting
**What we did:**
```yaml
- name: Configure git for private packages
run: |
@ -13,32 +15,41 @@
```
**Why it failed:**
- npm ci reads URLs directly from `package-lock.json`
- npm's internal git client doesn't reliably honor git config `url.insteadOf` rules
- npm fell back to SSH when it couldn't authenticate via HTTPS
### Attempt 2: Invalid .npmrc Configuration
**What we did:**
```
# backend/.npmrc
git-ssh-url = https://github.com/
```
**Why it failed:**
- `git-ssh-url` is not a valid npm configuration option
- npm doesn't recognize this setting
### Attempt 3: Reordering Steps (Git Config Before Node Setup)
**What we did:**
- Moved git config step before `actions/setup-node`
- Added npm cache clearing
**Why it failed:**
- While this helped with caching issues, it didn't solve the root problem
- npm ci still ignored git config and used lockfile URLs directly
### Attempt 4: persist-credentials: false
**What we did:**
```yaml
- uses: actions/checkout@v4
with:
@ -46,11 +57,14 @@ git-ssh-url = https://github.com/
```
**Why it failed (partially):**
- This fixed the token override issue (actions/checkout was setting default GITHUB_TOKEN)
- But npm ci still couldn't authenticate because the lockfile URL had no token
### Attempt 5: Local Git Config Override
**What we did:**
```bash
# Try to override global SSH rewrites with local HTTPS config
cd project-root
@ -61,6 +75,7 @@ npm install
```
**Why it failed:**
- npm's internal git client doesn't consistently honor local git config during package resolution
- Even with correct local config, npm still generated SSH URLs in `package-lock.json`
- The git config order of precedence (local > global > system) doesn't reliably apply to npm's git subprocess
@ -72,19 +87,23 @@ npm install
## ✅ What Finally Worked
### The Root Cause
**npm ci uses URLs from package-lock.json directly and ignores git config url.insteadOf**
Even though:
- ✅ package.json had `git+https://github.com/...`
- ✅ package-lock.json had `git+https://github.com/...` (no SSH)
- ✅ git config was properly set
npm would run:
```bash
git ls-remote https://github.com/Memo-2023/mana-core-nestjs-package.git
```
This failed with "Permission denied" because:
1. The URL had no authentication token
2. npm fell back to SSH (which wasn't configured)
3. Git config rewrites were ignored by npm's git subprocess
@ -92,13 +111,15 @@ This failed with "Permission denied" because:
### The Solution: Runtime Token Injection
**Step 1: Prevent Token Override**
```yaml
- uses: actions/checkout@v4
with:
persist-credentials: false # Don't let default GITHUB_TOKEN interfere
persist-credentials: false # Don't let default GITHUB_TOKEN interfere
```
**Step 2a: If lockfile has HTTPS URLs - Verify and Inject Token**
```yaml
- name: Verify no SSH URLs in lockfile
run: |
@ -116,6 +137,7 @@ This failed with "Permission denied" because:
```
**Step 2b: If lockfile has SSH URLs - Patch to HTTPS with Token**
```yaml
- name: Patch SSH URLs to HTTPS with token
env:
@ -135,6 +157,7 @@ This failed with "Permission denied" because:
> **Note**: Use Step 2a if you can generate HTTPS lockfiles locally. Use Step 2b if your local git config always generates SSH URLs (accepts either format).
**Step 4: Run npm ci**
```yaml
- name: Install dependencies
run: npm ci
@ -148,6 +171,7 @@ This failed with "Permission denied" because:
4. **Consistent Behavior**: Works across npm v7, v8, v9+ and all CI environments
### The Execution Order (Critical)
```
1. Checkout (persist-credentials: false)
2. Configure git (defense in depth, may help in edge cases)
@ -161,24 +185,26 @@ This failed with "Permission denied" because:
## 📊 Key Learnings
| Issue | What We Learned |
|-------|----------------|
| Git config ignored | npm ci reads package-lock.json directly, bypasses git config |
| persist-credentials | Default checkout token can override custom PAT config |
| npm v7+ behavior | Modern npm converts HTTPS to SSH for private repos if auth fails |
| Token placement | Must inject token into lockfile URL, not just configure git |
| sed is reliable | Runtime patching with sed is more reliable than git rewrites |
| Issue | What We Learned |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| Git config ignored | npm ci reads package-lock.json directly, bypasses git config |
| persist-credentials | Default checkout token can override custom PAT config |
| npm v7+ behavior | Modern npm converts HTTPS to SSH for private repos if auth fails |
| Token placement | Must inject token into lockfile URL, not just configure git |
| sed is reliable | Runtime patching with sed is more reliable than git rewrites |
| Local git config fails | npm's git subprocess doesn't honor local config consistently - even `git ls-remote` works but `npm install` still writes SSH |
| Don't fight it locally | Stop trying to generate HTTPS lockfiles locally - accept SSH and patch in CI |
| Don't fight it locally | Stop trying to generate HTTPS lockfiles locally - accept SSH and patch in CI |
## 🎯 The One-Liner That Fixed It
**For HTTPS lockfiles:**
```bash
sed -i "s|https://github.com/Memo-2023/|https://${GH_TOKEN}@github.com/Memo-2023/|g" package-lock.json
```
**For SSH lockfiles (if your local git config generates SSH URLs):**
```bash
sed -i "s|git+ssh://git@github.com/Memo-2023/|git+https://${GH_TOKEN}@github.com/Memo-2023/|g" package-lock.json
```
@ -267,6 +293,7 @@ Make sure you have set up in your repository:
If your local git config **always** generates SSH URLs in `package-lock.json` (despite attempts to fix it locally), you have two options:
### Option 1: Accept SSH and Patch in CI (Recommended)
1. **Stop fighting with local git config** - it's unreliable
2. **Commit the lockfile with SSH URLs** as-is
3. **Use the flexible sed command** in CI that handles both SSH and HTTPS:
@ -285,6 +312,7 @@ If your local git config **always** generates SSH URLs in `package-lock.json` (d
```
### Option 2: Force HTTPS Locally (Fragile)
If you insist on HTTPS lockfiles, you must ensure NO global git config rewrites exist:
```bash
@ -307,4 +335,4 @@ npm install
**Date Fixed:** 2025-09-29
**Commit:** `5cce473` - fix: inject PAT token into package-lock.json for npm ci
**Updated:** 2025-09-30 - Added SSH lockfile handling documentation
**Updated:** 2025-09-30 - Added SSH lockfile handling documentation

View file

@ -5,11 +5,13 @@
Dieses Dokument beschreibt das Upgrade von **Expo SDK 51** (aktuell) auf **Expo SDK 54** für das Märchenzauber Projekt.
### Aktuelle Version
- **Expo SDK**: 51.0.28
- **React Native**: 0.74.5
- **React**: 18.2.0
### Zielversion
- **Expo SDK**: 54.0.0
- **React Native**: 0.81.0
- **React**: 19.1.0
@ -17,20 +19,24 @@ Dieses Dokument beschreibt das Upgrade von **Expo SDK 51** (aktuell) auf **Expo
## 🚀 Neue Features in SDK 54
### 1. Performance-Verbesserungen
- **Precompiled XCFrameworks für iOS**: Reduziert Clean-Build-Zeiten von ~120 auf ~10 Sekunden
- **Schnellere Builds**: Besonders bei großen Projekten spürbar
### 2. Native UI-Features
- **Native Tabs (Beta)**: Liquid Glass Tabs mit automatischem Scrolling
- **iOS 26 Support**: Liquid Glass Icons und Views
- **Verbesserte Modals**: Web-Modals verhalten sich jetzt wie iPad/iPhone Modals
### 3. Technische Updates
- **React Native 0.81** mit React 19.1
- **Android 16 Target**: Edge-to-Edge standardmäßig aktiviert
- **New Architecture Migration**: SDK 55 wird nur noch New Architecture unterstützen
### 4. API-Verbesserungen
- **File System API**: Neue objektorientierte API
- **SQLite localStorage**: Drop-in Ersatz für Web localStorage
- **Streaming Support**: TextDecoderStream/TextEncoderStream für AI-Integration
@ -40,14 +46,17 @@ Dieses Dokument beschreibt das Upgrade von **Expo SDK 51** (aktuell) auf **Expo
### 1. Kritische Änderungen
#### expo-av Deprecation
```diff
- import { Audio, Video } from 'expo-av';
+ import { Audio } from 'expo-audio';
+ import { Video } from 'expo-video';
```
**Wichtig**: expo-av wird in SDK 55 entfernt!
#### File System API
```diff
- import { ... } from 'expo-file-system/next';
+ import { ... } from 'expo-file-system';
@ -56,22 +65,26 @@ Dieses Dokument beschreibt das Upgrade von **Expo SDK 51** (aktuell) auf **Expo
```
#### Reanimated v4
- Nur New Architecture Support
- Für Legacy Architecture: Bei Reanimated v3 bleiben
### 2. Platform-spezifische Änderungen
#### iOS
- **Xcode Requirement**: Xcode 16.1+ (empfohlen: Xcode 26)
- **iOS Minimum**: iOS 15.1
#### Android
- **Target SDK**: Android 16
- **Edge-to-Edge**: Standardmäßig aktiviert (nicht deaktivierbar)
## 📝 Upgrade-Schritte
### Schritt 1: Backup erstellen
```bash
# Git-Status prüfen
git status
@ -87,6 +100,7 @@ git checkout -b upgrade/expo-sdk-54
### Schritt 2: Dependencies aktualisieren
#### Mobile App (apps/mobile/package.json)
```json
{
"dependencies": {
@ -127,6 +141,7 @@ git checkout -b upgrade/expo-sdk-54
```
### Schritt 3: Installation durchführen
```bash
# Cache löschen
cd apps/mobile
@ -141,6 +156,7 @@ npx expo-doctor
```
### Schritt 4: Native Directories zurücksetzen (wenn vorhanden)
```bash
# Alte native Directories löschen
rm -rf ios android
@ -152,6 +168,7 @@ npx expo prebuild --clean
### Schritt 5: Code-Anpassungen
#### 1. File System API migrieren
```typescript
// ALT (SDK 51)
import * as FileSystem from 'expo-file-system';
@ -164,12 +181,14 @@ import * as FileSystem from 'expo-file-system/legacy';
```
#### 2. Router Updates (v3 → v4)
```typescript
// Prüfe expo-router Imports und Konfiguration
// Router v4 hat verbesserte TypeScript-Unterstützung
```
#### 3. Native Tabs (Optional - Beta)
```typescript
// Neue native Tabs verwenden (Beta)
import { Tabs } from 'expo-router/unstable-native-tabs';
@ -178,6 +197,7 @@ import { Tabs } from 'expo-router/unstable-native-tabs';
```
### Schritt 6: Metro-Konfiguration prüfen
```javascript
// metro.config.js
// Entferne veraltete Overrides
@ -185,6 +205,7 @@ import { Tabs } from 'expo-router/unstable-native-tabs';
```
### Schritt 7: Tests durchführen
```bash
# Unit Tests
npm test
@ -205,24 +226,29 @@ npm run android
## 🔧 Spezifische Anpassungen für Märchenzauber
### 1. Image Generation
- Replicate Integration sollte weiterhin funktionieren
- Prüfe expo-image v2.0 Breaking Changes
### 2. Supabase Integration
- Keine direkten Änderungen erwartet
- Auth-Flow testen
### 3. Character/Story Features
- File System API für Caching anpassen
- Image Picker API prüfen
### 4. Performance-Optimierungen nutzen
- iOS Builds werden deutlich schneller
- Android Edge-to-Edge für bessere UX
## 📱 Neue Features für Märchenzauber nutzen
### Native Tabs für Story-Navigation
```typescript
import { Tabs } from 'expo-router/unstable-native-tabs';
@ -240,6 +266,7 @@ import { Tabs } from 'expo-router/unstable-native-tabs';
```
### iOS 26 Liquid Glass Icons
```json
// app.json
{
@ -252,6 +279,7 @@ import { Tabs } from 'expo-router/unstable-native-tabs';
```
### Verbesserte Modal-Präsentation
```typescript
// Web-Modals verhalten sich jetzt nativ
<Modal
@ -265,6 +293,7 @@ import { Tabs } from 'expo-router/unstable-native-tabs';
## 🐛 Troubleshooting
### Problem: Build-Fehler nach Upgrade
```bash
# Cache komplett zurücksetzen
npx expo start -c
@ -273,12 +302,14 @@ watchman watch-del-all
```
### Problem: Reanimated Fehler
```bash
# Bei Legacy Architecture bleiben
npm install react-native-reanimated@3.16.0
```
### Problem: Metro-Fehler
```javascript
// metro.config.js anpassen
// Entferne metro/src/... Imports
@ -286,6 +317,7 @@ npm install react-native-reanimated@3.16.0
```
### Problem: Type-Fehler mit React 19
```bash
# TypeScript-Definitionen aktualisieren
npm install --save-dev @types/react@~19.1.0
@ -340,4 +372,4 @@ npm install --save-dev @types/react@~19.1.0
---
**Letzte Aktualisierung**: Januar 2025
**Märchenzauber Version**: Nach Upgrade auf SDK 54
**Märchenzauber Version**: Nach Upgrade auf SDK 54

View file

@ -22,6 +22,7 @@ npx expo install @expo/ui
### Host Component
Die `Host`-Komponente ist der Container für alle Expo UI Komponenten. Sie funktioniert ähnlich wie:
- `<svg>` für DOM
- `<Canvas>` für react-native-skia
@ -30,14 +31,13 @@ Unter der Haube verwendet sie `UIHostingController` um SwiftUI Views in UIKit zu
```javascript
import { Host } from '@expo/ui/swift-ui';
<Host style={{ flex: 1 }}>
{/* Expo UI Komponenten hier */}
</Host>
<Host style={{ flex: 1 }}>{/* Expo UI Komponenten hier */}</Host>;
```
### 1-zu-1 Mapping
Expo UI bietet eine direkte Abbildung zu nativen UI-Frameworks:
- SwiftUI Views für iOS
- Jetpack Compose Components für Android
@ -45,26 +45,26 @@ Expo UI bietet eine direkte Abbildung zu nativen UI-Frameworks:
### SwiftUI Components (@expo/ui/swift-ui)
| Komponente | Beschreibung |
|------------|-------------|
| `Host` | Container für SwiftUI Komponenten |
| `Button` | Native Button mit System-Images |
| `Text` | Native Text-Komponente |
| `VStack` | Vertikales Layout |
| `ContextMenu` | Kontextmenü |
| `DateTimePicker` | Datum/Zeit-Auswahl |
| `Picker` | Segmented und Wheel-Varianten |
| `Slider` | Schieberegler |
| `Switch` | Toggle/Schalter |
| `LinearProgress` | Fortschrittsbalken |
| `BottomSheet` | Bottom Sheet Modal |
| Komponente | Beschreibung |
| ---------------- | --------------------------------- |
| `Host` | Container für SwiftUI Komponenten |
| `Button` | Native Button mit System-Images |
| `Text` | Native Text-Komponente |
| `VStack` | Vertikales Layout |
| `ContextMenu` | Kontextmenü |
| `DateTimePicker` | Datum/Zeit-Auswahl |
| `Picker` | Segmented und Wheel-Varianten |
| `Slider` | Schieberegler |
| `Switch` | Toggle/Schalter |
| `LinearProgress` | Fortschrittsbalken |
| `BottomSheet` | Bottom Sheet Modal |
### Jetpack Compose Components (@expo/ui/jetpack-compose)
| Komponente | Beschreibung |
|------------|-------------|
| `TextInput` | Native Texteingabe |
| `Button` | Native Android Button |
| Komponente | Beschreibung |
| ---------------------------------- | --------------------- |
| `TextInput` | Native Texteingabe |
| `Button` | Native Android Button |
| Weitere Komponenten in Entwicklung |
## Code-Beispiele
@ -75,16 +75,14 @@ Expo UI bietet eine direkte Abbildung zu nativen UI-Frameworks:
import { Host, VStack, Text, Button } from '@expo/ui/swift-ui';
function MyComponent() {
return (
<Host style={{ flex: 1 }}>
<VStack spacing={8}>
<Text>Willkommen bei Expo UI!</Text>
<Button onPress={() => console.log('Geklickt!')}>
Klick mich
</Button>
</VStack>
</Host>
);
return (
<Host style={{ flex: 1 }}>
<VStack spacing={8}>
<Text>Willkommen bei Expo UI!</Text>
<Button onPress={() => console.log('Geklickt!')}>Klick mich</Button>
</VStack>
</Host>
);
}
```
@ -96,19 +94,16 @@ import { useState } from 'react';
import { useWindowDimensions } from 'react-native';
function BottomSheetExample() {
const [isOpened, setIsOpened] = useState(false);
const { width } = useWindowDimensions();
const [isOpened, setIsOpened] = useState(false);
const { width } = useWindowDimensions();
return (
<Host style={{ position: 'absolute', width }}>
<BottomSheet
isOpened={isOpened}
onIsOpenedChange={e => setIsOpened(e)}
>
<Text>Sheet-Inhalt hier</Text>
</BottomSheet>
</Host>
);
return (
<Host style={{ position: 'absolute', width }}>
<BottomSheet isOpened={isOpened} onIsOpenedChange={(e) => setIsOpened(e)}>
<Text>Sheet-Inhalt hier</Text>
</BottomSheet>
</Host>
);
}
```
@ -118,15 +113,9 @@ function BottomSheetExample() {
import { TextInput } from '@expo/ui/jetpack-compose';
function AndroidInput() {
const [value, setValue] = useState('');
const [value, setValue] = useState('');
return (
<TextInput
autocorrection={false}
defaultValue="Standardtext"
onChangeText={setValue}
/>
);
return <TextInput autocorrection={false} defaultValue="Standardtext" onChangeText={setValue} />;
}
```
@ -141,16 +130,16 @@ import { Host, VStack } from '@expo/ui/swift-ui';
import { View, Text as RNText } from 'react-native';
function MixedComponent() {
return (
<Host style={{ flex: 1 }}>
<VStack>
{/* React Native Komponente innerhalb von Expo UI */}
<View>
<RNText>React Native Text</RNText>
</View>
</VStack>
</Host>
);
return (
<Host style={{ flex: 1 }}>
<VStack>
{/* React Native Komponente innerhalb von Expo UI */}
<View>
<RNText>React Native Text</RNText>
</View>
</VStack>
</Host>
);
}
```
@ -159,21 +148,25 @@ Expo UI erstellt automatisch einen `UIViewRepresentable` Wrapper für React Nati
## Vorteile von Expo UI
### 1. Native Performance
- Direkte Nutzung von SwiftUI und Jetpack Compose
- Keine Bridge-Overhead für UI-Updates
- Optimierte native Animationen und Transitions
### 2. Moderne UI-Patterns
- Zugriff auf die neuesten nativen UI-Features
- System-konsistentes Design out-of-the-box
- Native Gesten und Interaktionen
### 3. Flexibilität
- Full-App Support: Gesamte App in Expo UI schreibbar
- Component-Level Mixing: Mische React Native, Expo UI, DOM und Custom 2D Components
- Schrittweise Migration möglich
### 4. Developer Experience
- TypeScript Support mit vollständigen Typen
- Hot Reload Support
- Vertraute React-Patterns
@ -200,13 +193,11 @@ Expo UI erstellt automatisch einen `UIViewRepresentable` Wrapper für React Nati
```javascript
// Separiere native UI in eigene Komponenten
function NativeSheet({ children }) {
return (
<Host style={{ flex: 1 }}>
<BottomSheet>
{children}
</BottomSheet>
</Host>
);
return (
<Host style={{ flex: 1 }}>
<BottomSheet>{children}</BottomSheet>
</Host>
);
}
```
@ -216,8 +207,8 @@ function NativeSheet({ children }) {
import { Platform } from 'react-native';
const NativeButton = Platform.select({
ios: require('@expo/ui/swift-ui').Button,
android: require('@expo/ui/jetpack-compose').Button,
ios: require('@expo/ui/swift-ui').Button,
android: require('@expo/ui/jetpack-compose').Button,
});
```
@ -227,7 +218,7 @@ const NativeButton = Platform.select({
import type { ButtonProps } from '@expo/ui/swift-ui';
interface MyButtonProps extends ButtonProps {
variant?: 'primary' | 'secondary';
variant?: 'primary' | 'secondary';
}
```
@ -257,15 +248,15 @@ interface MyButtonProps extends ButtonProps {
import { TouchableOpacity, Text } from 'react-native';
<TouchableOpacity onPress={handlePress}>
<Text>Click me</Text>
</TouchableOpacity>
<Text>Click me</Text>
</TouchableOpacity>;
// Nachher (Expo UI)
import { Host, Button } from '@expo/ui/swift-ui';
<Host>
<Button onPress={handlePress}>Click me</Button>
</Host>
<Button onPress={handlePress}>Click me</Button>
</Host>;
```
## Troubleshooting
@ -273,26 +264,32 @@ import { Host, Button } from '@expo/ui/swift-ui';
### Häufige Probleme
**Problem**: Components werden nicht angezeigt
- **Lösung**: Stelle sicher, dass Components in einem `Host` gewrappt sind
**Problem**: Build-Fehler mit Expo Go
- **Lösung**: Verwende Development Build: `npx expo run:ios` oder `npx expo run:android`
**Problem**: TypeScript-Fehler
- **Lösung**: Update auf neueste @expo/ui Version
## Ressourcen
### Offizielle Dokumentation
- [Expo UI Docs](https://docs.expo.dev/versions/latest/sdk/ui/)
- [SwiftUI Guide](https://docs.expo.dev/guides/expo-ui-swift-ui/)
- [GitHub Repository](https://github.com/expo/expo/tree/main/packages/expo-ui)
### Community
- [Expo Discord](https://discord.gg/expo)
- [GitHub Discussions](https://github.com/expo/expo/discussions)
### Beispiel-Projekte
- [Liquid Glass App](https://expo.dev/blog/liquid-glass-app-with-expo-ui-and-swiftui)
- [Live Activity Example](https://christopher.engineering/en/blog/live-activity-with-react-native/)
@ -301,7 +298,8 @@ import { Host, Button } from '@expo/ui/swift-ui';
Expo UI repräsentiert einen innovativen Ansatz für React Native Development, der die Grenzen zwischen React Native und nativen UI-Frameworks verschwimmen lässt. Während es sich noch in der Alpha-Phase befindet, zeigt es bereits das Potenzial für die Zukunft der mobilen App-Entwicklung mit React Native.
Für das Märchenzauber-Projekt könnte Expo UI besonders interessant sein für:
- Native Picker-Komponenten für Sprachauswahl
- BottomSheets für Story-Optionen
- Native Animationen für magische Übergänge
- System-konsistente UI-Elemente
- System-konsistente UI-Elemente