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,126 @@
# Browser Extension für URL-Extraktion
## Konzept
Eine Browser Extension kann direkt auf den gerenderten Content zugreifen, nachdem der Nutzer Cookies akzeptiert hat.
## Implementation (Chrome/Safari)
### Manifest.json
```json
{
"manifest_version": 3,
"name": "Reader App Extractor",
"permissions": ["activeTab", "clipboardWrite"],
"action": {
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
```
### Content Script
```javascript
// content.js
function extractArticle() {
// Nutze Readability direkt im Browser
const documentClone = document.cloneNode(true);
const reader = new Readability(documentClone);
const article = reader.parse();
if (article) {
// Sende an Reader App
const readerUrl = `reader-app://add?title=${encodeURIComponent(article.title)}&content=${encodeURIComponent(article.content)}`;
window.location.href = readerUrl;
}
}
```
### Integration in React Native
```typescript
// Deep Link Handler
import { Linking } from 'react-native';
Linking.addEventListener('url', (event) => {
const url = new URL(event.url);
if (url.protocol === 'reader-app:' && url.pathname === 'add') {
const title = url.searchParams.get('title');
const content = url.searchParams.get('content');
// Erstelle neuen Text
}
});
```
## iOS Share Extension Alternative
### Info.plist
```xml
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<string>SUBQUERY(extensionItems, $e, SUBQUERY($e.attachments, $a, $a.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url").@count > 0).@count > 0</string>
</dict>
</dict>
```
### Share Extension Code
```swift
import MobileCoreServices
class ShareViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let item = extensionContext?.inputItems.first as? NSExtensionItem,
let provider = item.attachments?.first {
if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
provider.loadItem(forTypeIdentifier: kUTTypeURL as String) { (url, error) in
if let shareURL = url as? URL {
// Extrahiere Content mit WKWebView
self.extractContent(from: shareURL)
}
}
}
}
}
func extractContent(from url: URL) {
let webView = WKWebView()
webView.load(URLRequest(url: url))
// Nach dem Laden JavaScript ausführen
webView.evaluateJavaScript("document.body.innerText") { (result, error) in
if let text = result as? String {
// Speichere in App Group oder sende an App
self.saveToApp(title: url.host ?? "Artikel", content: text, url: url.absoluteString)
}
}
}
}
```
## Vorteile
1. Umgeht alle Cookie-Banner (Nutzer akzeptiert im Browser)
2. Zugriff auf den vollständig gerenderten Content
3. Native Integration in iOS/Android Share-Menü
4. Kein Server-Side Rendering nötig
## Nachteile
1. Zusätzliche Installation erforderlich
2. Platform-spezifische Entwicklung
3. App Store Review Process für Extensions

View file

@ -0,0 +1,300 @@
# Reader App - Deployment Guide
## Voraussetzungen
1. **Google Cloud Account** mit aktivierter Text-to-Speech API
2. **Supabase Projekt** mit konfigurierter Datenbank
3. **Expo Developer Account** (für App Store Deployment)
## 1. Google Cloud Setup
### API Key erstellen
1. Google Cloud Console → "APIs & Services" → "Credentials"
2. "Create Credentials" → "API Key"
3. API Key auf Text-to-Speech API beschränken
### Stimmen konfigurieren
Die App verwendet Google Neural2 Stimmen:
- `de-DE-Neural2-A` (Deutsch, weiblich)
- `en-US-Neural2-A` (Englisch US, männlich)
- `en-GB-Neural2-A` (Englisch UK, weiblich)
## 2. Supabase Setup
### Datenbank Migrationen
```bash
# Migrations ausführen
supabase migration up
# Oder manuell in SQL Editor:
# - supabase/migrations/20240116_create_texts_table.sql
# - supabase/migrations/20240117_create_audio_storage.sql
```
### Environment Variables
In Supabase Dashboard → Settings → Edge Functions:
```
GOOGLE_TTS_API_KEY=your_google_api_key_here
```
### Edge Functions deployen
```bash
# Supabase CLI installieren
npm install -g supabase
# Edge Functions deployen
supabase functions deploy generate-audio
supabase functions deploy get-audio-url
```
### Storage Setup
- Bucket "audio" wird automatisch erstellt
- RLS Policies sind konfiguriert
- Benutzer können nur ihre eigenen Audio-Dateien zugreifen
## 3. React Native App Setup
### Environment Variables
Erstelle `.env.local`:
```
EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
```
### Dependencies installieren
```bash
npm install
```
### App konfigurieren
In `app.json`:
```json
{
"expo": {
"name": "Reader",
"slug": "reader",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.tilljs.reader"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
}
}
}
```
## 4. Development Testing
### Lokal testen
```bash
# Development Server starten
npm start
# iOS Simulator
npm run ios
# Android Emulator
npm run android
```
### Edge Functions testen
```bash
# Lokal
supabase functions serve
# Test Audio Generation
curl -X POST 'http://localhost:54321/functions/v1/generate-audio' \
-H 'Authorization: Bearer YOUR_SUPABASE_JWT' \
-H 'Content-Type: application/json' \
-d '{
"textId": "test-id",
"content": "Dies ist ein Test für die Audio-Generierung.",
"voice": "de-DE",
"speed": 1.0
}'
```
## 5. Production Deployment
### EAS Build Setup
```bash
# EAS CLI installieren
npm install -g @expo/eas-cli
# EAS initialisieren
eas init
# Build konfigurieren
eas build:configure
```
### Build Profile (`eas.json`)
```json
{
"cli": {
"version": ">= 0.52.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {}
},
"submit": {
"production": {}
}
}
```
### Builds erstellen
```bash
# Development Build
eas build --profile development
# Production Build
eas build --profile production
```
### App Store Submission
```bash
# iOS App Store
eas submit --platform ios
# Google Play Store
eas submit --platform android
```
## 6. Monitoring & Maintenance
### Supabase Dashboard
- Database Performance
- Storage Usage
- Edge Function Logs
- User Activity
### Google Cloud Monitoring
- API Usage
- Kosten überwachen
- Rate Limits prüfen
### App Analytics
- Expo Analytics
- Crashlytics Integration
- Performance Monitoring
## 7. Kosten-Optimierung
### Google Cloud TTS
- Erste 1M Zeichen/Monat kostenlos
- Neural2 Stimmen: $16/1M Zeichen
- Caching implementiert zur Kostenreduzierung
### Supabase
- Free Tier: 500MB DB, 1GB Storage
- Pro Tier: $25/Monat für erweiterte Features
- Storage: $0.021/GB/Monat
## 8. Sicherheit
### Best Practices
- API Keys niemals in Client-Code
- Row Level Security (RLS) aktiviert
- Signed URLs für Audio-Dateien
- JWT Token Validation
### Regelmäßige Updates
- Dependencies aktualisieren
- Sicherheitspatches einspielen
- API Key Rotation
## 9. Troubleshooting
### Häufige Probleme
1. **Audio-Generierung fehlschlägt**
- Google Cloud API Key prüfen
- Quota-Limits prüfen
- Edge Function Logs kontrollieren
2. **Supabase Connection Issues**
- Environment Variables prüfen
- RLS Policies kontrollieren
- Database Connection Pool
3. **Audio-Wiedergabe Probleme**
- Expo AV Permissions
- File System Access
- Audio Format Kompatibilität
### Logs & Debugging
```bash
# Supabase Logs
supabase logs
# Edge Function Logs
supabase functions logs generate-audio
# App Logs
expo logs
```
## 10. Nächste Schritte
### Feature Roadmap
- Push Notifications
- Offline-First Synchronisation
- Cloud Backup
- Multi-User Support
- Advanced Audio Controls
### Performance Optimierung
- Image Optimization
- Bundle Size Reduction
- Lazy Loading
- Background Processing

View file

@ -0,0 +1,134 @@
# Google Cloud Text-to-Speech Setup
## 1. Google Cloud Projekt erstellen
1. Besuche die [Google Cloud Console](https://console.cloud.google.com/)
2. Erstelle ein neues Projekt oder wähle ein existierendes aus
3. Notiere dir die **Project ID**
## 2. Text-to-Speech API aktivieren
1. Gehe zu "APIs & Services" → "Library"
2. Suche nach "Cloud Text-to-Speech API"
3. Klicke auf "Enable"
## 3. Service Account erstellen
1. Gehe zu "IAM & Admin" → "Service Accounts"
2. Klicke auf "Create Service Account"
3. Name: `reader-tts-service`
4. Rolle: `Cloud Text-to-Speech Client`
5. Klicke auf "Create and Continue"
## 4. API Key erstellen (Alternative)
Für einfache Implementierung können wir einen API Key verwenden:
1. Gehe zu "APIs & Services" → "Credentials"
2. Klicke auf "Create Credentials" → "API Key"
3. Kopiere den API Key
4. Klicke auf "Restrict Key" für Sicherheit
5. Unter "API restrictions" wähle "Cloud Text-to-Speech API"
## 5. Supabase Environment Variables
Füge folgende Variablen in deine Supabase Edge Functions ein:
```bash
# In der Supabase Dashboard unter Settings → Edge Functions → Environment Variables
GOOGLE_TTS_API_KEY=dein_api_key_hier
```
## 6. Verfügbare Google Cloud TTS Voices
### Deutsch (de-DE)
#### Neural2 Voices (Empfohlen - beste Balance zwischen Qualität und Kosten)
- `de-DE-Neural2-A` (weiblich)
- `de-DE-Neural2-B` (männlich)
- `de-DE-Neural2-C` (weiblich)
- `de-DE-Neural2-D` (männlich)
- `de-DE-Neural2-E` (weiblich)
- `de-DE-Neural2-F` (männlich)
#### WaveNet Voices (Hochqualitativ)
- `de-DE-Wavenet-A` (weiblich)
- `de-DE-Wavenet-B` (männlich)
- `de-DE-Wavenet-C` (weiblich)
- `de-DE-Wavenet-D` (männlich)
- `de-DE-Wavenet-E` (weiblich)
- `de-DE-Wavenet-F` (männlich)
#### Studio Voices (Broadcast-Qualität)
- `de-DE-Studio-B` (männlich)
- `de-DE-Studio-C` (weiblich)
#### Standard Voices (Basis-Qualität, günstigste Option)
- `de-DE-Standard-A` (weiblich)
- `de-DE-Standard-B` (männlich)
- `de-DE-Standard-C` (weiblich)
- `de-DE-Standard-D` (männlich)
- `de-DE-Standard-E` (weiblich)
- `de-DE-Standard-F` (männlich)
### Englisch (US)
- `en-US-Neural2-A` (männlich)
- `en-US-Neural2-C` (weiblich)
- `en-US-Neural2-D` (männlich)
- `en-US-Neural2-E` (weiblich)
### Englisch (UK)
- `en-GB-Neural2-A` (weiblich)
- `en-GB-Neural2-B` (männlich)
- `en-GB-Neural2-C` (weiblich)
- `en-GB-Neural2-D` (männlich)
## 7. Kostenschätzung
- **Standard Voices**: $4.00 pro 1 Million Zeichen
- **Neural2 Voices**: $16.00 pro 1 Million Zeichen
- **Erstes 1 Million Zeichen pro Monat**: Kostenlos
### Beispielrechnung für 10.000 Zeichen:
- Standard: $0.04
- Neural2: $0.16
## 8. Quotas und Limits
- **Requests pro Minute**: 1,000
- **Requests pro Tag**: 100,000
- **Zeichen pro Request**: 5,000
## 9. Test der API
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"input": {"text": "Hallo Welt, das ist ein Test."},
"voice": {"languageCode": "de-DE", "name": "de-DE-Neural2-A"},
"audioConfig": {"audioEncoding": "MP3"}
}' \
"https://texttospeech.googleapis.com/v1/text:synthesize?key=YOUR_API_KEY"
```
## 10. Nächste Schritte
1. API Key in Supabase Environment Variables eintragen
2. Edge Functions deployen
3. Audio-Generierung in der App testen
4. Monitoring und Logging einrichten
## Sicherheitshinweise
- API Key niemals in Client-Code einbetten
- Nur über Supabase Edge Functions verwenden
- Regelmäßige Rotation der API Keys
- Monitoring der API-Nutzung einrichten

