chore: archive inactive projects to apps-archived/

Move inactive projects out of active workspace:
- bauntown (community website)
- maerchenzauber (AI story generation)
- memoro (voice memo app)
- news (news aggregation)
- nutriphi (nutrition tracking)
- reader (reading app)
- uload (URL shortener)
- wisekeep (AI wisdom extraction)

Update CLAUDE.md documentation:
- Add presi to active projects
- Document archived projects section
- Update workspace configuration

Archived apps can be re-activated by moving back to apps/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-11-29 07:03:59 +01:00
parent b97149ac12
commit 61d181fbc2
3148 changed files with 437 additions and 46640 deletions

View file

@ -0,0 +1,78 @@
⏺ AudioPlayer Verbesserungsplan
1. Geschwindigkeitssteuerung
- Playback-Speed Kontrolle
(0.5x, 0.75x, 1x, 1.25x, 1.5x,
2x)
- Geschwindigkeit bleibt für
alle Audios gespeichert
- Kleiner Button neben den
Controls
2. Visuelle Verbesserungen
- Waveform-Visualisierung
während der Wiedergabe
- Bessere Progress-Bar mit
Touch-Gesten zum Scrubben
- Pulsierender Play-Button
während des Ladens
3. Erweiterte Navigation
- Kapitel-Support (bei
längeren Texten)
- Lesezeichen setzen während
der Wiedergabe
- Zu bestimmten Zeitstempeln
springen
4. Sleep Timer
- Timer zum automatischen
Stoppen (15, 30, 45, 60 Min)
- Fade-Out am Ende
- Visual Countdown
5. Kontinuierliche Wiedergabe
- Automatisch nächsten Text
abspielen
- Queue-System für mehrere
Texte
- Shuffle-Modus
6. Mini-Player
- Kompakter Player am unteren
Bildschirmrand
- Bleibt beim Navigieren
sichtbar
- Swipe-to-dismiss
7. Offline-Optimierung
- Download-Button für lokale
Speicherung
- Download-Progress anzeigen
- Cache-Management UI
8. Statistiken & History
- Listening History anzeigen
- Fortschritt pro Text tracken
- Gesamte Hörzeit
9. Accessibility
- VoiceOver Support verbessern
- Größere Touch-Targets
- Keyboard-Shortcuts (iPad)
10. Performance
- Preloading des nächsten
Chunks
- Smooth Chunk-Übergänge
- Background Audio optimieren

View file

@ -0,0 +1,226 @@
Expo UI
A set of components that allow you to build UIs directly with SwiftUI and Jetpack Compose from React.
Bundled version:
~0.1.1-alpha.10
This library is currently in alpha and will frequently experience breaking changes. It is not available in the Expo Go app use development builds to try it out.
@expo/ui is a set of native input components that allows you to build fully native interfaces with SwiftUI and Jetpack Compose. It aims to provide the commonly used features and components that a typical app will need.
Installation
Terminal
Copy
npx expo install @expo/ui
If you are installing this in an existing React Native app, make sure to install expo in your project.
Swift UI examples
BottomSheet
iOS
Code
BottomSheet component on iOS.
Button
iOS
Code
Button component on iOS.
CircularProgress
iOS
Code
CircularProgress component on iOS.
ColorPicker
iOS
Code
ColorPicker component on iOS.
ContextMenu
Note: Also known as DropdownMenu.
iOS
Code
ContextMenu component on iOS.
DateTimePicker (date)
iOS
Code
DateTimePicker (date) component on iOS.
DateTimePicker (time)
iOS
Code
DateTimePicker (time) component on iOS.
Gauge
iOS
Code
Gauge component on iOS.
LinearProgress
iOS
Code
LinearProgress component on iOS.
List
iOS
Code
List component on iOS.
Picker (segmented)
iOS
Code
Picker component on iOS.
Picker (wheel)
iOS
Code
Picker component on iOS.
Slider
iOS
Code
Slider component on iOS.
Switch (toggle)
Note: Also known as Toggle.
iOS
Code
Switch component on iOS.
Switch (checkbox)
iOS
Code
Picker component on iOS.
TextInput
iOS
Code
TextInput component on iOS.
Jetpack Compose examples
Button
Android
Code
Button component on Android.
CircularProgress
Android
Code
CircularProgress component on Android.
ContextMenu
Note: Also known as DropdownMenu.
Android
Code
ContextMenu component on Android.
DateTimePicker (date)
Android
Code
DateTimePicker component on Android.
DateTimePicker (time)
Android
Code
DateTimePicker (time) component on Android.
LinearProgress
Android
Code
LinearProgress component on Android.
Picker (radio)
Android
Code
Picker component (radio) on Android.
Picker (segmented)
Android
Code
Picker component on Android.
Slider
Android
Code
Slider component on Android.
Switch (toggle)
Note: Also known as Toggle.
Android
Code
Switch component on Android.
Switch (checkbox)
Android
Code
Switch (checkbox variant) component on Android.
TextInput
Android
Code
TextInput component on Android.
API
Full documentation is not yet available. Use TypeScript types to explore the API.
// Import from the SwiftUI package
import { BottomSheet } from '@expo/ui/swift-ui';
// Import from the Jetpack Compose package
import { Button } from '@expo/ui/jetpack-compose';

