mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 13:06:42 +02:00
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>
568 lines
17 KiB
Markdown
568 lines
17 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
Storyteller is a magical children's story generation app with:
|
|
|
|
- AI-powered story creation with consistent characters
|
|
- Custom character generation from descriptions or photos
|
|
- Multi-page illustrated stories
|
|
- Credit-based system via Mana Core
|
|
- Support for multiple languages (German/English)
|
|
|
|
## Prerequisites
|
|
|
|
- **Node.js 18+** and **pnpm 9+**
|
|
- Install pnpm globally: `npm install -g pnpm`
|
|
- Supabase account and project
|
|
- Mana Core account for authentication
|
|
- AI API keys (Azure OpenAI, Gemini, Replicate)
|
|
|
|
## Quick Start
|
|
|
|
### Local Development Setup (Mobile + Local Backend)
|
|
|
|
**Step 1: Configure mobile to use local backend**
|
|
|
|
```bash
|
|
# Edit apps/mobile/.env and set:
|
|
echo "EXPO_PUBLIC_STORYTELLER_BACKEND_URL=http://localhost:3002" > apps/mobile/.env
|
|
echo "EXPO_ROUTER_APP_ROOT=app" >> apps/mobile/.env
|
|
|
|
# For physical devices, use your computer's IP instead:
|
|
# EXPO_PUBLIC_STORYTELLER_BACKEND_URL=http://192.168.1.X:3002
|
|
```
|
|
|
|
**Step 2: Start backend and mobile**
|
|
|
|
```bash
|
|
# Terminal 1 - Backend
|
|
cd apps/backend && npm run dev
|
|
# Backend runs on http://localhost:3002
|
|
# Wait for "Nest application successfully started" message
|
|
|
|
# Terminal 2 - Mobile
|
|
cd apps/mobile && npm run dev
|
|
# Press 'i' for iOS, 'a' for Android, 'w' for web
|
|
```
|
|
|
|
**Step 3: Verify connection**
|
|
|
|
```bash
|
|
# In Terminal 1 (backend), you should see incoming requests from mobile app
|
|
# Check health endpoint:
|
|
curl http://localhost:3002/health | jq
|
|
```
|
|
|
|
### Alternative: Mobile with Production Backend
|
|
|
|
```bash
|
|
# Edit apps/mobile/.env to use production:
|
|
echo "EXPO_PUBLIC_STORYTELLER_BACKEND_URL=https://storyteller-backend-111768794939.europe-west3.run.app" > apps/mobile/.env
|
|
echo "EXPO_ROUTER_APP_ROOT=app" >> apps/mobile/.env
|
|
|
|
# Restart Expo with cache clear (important!)
|
|
cd apps/mobile && npx expo start -c
|
|
```
|
|
|
|
### Quick Backend Switch Reference
|
|
|
|
| Setup | apps/mobile/.env Value | Terminal Setup |
|
|
| ---------------------- | --------------------------------------------------------------- | ------------------------- |
|
|
| **Local Backend** | `http://localhost:3002` | Run both backend + mobile |
|
|
| **Physical Device** | `http://YOUR_IP:3002` | Run both backend + mobile |
|
|
| **Production Backend** | `https://storyteller-backend-111768794939.europe-west3.run.app` | Run mobile only |
|
|
|
|
**Remember:** Always restart Expo with `-c` flag after changing `.env`
|
|
|
|
### Other Development Commands
|
|
|
|
**Install dependencies (first time):**
|
|
|
|
```bash
|
|
pnpm install
|
|
```
|
|
|
|
**Start everything via Turborepo:**
|
|
|
|
```bash
|
|
pnpm run dev # From root - starts all services
|
|
```
|
|
|
|
**Backend only:**
|
|
|
|
```bash
|
|
cd apps/backend && npm run dev
|
|
# Test: curl http://localhost:3002/health | jq
|
|
```
|
|
|
|
**Mobile only:**
|
|
|
|
```bash
|
|
cd apps/mobile && npm run dev
|
|
```
|
|
|
|
**Landing page:**
|
|
|
|
```bash
|
|
cd apps/landing && npm run dev
|
|
```
|
|
|
|
**Web app:**
|
|
|
|
```bash
|
|
cd apps/web && npm run dev
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
apps/maerchenzauber/
|
|
├── apps/
|
|
│ ├── backend/ # NestJS backend
|
|
│ │ ├── src/
|
|
│ │ │ ├── story/ # Story generation & management
|
|
│ │ │ │ ├── services/story-creation.service.ts # Main story generation logic
|
|
│ │ │ │ └── illustration.service.ts # Image generation
|
|
│ │ │ ├── character/ # Character creation & management
|
|
│ │ │ │ └── character.service.ts
|
|
│ │ │ ├── core/
|
|
│ │ │ │ ├── services/
|
|
│ │ │ │ │ ├── prompting.service.ts # AI prompt management
|
|
│ │ │ │ │ ├── image-supabase.service.ts # Image storage
|
|
│ │ │ │ │ └── supabase-data.service.ts # Database operations
|
|
│ │ │ │ └── consts/ # System prompts & constants
|
|
│ │ │ ├── settings/ # User settings
|
|
│ │ │ ├── credits/ # Credit management
|
|
│ │ │ ├── auth/ # Authentication proxy
|
|
│ │ │ └── health/ # Health checks
|
|
│ │ └── .env # Backend configuration
|
|
│ ├── mobile/ # React Native Expo app
|
|
│ │ ├── app/ # expo-router routes
|
|
│ │ │ └── (tabs)/
|
|
│ │ │ ├── (story)/ # Story screens
|
|
│ │ │ └── (character)/ # Character screens
|
|
│ │ ├── src/
|
|
│ │ │ ├── utils/api.ts # API client
|
|
│ │ │ ├── services/
|
|
│ │ │ │ ├── authService.ts
|
|
│ │ │ │ └── tokenManager.ts
|
|
│ │ │ ├── components/ # Reusable components
|
|
│ │ │ └── hooks/ # Custom React hooks
|
|
│ │ └── .env # Mobile configuration
|
|
│ ├── landing/ # Astro landing page
|
|
│ └── web/ # SvelteKit web app (NEW)
|
|
├── docs/ # Documentation
|
|
│ └── SYSTEM_CHARACTERS.md # System characters guide
|
|
├── turbo.json # Turborepo configuration
|
|
└── package.json # Root package with workspace scripts
|
|
```
|
|
|
|
## Key Implementation Details
|
|
|
|
### Story Generation Flow
|
|
|
|
1. **Character Selection**: User selects existing character or creates new one
|
|
2. **Story Request**: User provides story description, system selects author/illustrator personas
|
|
3. **Generation Pipeline**:
|
|
- Generate story text (10 pages) via `story-creation.service.ts`
|
|
- Extract character descriptions
|
|
- Generate illustration prompts
|
|
- Create images via Replicate
|
|
- Translate to German
|
|
- Save to database
|
|
4. **Credit Deduction**: 10 credits per story/character via Mana Core
|
|
|
|
### System Characters
|
|
|
|
System characters are special read-only characters visible to all users:
|
|
|
|
- Identified by system user ID: `00000000-0000-0000-0000-000000000000`
|
|
- Accessible to all authenticated users via RLS policies
|
|
- Cannot be edited or deleted by regular users
|
|
- UI hides edit/share buttons for system characters
|
|
- Currently includes "Finia" the wise fox as the default character
|
|
|
|
**See detailed documentation**: [docs/SYSTEM_CHARACTERS.md](docs/SYSTEM_CHARACTERS.md)
|
|
|
|
Key implementation points:
|
|
|
|
- **Database**: Characters table with system `user_id`
|
|
- **Backend**: Validation allows both owned and system characters
|
|
- **Frontend**: Conditional rendering based on `user_id` check
|
|
- **Storage**: Images stored in system user folder in Supabase Storage
|
|
|
|
### AI Services Architecture
|
|
|
|
- **Prompting**: `backend/src/core/services/prompting.service.ts` handles all AI interactions
|
|
- **System Prompts**: Stored in `backend/src/core/consts/`
|
|
- **Image Generation**: `backend/src/core/services/image-supabase.service.ts`
|
|
- **Storage**: Supabase Storage bucket `maerchenzauber`
|
|
- **Models**: Azure OpenAI (GPT-4), Google Gemini, Replicate (Flux for images)
|
|
|
|
### Database (Supabase)
|
|
|
|
- **Client**: `backend/src/supabase/supabase.provider.ts`
|
|
- **Data Service**: `backend/src/core/services/supabase-data.service.ts`
|
|
- **Tables**: `characters`, `stories`, `story_collections`, `user_settings`
|
|
|
|
### Authentication
|
|
|
|
- Uses Mana Core for authentication
|
|
- Backend acts as proxy: `backend/src/auth/`
|
|
- Mobile token management: `mobile/src/services/tokenManager.ts`
|
|
- Secure storage: `expo-secure-store` for tokens
|
|
|
|
## Package Manager
|
|
|
|
This project uses **PNPM** as the package manager for better performance and disk space efficiency.
|
|
|
|
**Key PNPM commands:**
|
|
|
|
```bash
|
|
pnpm install # Install all dependencies
|
|
pnpm add <package> # Add a dependency to workspace root
|
|
pnpm add <package> -w # Add to workspace root (explicit)
|
|
pnpm add <package> --filter @storyteller/backend # Add to specific app
|
|
```
|
|
|
|
## Available Scripts
|
|
|
|
### Root Level
|
|
|
|
- `pnpm run dev` - Start all services (Turborepo)
|
|
- `pnpm run build` - Build all applications
|
|
- `pnpm run lint` - Lint all packages
|
|
- `pnpm run type-check` - TypeScript checks
|
|
- `pnpm run format` - Format with Prettier
|
|
- `pnpm run clean` - Clean build artifacts
|
|
|
|
### Backend (cd apps/backend)
|
|
|
|
- `pnpm run dev` - Start with hot reload (port 3002)
|
|
- `pnpm run build` - Build production bundle
|
|
- `pnpm run start:prod` - Run production build
|
|
- `pnpm run test` - Run Jest tests
|
|
- `pnpm run test:watch` - Tests in watch mode
|
|
- `pnpm run test:cov` - Tests with coverage
|
|
- `pnpm run type-check` - TypeScript validation
|
|
|
|
### Mobile (cd apps/mobile)
|
|
|
|
- `pnpm run dev` - Start Expo dev server
|
|
- `pnpm run ios` - Run on iOS simulator
|
|
- `pnpm run android` - Run on Android emulator
|
|
- `pnpm run web` - Run in browser
|
|
- `pnpm run build` - Export production build
|
|
- `pnpm run test` - Run tests
|
|
- `pnpm run type-check` - TypeScript validation
|
|
|
|
### Landing Page (cd apps/landing)
|
|
|
|
- `pnpm run dev` - Start Astro dev server
|
|
- `pnpm run build` - Build static site
|
|
- `pnpm run preview` - Preview production build
|
|
|
|
### Web App (cd apps/web)
|
|
|
|
- `pnpm run dev` - Start SvelteKit dev server
|
|
- `pnpm run build` - Build production bundle
|
|
- `pnpm run preview` - Preview production build
|
|
|
|
## Troubleshooting
|
|
|
|
### Backend Won't Start
|
|
|
|
```bash
|
|
# Port 3002 already in use
|
|
lsof -i :3002
|
|
kill -9 $(lsof -t -i:3002)
|
|
|
|
# Check environment variables
|
|
cat backend/.env | grep -v "^#" | grep -v "^$"
|
|
|
|
# Database connection issues - verify:
|
|
# - MAERCHENZAUBER_SUPABASE_URL
|
|
# - MAERCHENZAUBER_SUPABASE_ANON_KEY
|
|
# - MAERCHENZAUBER_SUPABASE_SERVICE_ROLE_KEY
|
|
```
|
|
|
|
### Mobile Can't Connect to Backend
|
|
|
|
```bash
|
|
# For physical devices, use computer IP instead of localhost
|
|
ifconfig | grep "inet " | grep -v 127.0.0.1
|
|
|
|
# Update apps/mobile/.env
|
|
EXPO_PUBLIC_STORYTELLER_BACKEND_URL=http://YOUR_IP:3002
|
|
|
|
# IMPORTANT: After changing .env, restart Expo dev server
|
|
cd apps/mobile && npx expo start -c # -c flag clears cache
|
|
```
|
|
|
|
### Environment Variables Not Loading
|
|
|
|
```bash
|
|
# Mobile app: Environment changes require restart
|
|
# 1. Stop Expo dev server (Ctrl+C)
|
|
# 2. Clear cache and restart:
|
|
cd apps/mobile && npx expo start -c
|
|
|
|
# Backend: Changes require restart
|
|
# 1. Stop backend (Ctrl+C)
|
|
# 2. Restart:
|
|
cd apps/backend && npm run dev
|
|
|
|
# Verify environment is loaded (backend):
|
|
# Check logs on startup - you should see configuration being loaded
|
|
```
|
|
|
|
### AI Service Errors
|
|
|
|
Check these environment variables in `apps/backend/.env`:
|
|
|
|
- `MAERCHENZAUBER_AZURE_OPENAI_ENDPOINT` and `_KEY`
|
|
- `MAERCHENZAUBER_GOOGLE_GENAI_API_KEY`
|
|
- `MAERCHENZAUBER_REPLICATE_API_KEY`
|
|
|
|
### iOS Deeplink Crashes
|
|
|
|
If the app crashes when opening deeplinks on iOS (especially character sharing links):
|
|
|
|
See **[complete debugging guide](mobile/docs/DEEPLINK_CRASH_FIX.md)** for detailed solutions.
|
|
|
|
**Quick fixes**:
|
|
|
|
1. Check `expo-linear-gradient` version is 15.0.7+
|
|
2. Ensure all `LinearGradient` styles use `alignSelf: 'stretch'` instead of `width: '100%'`
|
|
3. Verify `MagicalLoadingScreen` has `context` prop
|
|
4. Check `expo-image` has `transition={0}` on navigation screens
|
|
5. Ensure each route directory has proper `_layout.tsx` with `freezeOnBlur: false`
|
|
|
|
**Common symptoms**:
|
|
|
|
- Crash during navigation after deeplink opens
|
|
- `CoreGraphics CGContextDrawLinearGradient` errors
|
|
- `RNSScreen setViewToSnapshot` crashes
|
|
- Image deallocation errors
|
|
|
|
## API Testing
|
|
|
|
### Health Checks
|
|
|
|
```bash
|
|
# Full health check
|
|
curl http://localhost:3002/health | jq
|
|
|
|
# Readiness check (for deployments)
|
|
curl http://localhost:3002/health/ready | jq
|
|
|
|
# Liveness check
|
|
curl http://localhost:3002/health/live | jq
|
|
```
|
|
|
|
### Main Endpoints
|
|
|
|
```bash
|
|
# Authentication
|
|
POST /auth/signin # Sign in with email/password
|
|
POST /auth/signup # Create account
|
|
POST /auth/google-signin # Google OAuth
|
|
POST /auth/apple-signin # Apple Sign In
|
|
POST /auth/refresh # Refresh token
|
|
POST /auth/logout # Log out
|
|
|
|
# Characters
|
|
GET /character # List user's characters
|
|
POST /character/generate-images # Generate character
|
|
GET /character/:id # Get specific character
|
|
PUT /character/:id # Update character
|
|
DELETE /character/:id # Delete character
|
|
|
|
# Stories
|
|
GET /story # List user's stories
|
|
POST /story # Create new story
|
|
GET /story/:id # Get specific story
|
|
PUT /story/:id # Update story
|
|
DELETE /story/:id # Delete story
|
|
|
|
# Settings
|
|
GET /settings/user # User settings
|
|
PUT /settings/user # Update settings
|
|
GET /settings/creators # Available creators
|
|
GET /settings/languages # Supported languages
|
|
|
|
# Credits
|
|
GET /credits/balance # Get balance
|
|
GET /credits/history # Transaction history
|
|
POST /credits/check # Check availability
|
|
POST /credits/consume # Consume credits
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
### Backend (`backend/.env`)
|
|
|
|
**Required:**
|
|
|
|
- `MANA_SERVICE_URL` - Mana Core auth service URL
|
|
- `APP_ID` - Mana Core application ID
|
|
- `SERVICE_KEY` - Mana Core service key
|
|
- `MAERCHENZAUBER_SUPABASE_URL` - Supabase project URL
|
|
- `MAERCHENZAUBER_SUPABASE_ANON_KEY` - Supabase anonymous key
|
|
- `MAERCHENZAUBER_SUPABASE_SERVICE_ROLE_KEY` - Supabase service role key
|
|
- `MAERCHENZAUBER_AZURE_OPENAI_ENDPOINT` - Azure OpenAI endpoint
|
|
- `MAERCHENZAUBER_AZURE_OPENAI_KEY` - Azure OpenAI key
|
|
- `MAERCHENZAUBER_GOOGLE_GENAI_API_KEY` - Google Gemini API key
|
|
- `MAERCHENZAUBER_REPLICATE_API_KEY` - Replicate API token
|
|
- `MAERCHENZAUBER_STORAGE_BUCKET` - Supabase storage bucket name (default: `maerchenzauber`)
|
|
|
|
**Optional:**
|
|
|
|
- `PORT` - Server port (default: 3002)
|
|
- `NODE_ENV` - Environment (development/production)
|
|
|
|
### Mobile (`apps/mobile/.env`)
|
|
|
|
**Required:**
|
|
|
|
- `EXPO_PUBLIC_STORYTELLER_BACKEND_URL` - Backend API URL
|
|
- Local: `http://localhost:3002`
|
|
- Production: `https://storyteller-backend-111768794939.europe-west3.run.app`
|
|
- Physical devices: `http://YOUR_COMPUTER_IP:3002`
|
|
- `EXPO_ROUTER_APP_ROOT` - App root (always `app`)
|
|
|
|
## Code Patterns & Standards
|
|
|
|
### Backend (NestJS/TypeScript)
|
|
|
|
- **Dependency Injection**: Use NestJS DI with `@Injectable()` decorators
|
|
- **Error Handling**: Return `Result<T>` type: `{ data: T | null, error: Error | null }`
|
|
- **DTOs**: Use `class-validator` decorators for validation
|
|
- **Logging**: Use console.log with service prefix: `console.log('[ServiceName]', 'message', data)`
|
|
- **Database**: All queries through `supabase-data.service.ts`
|
|
|
|
### Mobile (React Native/Expo)
|
|
|
|
- **Components**: Functional components with hooks only
|
|
- **Navigation**: Use `expo-router` file-based routing
|
|
- **API Calls**: Through `src/utils/api.ts` with automatic token refresh
|
|
- **Storage**: Use `expo-secure-store` for sensitive data, `@react-native-async-storage/async-storage` for non-sensitive
|
|
- **State**: Local state with `useState`, no global state library currently
|
|
|
|
### Error Handling Pattern
|
|
|
|
```typescript
|
|
// Backend
|
|
async function operation(): Promise<Result<Data>> {
|
|
try {
|
|
const result = await doSomething();
|
|
return { data: result, error: null };
|
|
} catch (error) {
|
|
console.error('[ServiceName] Operation failed:', error);
|
|
return { data: null, error };
|
|
}
|
|
}
|
|
|
|
// Mobile
|
|
const response = await fetchWithAuth('/endpoint', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`API error: ${response.status}`);
|
|
}
|
|
```
|
|
|
|
## Deployment
|
|
|
|
### Backend (Google Cloud Run)
|
|
|
|
Current production: `https://storyteller-backend-111768794939.europe-west3.run.app`
|
|
|
|
```bash
|
|
cd apps/backend
|
|
|
|
# Build and test locally
|
|
docker build -t storyteller-backend .
|
|
docker run -p 3002:3002 --env-file .env storyteller-backend
|
|
|
|
# Deploy to Cloud Run
|
|
gcloud builds submit --tag gcr.io/PROJECT_ID/storyteller-backend
|
|
gcloud run deploy storyteller-backend \
|
|
--image gcr.io/PROJECT_ID/storyteller-backend \
|
|
--region europe-west3 \
|
|
--platform managed \
|
|
--allow-unauthenticated
|
|
```
|
|
|
|
### Mobile (EAS Build)
|
|
|
|
EAS configuration in `eas.json` at project root.
|
|
|
|
```bash
|
|
cd apps/mobile
|
|
|
|
# Configure EAS (first time)
|
|
eas build:configure
|
|
|
|
# Build for iOS
|
|
eas build --platform ios --profile production
|
|
|
|
# Build for Android
|
|
eas build --platform android --profile production
|
|
|
|
# Submit to stores
|
|
eas submit --platform ios
|
|
eas submit --platform android
|
|
```
|
|
|
|
### Landing Page (Netlify/Vercel)
|
|
|
|
```bash
|
|
cd apps/landing
|
|
|
|
# Build locally
|
|
npm run build
|
|
|
|
# Deploy (automatically via git push to main)
|
|
```
|
|
|
|
### Web App (SvelteKit)
|
|
|
|
```bash
|
|
cd apps/web
|
|
|
|
# Build locally
|
|
npm run build
|
|
|
|
# Preview production build
|
|
npm run preview
|
|
```
|
|
|
|
## Debugging
|
|
|
|
### Backend Debugging
|
|
|
|
```bash
|
|
# Check logs in production
|
|
gcloud run services logs read storyteller-backend --limit=100
|
|
|
|
# Monitor specific service
|
|
gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=storyteller-backend" --limit=50
|
|
```
|
|
|
|
### Mobile Debugging
|
|
|
|
- **Network**: Check API calls in `apps/mobile/src/utils/api.ts`
|
|
- **Storage**: Use React Native Debugger to inspect AsyncStorage/SecureStore
|
|
- **Logs**: Use `console.log('[ComponentName]', message)` format
|
|
- **Expo**: Use `npx expo start --dev-client` for more debugging tools
|
|
|
|
### Database Debugging
|
|
|
|
- Use Supabase Dashboard for direct queries
|
|
- Add `.select('*')` to see all returned fields
|
|
- Check RLS policies if queries return empty results
|