View file

@ -0,0 +1,149 @@
# URL-Extraktion Optionen
## Problem
Viele Webseiten zeigen Cookie-Banner oder andere Overlays, die den eigentlichen Inhalt blockieren.
## Lösungsoptionen
### 1. **ScrapingBee API** (Empfohlen für Production)
- **Vorteile**:
- JavaScript-Rendering
- Automatisches Cookie-Banner-Handling
- Anti-Bot-Umgehung
- Einfache Integration
- **Nachteile**:
- Kostenpflichtig (1000 kostenlose Credits/Monat)
- API-Key erforderlich
- **Setup**:
1. Account bei [ScrapingBee](https://www.scrapingbee.com) erstellen
2. API-Key in Supabase Secrets speichern: `SCRAPINGBEE_API_KEY`
3. Edge Function `extract-url-scrapingbee` deployen
### 2. **Browserless.io**
- **Vorteile**:
- Headless Chrome as a Service
- Puppeteer/Playwright kompatibel
- Cookie-Banner können programmatisch geklickt werden
- **Nachteile**:
- Kostenpflichtig
- Komplexere Integration
- **Code-Beispiel**:
```typescript
const browserlessUrl = `https://chrome.browserless.io/content?token=${BROWSERLESS_TOKEN}`;
const response = await fetch(browserlessUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: targetUrl,
waitFor: 3000,
scripts: [
{
content: `document.querySelectorAll('[class*="cookie"] button').forEach(b => b.click())`,
},
],
}),
});
```
### 3. **Reader API von Jina.ai** (Einfachste Lösung)
- **Vorteile**:
- Kostenlos
- Keine Registrierung
- Einfache Integration
- **Nachteile**:
- Weniger Kontrolle
- Rate Limits
- **Implementierung**:
```typescript
const response = await fetch(`https://r.jina.ai/${encodeURIComponent(url)}`, {
headers: {
Accept: 'application/json',
'X-With-Images': 'false',
},
});
```
### 4. **Client-seitige Lösung** (iOS/Android)
- **iOS**: SFSafariViewController mit Reader Mode
- **Android**: Chrome Custom Tabs mit Reader Mode
- **React Native**:
```typescript
import { WebView } from 'react-native-webview';
// Injiziere JavaScript um Content zu extrahieren
const injectedJS = `
// Entferne Cookie-Banner
document.querySelectorAll('[class*="cookie"]').forEach(el => el.remove());
// Sende Content zurück
window.ReactNativeWebView.postMessage(document.body.innerText);
`;
```
### 5. **Proxy-Service mit Playwright**
Eigener Service auf Vercel/Railway:
```typescript
// api/extract.ts
import { chromium } from 'playwright';
export default async function handler(req, res) {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(req.query.url);
// Warte auf Content und klicke Cookie-Banner weg
await page.waitForTimeout(2000);
await page.click('text=/akzeptieren|accept|agree/i').catch(() => {});
const content = await page.evaluate(() => {
return (
document.querySelector('article')?.innerText ||
document.querySelector('main')?.innerText ||
document.body.innerText
);
});
await browser.close();
res.json({ content });
}
```
## Empfehlung
Für schnelle Lösung: **Jina.ai Reader API** einbauen
Für Production: **ScrapingBee** mit Fallback auf direkte Extraktion
### Quick Implementation mit Jina.ai:
```typescript
// In extract-url Edge Function
try {
// Versuche zuerst Jina.ai
const jinaResponse = await fetch(`https://r.jina.ai/${url}`, {
headers: { Accept: 'application/json' },
});
if (jinaResponse.ok) {
const data = await jinaResponse.json();
return new Response(
JSON.stringify({
title: data.title,
content: data.content,
// ... weitere Felder
})
);
}
} catch (e) {
// Fallback auf normale Extraktion
}
```