View file

@ -0,0 +1,570 @@
# Absolut Minimalste Text-to-Speech Datenbank
## Philosophie
Eine einzige Tabelle für alles. JSONB macht's möglich. Keine Joins, keine Komplexität, nur pure Funktionalität.
## Die Eine Tabelle
```sql
-- Die einzige Tabelle die du brauchst
CREATE TABLE texts (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
-- Der eigentliche Content
title TEXT NOT NULL,
content TEXT NOT NULL,
-- ALLES andere in einem JSONB Feld
data JSONB DEFAULT '{}' NOT NULL,
-- Nur die absolut nötigen Timestamps
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Ein Index für Performance
CREATE INDEX idx_texts_user ON texts(user_id);
CREATE INDEX idx_texts_data ON texts USING GIN (data);
-- RLS aktivieren
ALTER TABLE texts ENABLE ROW LEVEL SECURITY;
-- Jeder sieht nur seine eigenen Texte
CREATE POLICY "Own texts only" ON texts
FOR ALL USING (auth.uid() = user_id);
-- Update Timestamp Trigger
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_texts_updated_at
BEFORE UPDATE ON texts
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();
```
## Was kommt ins `data` JSONB Feld?
```javascript
// Beispiel eines vollständigen Text-Objekts
{
id: "uuid-hier",
user_id: "user-uuid",
title: "Mein Buch",
content: "Der eigentliche Text...",
data: {
// Vorlese-Einstellungen
tts: {
speed: 1.0,
voice: "de-DE",
lastPosition: 1234, // Zeichen-Position
lastPlayed: "2024-01-15T10:30:00Z"
},
// Audio-Cache (NEU!)
audio: {
hasLocalCache: false,
chunks: [
{
id: "chunk-1",
start: 0,
end: 1000, // Zeichen-Position
filename: "text-uuid-chunk-1.mp3",
size: 245760, // Bytes
duration: 120, // Sekunden
createdAt: "2024-01-15T10:00:00Z"
}
],
totalSize: 2457600, // Total in Bytes
lastGenerated: "2024-01-15T10:00:00Z",
settings: { // Settings bei Generierung
voice: "de-DE",
speed: 1.0
}
},
// Organisation (optional)
tags: ["roman", "favorit"],
color: "#FF5733",
// Statistiken (optional)
stats: {
playCount: 5,
totalTime: 3600, // Sekunden
completed: false
},
// Was auch immer du später brauchst
notes: "Für die Zugfahrt",
source: "kindle-import"
},
created_at: "2024-01-01T10:00:00Z",
updated_at: "2024-01-15T10:30:00Z"
}
```
## Basis-Operationen
### Text erstellen
```javascript
const { data, error } = await supabase
.from('texts')
.insert({
title: 'Mein Text',
content: 'Inhalt hier...',
data: {
tts: { speed: 1.0, voice: 'de-DE' },
tags: ['neu']
}
});
```
### Alle Texte holen
```javascript
const { data: texts } = await supabase
.from('texts')
.select('*')
.order('updated_at', { ascending: false });
```
### Nach Tags filtern
```javascript
const { data: filtered } = await supabase
.from('texts')
.select('*')
.contains('data', { tags: ['favorit'] });
```
### Leseposition updaten
```javascript
const { error } = await supabase
.from('texts')
.update({
data: {
...currentData,
tts: {
...currentData.tts,
lastPosition: 5678,
lastPlayed: new Date().toISOString()
}
}
})
.eq('id', textId);
```
### Statistiken hochzählen
```sql
-- Als Postgres Funktion für atomare Updates
CREATE OR REPLACE FUNCTION increment_play_count(text_id UUID)
RETURNS void AS $$
BEGIN
UPDATE texts
SET data = jsonb_set(
jsonb_set(
data,
'{stats,playCount}',
to_jsonb(COALESCE((data->'stats'->>'playCount')::int, 0) + 1)
),
'{tts,lastPlayed}',
to_jsonb(NOW())
)
WHERE id = text_id;
END;
$$ LANGUAGE plpgsql;
-- Aufruf
SELECT increment_play_count('text-uuid-hier');
```
## Supabase Quickstart
```bash
# 1. Supabase CLI installieren
npm install -g supabase
# 2. Projekt initialisieren
supabase init
# 3. Migration erstellen
supabase migration new create_texts_table
# 4. SQL von oben in die Migration kopieren
# 5. Migration ausführen
supabase db push
```
## React Native Integration
```javascript
// hooks/useTexts.js
import { useState, useEffect } from 'react';
import { supabase } from '../lib/supabase';
export const useTexts = () => {
const [texts, setTexts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchTexts();
}, []);
const fetchTexts = async () => {
const { data } = await supabase
.from('texts')
.select('*')
.order('updated_at', { ascending: false });
setTexts(data || []);
setLoading(false);
};
const createText = async (title, content) => {
const { data, error } = await supabase
.from('texts')
.insert({
title,
content,
data: { tts: { speed: 1.0, voice: 'de-DE' } }
})
.select()
.single();
if (data) {
setTexts([data, ...texts]);
}
return { data, error };
};
const updatePosition = async (textId, position) => {
const text = texts.find(t => t.id === textId);
if (!text) return;
await supabase
.from('texts')
.update({
data: {
...text.data,
tts: {
...text.data.tts,
lastPosition: position,
lastPlayed: new Date().toISOString()
}
}
})
.eq('id', textId);
};
return { texts, loading, createText, updatePosition, refetch: fetchTexts };
};
```
## Audio-Cache Management
```javascript
// hooks/useAudioCache.js
import * as FileSystem from 'expo-file-system';
import * as Speech from 'expo-speech';
import { Audio } from 'expo-av';
import { supabase } from '../lib/supabase';
const AUDIO_DIR = `${FileSystem.documentDirectory}audio/`;
export const useAudioCache = () => {
// Verzeichnis erstellen beim Start
useEffect(() => {
FileSystem.makeDirectoryAsync(AUDIO_DIR, { intermediates: true })
.catch(() => {}); // Ignorieren wenn bereits existiert
}, []);
// Text in Chunks aufteilen (z.B. alle 1000 Zeichen)
const chunkText = (text, chunkSize = 1000) => {
const chunks = [];
for (let i = 0; i < text.length; i += chunkSize) {
chunks.push({
id: `chunk-${chunks.length}`,
start: i,
end: Math.min(i + chunkSize, text.length),
content: text.slice(i, i + chunkSize)
});
}
return chunks;
};
// Audio für einen Chunk generieren und speichern
const generateAudioChunk = async (textId, chunk, settings) => {
const filename = `${textId}-${chunk.id}.mp3`;
const filePath = `${AUDIO_DIR}${filename}`;
// Option 1: Mit einer TTS API (z.B. Google Cloud TTS)
// const audioData = await callTTSAPI(chunk.content, settings);
// await FileSystem.writeAsStringAsync(filePath, audioData, {
// encoding: FileSystem.EncodingType.Base64
// });
// Option 2: Workaround mit expo-speech (keine direkte MP3 Generierung)
// Hinweis: expo-speech kann nicht direkt als Datei speichern
// Alternative: Web-API oder Cloud-Service nutzen
const fileInfo = await FileSystem.getInfoAsync(filePath);
return {
id: chunk.id,
start: chunk.start,
end: chunk.end,
filename,
size: fileInfo.size || 0,
duration: Math.ceil(chunk.content.length / 150) * 60, // Geschätzt
createdAt: new Date().toISOString()
};
};
// Alle Chunks für einen Text generieren
const generateAudioForText = async (textId, content, settings = {}) => {
const chunks = chunkText(content);
const audioChunks = [];
for (const chunk of chunks) {
const audioChunk = await generateAudioChunk(textId, chunk, settings);
audioChunks.push(audioChunk);
}
// Metadaten in Supabase updaten
await updateAudioMetadata(textId, audioChunks, settings);
return audioChunks;
};
// Audio-Metadaten in Supabase speichern
const updateAudioMetadata = async (textId, chunks, settings) => {
const totalSize = chunks.reduce((sum, chunk) => sum + chunk.size, 0);
const { data: currentText } = await supabase
.from('texts')
.select('data')
.eq('id', textId)
.single();
await supabase
.from('texts')
.update({
data: {
...currentText.data,
audio: {
hasLocalCache: true,
chunks,
totalSize,
lastGenerated: new Date().toISOString(),
settings
}
}
})
.eq('id', textId);
};
// Audio abspielen
const playAudioFromCache = async (textId, startPosition = 0) => {
const { data: text } = await supabase
.from('texts')
.select('data')
.eq('id', textId)
.single();
if (!text?.data?.audio?.hasLocalCache) {
throw new Error('Kein Audio-Cache vorhanden');
}
// Richtigen Chunk finden
const chunk = text.data.audio.chunks.find(
c => startPosition >= c.start && startPosition < c.end
);
if (!chunk) return;
const filePath = `${AUDIO_DIR}${chunk.filename}`;
const { sound } = await Audio.Sound.createAsync({ uri: filePath });
// Position innerhalb des Chunks berechnen
const chunkPosition = startPosition - chunk.start;
const positionMillis = (chunkPosition / chunk.end) * chunk.duration * 1000;
await sound.setPositionAsync(positionMillis);
await sound.playAsync();
return sound;
};
// Cache löschen
const clearAudioCache = async (textId) => {
const { data: text } = await supabase
.from('texts')
.select('data')
.eq('id', textId)
.single();
if (text?.data?.audio?.chunks) {
for (const chunk of text.data.audio.chunks) {
try {
await FileSystem.deleteAsync(`${AUDIO_DIR}${chunk.filename}`);
} catch (e) {
console.log('Fehler beim Löschen:', e);
}
}
}
// Metadaten updaten
await supabase
.from('texts')
.update({
data: {
...text.data,
audio: {
hasLocalCache: false,
chunks: [],
totalSize: 0
}
}
})
.eq('id', textId);
};
// Cache-Größe berechnen
const getCacheSize = async () => {
const files = await FileSystem.readDirectoryAsync(AUDIO_DIR);
let totalSize = 0;
for (const file of files) {
const info = await FileSystem.getInfoAsync(`${AUDIO_DIR}${file}`);
totalSize += info.size || 0;
}
return totalSize;
};
return {
generateAudioForText,
playAudioFromCache,
clearAudioCache,
getCacheSize
};
};
```
## Beispiel-Screen für Audio-Management
```javascript
// screens/TextDetailScreen.js
import React, { useState } from 'react';
import { View, Text, Button, ActivityIndicator } from 'react-native';
import { useAudioCache } from '../hooks/useAudioCache';
export const TextDetailScreen = ({ route }) => {
const { text } = route.params;
const { generateAudioForText, playAudioFromCache, clearAudioCache } = useAudioCache();
const [generating, setGenerating] = useState(false);
const hasCache = text.data?.audio?.hasLocalCache;
const handleGenerateAudio = async () => {
setGenerating(true);
try {
await generateAudioForText(text.id, text.content, {
voice: text.data?.tts?.voice || 'de-DE',
speed: text.data?.tts?.speed || 1.0
});
// Text-Objekt neu laden
} catch (error) {
console.error('Fehler beim Generieren:', error);
} finally {
setGenerating(false);
}
};
const handlePlay = async () => {
try {
const position = text.data?.tts?.lastPosition || 0;
await playAudioFromCache(text.id, position);
} catch (error) {
// Fallback zu expo-speech
Speech.speak(text.content.slice(position), {
language: text.data?.tts?.voice || 'de-DE',
rate: text.data?.tts?.speed || 1.0
});
}
};
return (
<View>
<Text>{text.title}</Text>
{!hasCache && (
<Button
title="Audio generieren & speichern"
onPress={handleGenerateAudio}
disabled={generating}
/>
)}
{generating && <ActivityIndicator />}
{hasCache && (
<>
<Text>
Audio gespeichert: {(text.data.audio.totalSize / 1024 / 1024).toFixed(2)} MB
</Text>
<Button title="Offline abspielen" onPress={handlePlay} />
<Button title="Cache löschen" onPress={() => clearAudioCache(text.id)} />
</>
)}
</View>
);
};
```
## Vorteile dieser Struktur
**Eine Tabelle** = Keine Joins, keine Komplexität
**JSONB** = Unendlich erweiterbar ohne Migrations
**Performance** = PostgreSQL's JSONB ist super schnell
**Einfach** = Jeder versteht es sofort
**Flexibel** = Neue Features sind nur ein JSON-Feld entfernt
## Erweiterungsbeispiele
```javascript
// Später: Lesezeichen hinzufügen
data.bookmarks = [
{ position: 1234, note: "Wichtige Stelle", created: "2024-01-15" }
];
// Später: Sharing hinzufügen
data.sharing = {
isPublic: false,
shareToken: "abc123",
sharedWith: ["email@example.com"]
};
// Später: AI-Features
data.ai = {
summary: "KI-generierte Zusammenfassung",
keywords: ["Thema1", "Thema2"],
difficulty: "medium"
};
```
## Das war's! 🎉
Mit dieser einen Tabelle kannst du:
- Texte speichern ✓
- Vorlesen mit gespeicherter Position ✓
- Tags/Kategorien verwalten ✓
- Statistiken tracken ✓
- Beliebig erweitern ✓
Keine zweite Tabelle nötig. Kein Over-Engineering. Einfach machen.

View file

@ -0,0 +1,217 @@
# Reader - Projektübersicht
## Was ist Reader?
Reader ist eine moderne Text-to-Speech App, die Texte mit hochqualitativen KI-Stimmen vorliest und für die Offline-Nutzung speichert. Die App kombiniert die neuesten Google Chirp Stimmen mit einer eleganten Benutzeroberfläche und intelligenter Audio-Verwaltung.
## Kernfunktionen
### 📚 Text-Management
- **Import**: Texte manuell eingeben oder aus Dateien importieren
- **Organisation**: Einfache Tag-basierte Verwaltung
- **Synchronisation**: Automatischer Sync zwischen Geräten via Supabase
- **Lesefortschritt**: Merkt sich wo du aufgehört hast
### 🎧 Premium Audio-Wiedergabe
- **Google Chirp Stimmen**: Natürlich klingende KI-Stimmen in Studio-Qualität
- **Offline-Verfügbarkeit**: Einmal generiert, immer verfügbar
- **Anpassbar**: Geschwindigkeit und Tonhöhe individuell einstellbar
- **Nahtlose Wiedergabe**: Intelligentes Chunk-System für unterbrechungsfreies Hören
### 💾 Smart Caching
- **Automatische Segmentierung**: Lange Texte werden intelligent aufgeteilt
- **Progressives Laden**: Chunks werden bei Bedarf geladen
- **Speicherverwaltung**: Übersicht über genutzten Speicherplatz
- **Selective Sync**: Wähle welche Texte offline verfügbar sein sollen
### 👤 Benutzerfreundlichkeit
- **Ein-Klick-Generierung**: Audio für komplette Texte erstellen
- **Hintergrund-Wiedergabe**: Weiterhören während andere Apps genutzt werden
- **Sleep Timer**: Automatisches Stoppen nach eingestellter Zeit
- **Lesezeichen**: Wichtige Stellen markieren
## Technische Architektur
### Frontend: React Native mit Expo
- **Plattformen**: iOS und Android aus einer Codebasis
- **UI Framework**: Native Komponenten für beste Performance
- **Offline-First**: Funktioniert auch ohne Internetverbindung
- **State Management**: React Context für einfache Datenverwaltung
### Backend: Supabase
- **Datenbank**: PostgreSQL mit einer minimalistischen Tabelle
- **Authentifizierung**: Sichere Benutzerkonten out-of-the-box
- **Realtime Sync**: Änderungen werden sofort synchronisiert
- **Edge Functions**: Serverless Audio-Generierung
### Audio-Pipeline: Google Cloud TTS
- **Chirp Voices**: Neueste Generation von Google's Text-to-Speech
- **Studio-Qualität**: Broadcast-taugliche Sprachausgabe
- **Mehrsprachig**: Unterstützung für 40+ Sprachen
- **Neural Synthesis**: KI-basierte Sprachgenerierung
## Projektkonzept für Google Chirp Integration
### Phase 1: Infrastruktur-Setup
**Ziel**: Grundlegende Verbindungen zwischen allen Systemen herstellen
**Google Cloud Konfiguration**:
- Google Cloud Projekt erstellen und Text-to-Speech API aktivieren
- Service Account für sichere API-Zugriffe einrichten
- Zugriffsschlüssel generieren und sicher speichern
- Kostenkontrolle durch Quotas und Budgets einrichten
**Supabase Edge Functions Setup**:
- Zwei Hauptfunktionen: Audio-Generierung und Batch-Processing
- Sichere Speicherung der Google Cloud Credentials
- CORS-Konfiguration für App-Zugriffe
- Error Handling und Logging-Strategie
### Phase 2: Audio-Generierungs-Pipeline
**Ziel**: Robuste und skalierbare Audio-Erstellung
**Text-Segmentierung**:
- Intelligente Aufteilung an Satzgrenzen
- Optimale Chunk-Größe für Balance zwischen Qualität und Performance
- Metadaten für nahtlose Wiedergabe speichern
**Batch-Processing**:
- Parallele Verarbeitung mit Rate Limiting
- Fortschrittsanzeige für Benutzer
- Fehlerbehandlung für einzelne Chunks
- Automatische Wiederholung bei Fehlern
**Storage-Strategie**:
- Supabase Storage für zentrale Audio-Dateien
- Signierte URLs mit Ablaufzeit
- Lokaler Cache auf Geräten
- Intelligente Garbage Collection
### Phase 3: App-Integration
**Ziel**: Nahtlose Benutzererfahrung
**Audio-Service Layer**:
- Abstraktion der Komplexität
- Queue-Management für Wiedergabe
- Prefetching für unterbrechungsfreies Hören
- Fallback-Mechanismen
**UI/UX Konzepte**:
- Ein-Tap Audio-Generierung
- Visuelles Feedback während Processing
- Download-Progress für Offline-Sync
- Intuitive Playback-Controls
### Phase 4: Optimierung & Skalierung
**Ziel**: Production-ready System
**Performance**:
- CDN-Integration für schnelle Downloads
- Chunk-Größen-Optimierung
- Parallele Downloads
- Background Processing
**Kosten-Optimierung**:
- Caching bereits generierter Audios
- Deduplizierung gleicher Textpassagen
- Nutzungsbasierte Limits
- Premium-Tier für Heavy Users
**Monitoring**:
- Verwendungsstatistiken
- Error Tracking
- Performance Metriken
- Kosten-Überwachung
## Alleinstellungsmerkmale
### 🎯 Was Reader besonders macht:
1. **Höchste Audioqualität**: Google Chirp Stimmen klingen natürlicher als Standard TTS
2. **True Offline**: Einmal generiert, für immer verfügbar - kein Streaming nötig
3. **Minimalistisches Design**: Fokus auf das Wesentliche ohne überflüssige Features
4. **Privacy-First**: Deine Texte bleiben deine Texte
5. **Fair Pricing**: Einmalige Generierung statt ständige Streaming-Kosten
## Monetarisierung
### Freemium Modell:
- **Free Tier**: 10.000 Zeichen/Monat
- **Pro**: 500.000 Zeichen/Monat + Premium Stimmen
- **Team**: Unbegrenzt + Collaboration Features
### Kostenstruktur:
- Google TTS: ~$16 per 1 Million Zeichen (Chirp Voices)
- Supabase: $25/Monat für Pro Features
- Storage: $0.021 per GB/Monat
## Zeitplan
**Woche 1-2**: Setup & Basis-Integration
- Google Cloud und Supabase konfigurieren
- Edge Functions entwickeln
- Basis-App mit Authentifizierung
**Woche 3-4**: Audio-Pipeline
- Chunk-System implementieren
- Storage-Integration
- Playback-Funktionalität
**Woche 5-6**: Polish & Launch
- UI/UX Verfeinerung
- Testing & Bugfixing
- App Store Vorbereitung
## Erfolgsmetriken
- **Nutzer-Aktivierung**: 80% generieren ersten Audio innerhalb 5 Minuten
- **Retention**: 40% Daily Active Users
- **Audio-Qualität**: <2% Neu-Generierungen wegen Qualität
- **Performance**: <3 Sekunden für Start der Wiedergabe
- **Conversion**: 5% Free-to-Pro nach 30 Tagen
## Risiken & Mitigationen
**API-Kosten**:
- Monitoring und Alerts
- Caching-Strategien
- User Limits
**Technische Komplexität**:
- Schrittweise Integration
- Ausführliches Testing
- Fallback-Optionen
**Skalierung**:
- Edge Function Limits beachten
- CDN frühzeitig einplanen
- Horizontale Skalierung vorbereiten