managarten/apps/cards/MANA_CORE_ARCHITECTURE.md
Till JS 22a73943e1 chore: complete ManaCore → Mana rename (docs, go modules, plists, images)
Final cleanup of references missed in previous rename commits:

- Dockerfiles: PUBLIC_MANA_CORE_AUTH_URL → PUBLIC_MANA_AUTH_URL
- Go modules: github.com/manacore/* → github.com/mana/* (7 go.mod files)
- launchd plists: com.manacore.* → com.mana.* (14 files renamed + content)
- Image assets: *_Manacore_AI_Credits* → *_Mana_AI_Credits* (11 files)
- .env.example files: ManaCore brand strings → Mana
- .prettierignore: stale apps/manacore/* paths → apps/mana/*
- Markdown docs (CLAUDE.md, /docs/*): mana-core-auth → mana-auth, etc.

Excluded from rename: .claude/, devlog/, manascore/ (historical content),
client testimonials, blueprints, npm package refs (@mana-core/*).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:26:10 +02:00

591 lines
30 KiB
Markdown

# Mana Architecture in Storyteller
This document explains the architecture and data flow of the Mana integration in the Storyteller project.
## System Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ Frontend Layer │
│ (React Native + Expo) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Auth Service │ │ API Client │ │Token Manager │ │
│ │ │ │ │ │ │ │
│ │ • Sign In │ │ • fetchWith │ │ • getValid │ │
│ │ • Sign Up │ │ Auth() │ │ Token() │ │
│ │ • Sign Out │ │ • Auto │ │ • refresh │ │
│ │ • Device │ │ Refresh │ │ Token() │ │
│ │ Info │ │ • Error │ │ • Token │ │
│ │ │ │ Handling │ │ Storage │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
└─────────┼──────────────────┼──────────────────┼────────────────┘
│ │ │
│ HTTP/HTTPS │ Bearer Token │ Refresh
│ Requests │ in Headers │ Flow
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Backend Layer │
│ (NestJS + TypeScript) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Mana NestJS Integration │ │
│ ├───────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ AuthGuard │ │@CurrentUser()│ │ Credit │ │ │
│ │ │ │ │ │ │ Client │ │ │
│ │ │ • Validate │ │ • Extract │ │ Service │ │ │
│ │ │ JWT │ │ User ID │ │ │ │ │
│ │ │ • Check │ │ • Extract │ │ • validate │ │ │
│ │ │ Expiry │ │ Email │ │ Credits() │ │ │
│ │ │ • Inject │ │ • Extract │ │ • consume │ │ │
│ │ │ User │ │ Role │ │ Credits() │ │ │
│ │ │ │ │ │ │ • get │ │ │
│ │ │ │ │ │ │ Balance() │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────┼──────────────────────────────────┐ │
│ │ Application Controllers & Services │ │
│ ├────────────────────────┼──────────────────────────────────┤ │
│ │ │ │ │
│ │ CharacterController │ StoryController │ │
│ │ • generateCharacter │ • createStory │ │
│ │ • getCharacters │ • getStories │ │
│ │ • updateCharacter │ • updateStory │ │
│ │ • deleteCharacter │ • deleteStory │ │
│ │ │ │ │
│ │ SettingsController │ CreatorsController │ │
│ │ • getUserSettings │ • getCreators │ │
│ │ • updateSettings │ • getLanguages │ │
│ │ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
└───────────────────────────┼─────────────────────────────────────┘
│ API Requests
│ (Auth Validation,
│ Credit Operations)
┌─────────────────────────────────────────────────────────────────┐
│ Mana Service │
│ (Authentication & Credits) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ Authentication │ │ Credit Management │ │
│ │ │ │ │ │
│ │ • User Management │ │ • Balance Tracking │ │
│ │ • Token Generation │ │ • Transaction Log │ │
│ │ • Token Validation │ │ • Operation Types │ │
│ │ • Token Refresh │ │ • App-Level Track │ │
│ │ • Device Management │ │ • Space Credits │ │
│ │ • OAuth Providers │ │ • Billing History │ │
│ │ │ │ │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
---
## Authentication Flow
### Sign-In Flow
```
┌────────┐ ┌────────┐ ┌────────┐
│ Mobile │ │Backend │ │ Mana │
│ App │ │ (Nest) │ │ Core │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
│ 1. Sign In Request │ │
│ POST /auth/signin │ │
│ { email, password, │ │
│ deviceInfo } │ │
├────────────────────────────►│ │
│ │ │
│ │ 2. Forward to Mana │
│ │ POST /auth/signin │
│ ├────────────────────────────►│
│ │ │
│ │ │ 3. Validate
│ │ │ Credentials
│ │ │
│ │ 4. Return Tokens │
│ │ { appToken, refreshToken, │
│ │ user, device } │
│ │◄────────────────────────────┤
│ │ │
│ 5. Return to Client │ │
│ { appToken, refreshToken } │ │
│◄────────────────────────────┤ │
│ │ │
│ 6. Store Tokens │ │
│ in SecureStorage │ │
│ │ │
```
### Token Refresh Flow
```
┌────────┐ ┌────────┐ ┌────────┐
│ Mobile │ │Backend │ │ Mana │
│ App │ │ (Nest) │ │ Core │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
│ 1. API Request │ │
│ with Expired Token │ │
├────────────────────────────►│ │
│ │ │
│ │ 2. Validate Token │
│ │ (Expired!) │
│ │ │
│ 3. 401 Unauthorized │ │
│◄────────────────────────────┤ │
│ │ │
│ 4. Token Refresh Request │ │
│ POST /auth/refresh │ │
│ { refreshToken, deviceInfo }│ │
├────────────────────────────►│ │
│ │ │
│ │ 5. Forward to Mana │
│ ├────────────────────────────►│
│ │ │
│ │ │ 6. Validate
│ │ │ Refresh
│ │ │ Token
│ │ │
│ │ 7. New Tokens │
│ │◄────────────────────────────┤
│ │ │
│ 8. Return New Tokens │ │
│◄────────────────────────────┤ │
│ │ │
│ 9. Store New Tokens │ │
│ │ │
│ 10. Retry Original Request │ │
│ with New Token │ │
├────────────────────────────►│ │
│ │ │
│ 11. Success Response │ │
│◄────────────────────────────┤ │
```
---
## Protected Route Flow
### With AuthGuard
```
┌────────┐ ┌────────┐ ┌────────┐
│ Mobile │ │Backend │ │ Mana │
│ App │ │ (Nest) │ │ Core │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
│ 1. GET /character │ │
│ Authorization: Bearer │ │
│ eyJhbGc... │ │
├────────────────────────────►│ │
│ │ │
│ │ 2. AuthGuard │
│ │ intercepts │
│ │ │
│ │ 3. Validate Token │
│ ├────────────────────────────►│
│ │ │
│ │ 4. Token Valid │
│ │ + User Payload │
│ │◄────────────────────────────┤
│ │ │
│ │ 5. Inject user into │
│ │ request object │
│ │ │
│ │ 6. Execute Controller │
│ │ Method │
│ │ @CurrentUser() │
│ │ extracts user │
│ │ │
│ 7. Response with Data │ │
│◄────────────────────────────┤ │
│ │ │
```
---
## Credit Management Flow
### Character Creation (20 Credits)
```
┌────────┐ ┌────────┐ ┌────────┐
│ Mobile │ │Backend │ │ Mana │
│ App │ │ (Nest) │ │ Core │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
│ 1. Create Character Request │ │
│ POST /character/generate │ │
│ { name, description } │ │
├────────────────────────────►│ │
│ │ │
│ │ 2. Pre-flight Check │
│ │ validateCredits() │
│ │ userId, "character_ │
│ │ creation", 20 │
│ ├────────────────────────────►│
│ │ │
│ │ │ 3. Check
│ │ │ Balance
│ │ │
│ │ 4. Validation Result │
│ │ { hasCredits: true, │
│ │ availableCredits: 100 } │
│ │◄────────────────────────────┤
│ │ │
│ │ 5. If hasCredits = false │
│ │ Return error │
│◄────────────────────────────┤ │
│ │ │
│ 6. Show "Buy Credits" Modal │ │
│ │ │
│ │ 7. If hasCredits = true │
│ │ Proceed with creation │
│ │ • Generate images │
│ │ • Store in database │
│ │ │
│ │ 8. Consume Credits │
│ │ consumeCredits() │
│ │ userId, "character_ │
│ │ creation", 20, │
│ │ "Created: Cat" │
│ ├────────────────────────────►│
│ │ │
│ │ │ 9. Deduct
│ │ │ Credits
│ │ │
│ │ 10. Transaction Receipt │
│ │ { transactionId, │
│ │ remainingBalance: 80 } │
│ │◄────────────────────────────┤
│ │ │
│ 11. Success Response │ │
│ { data: { characterId, │ │
│ images, ... } } │ │
│◄────────────────────────────┤ │
│ │ │
```
### Story Creation (100 Credits)
```
Same flow as character creation, but with:
- operationType: "story_creation"
- amount: 100
- More expensive due to:
* Story text generation
* Multiple image generations (10 pages)
* Translation to German
```
---
## Credit Operation Types in Storyteller
```typescript
// Defined in Storyteller
type StorytellerOperations =
| 'character_creation' // 20 credits
| 'story_creation'; // 100 credits
// Credit Costs
const CREDIT_COSTS = {
character_creation: 20, // 3 image variants
story_creation: 100, // 10-page story with images + translation
};
```
---
## Data Flow: Complete Example
### Creating a Story with Credits
1. **Frontend**: User fills story form
```typescript
const createStory = async () => {
const response = await fetchWithAuth('/story', {
method: 'POST',
body: JSON.stringify({
characters: [characterId],
storyDescription: 'A magical forest adventure',
authorId: 'author-1',
illustratorId: 'illustrator-1',
}),
});
const data = await response.json();
if (data.error === 'insufficient_credits') {
navigation.navigate('PurchaseCredits', {
required: 100,
available: data.availableCredits,
});
}
};
```
2. **Backend Controller**: Story creation endpoint
```typescript
@Post()
@UseGuards(AuthGuard)
async createStory(
@Body() dto: CreateStoryDto,
@CurrentUser() user: JwtPayload,
) {
// Pre-flight check
const validation = await this.creditClient.validateCredits(
user.sub,
'story_creation',
100,
);
if (!validation.hasCredits) {
throw new BadRequestException({
error: 'insufficient_credits',
requiredCredits: 100,
availableCredits: validation.availableCredits,
});
}
// Create story
const result = await this.storyService.createStory({
userId: user.sub,
characterId: dto.characters[0],
storyDescription: dto.storyDescription,
});
// Consume credits
await this.creditClient.consumeCredits(
user.sub,
'story_creation',
100,
`Created story: ${result.storyData.title}`,
{ storyId: result.storyData.id },
);
return result;
}
```
3. **Mana**: Processes credit operations
- Validates user has sufficient credits
- Deducts credits from user's balance
- Records transaction in ledger
- Returns transaction ID and new balance
- Tracks operation by app ID
---
## Security Architecture
### Token Security
```
┌─────────────────────────────────────────────────────────┐
│ Token Structure │
├─────────────────────────────────────────────────────────┤
│ │
│ Access Token (appToken): │
│ • JWT format │
│ • Short-lived (15 minutes) │
│ • Contains: { sub, email, role, exp, iat } │
│ • Used for API authentication │
│ • Stored in SecureStorage (mobile) │
│ │
│ Refresh Token: │
│ • Long-lived (30 days) │
│ • Used to get new access token │
│ • Single-use (rotated on refresh) │
│ • Device-specific │
│ • Stored in SecureStorage (mobile) │
│ │
└─────────────────────────────────────────────────────────┘
```
### AuthGuard Protection
```typescript
// All routes under @UseGuards(AuthGuard) are protected:
✅ Validates JWT signature
✅ Checks token expiration
✅ Extracts user payload
✅ Injects user into request
✅ Returns 401 if invalid
// Usage:
@Controller('character')
@UseGuards(AuthGuard) // ← Protects all routes in controller
export class CharacterController {
@Get()
getCharacters(@CurrentUser() user: JwtPayload) {
// user is automatically available here
}
}
```
---
## Database Integration (Supabase RLS)
### Row Level Security with JWT
Storyteller uses Supabase with Row Level Security (RLS). The `@UserToken()` decorator extracts the raw JWT for RLS:
```typescript
@Get()
async getCharacters(
@CurrentUser() user: JwtPayload, // Validated user
@UserToken() token: string, // Raw JWT for RLS
) {
// Pass token to Supabase client
const characters = await this.supabase
.from('characters')
.select('*')
.eq('user_id', user.sub)
.setAuth(token); // RLS enforces user_id match
return { data: characters };
}
```
**Why Both Decorators?**
- `@CurrentUser()`: Validated user data for business logic
- `@UserToken()`: Raw JWT for database RLS enforcement
---
## Environment Configuration
### Backend `.env`
```env
# Mana (Required)
MANA_SERVICE_URL=https://mana-middleware-111768794939.europe-west3.run.app
APP_ID=8d2f5ddb-e251-4b3b-8802-84022a7ac77f
MANA_SUPABASE_SECRET_KEY=your-service-key
# Application
NODE_ENV=development
PORT=3002
# Database (Supabase)
MAERCHENZAUBER_SUPABASE_URL=your-supabase-url
MAERCHENZAUBER_SUPABASE_ANON_KEY=your-anon-key
```
### Frontend `.env`
```env
# Backend URL
EXPO_PUBLIC_STORYTELLER_BACKEND_URL=http://localhost:3002
# For production:
# EXPO_PUBLIC_STORYTELLER_BACKEND_URL=https://your-api.com
```
---
## Key Takeaways
### What Mana Provides
1. **Authentication System**
- ✅ Email/password sign-in/sign-up
- ✅ Google OAuth integration
- ✅ Apple Sign-in integration
- ✅ JWT token generation and validation
- ✅ Token refresh mechanism
- ✅ Multi-device management
2. **Credit Management**
- ✅ Balance tracking per user
- ✅ Pre-flight validation
- ✅ Transaction recording
- ✅ Operation type tracking
- ✅ App-level tracking
- ✅ Metadata support
3. **Developer Experience**
- ✅ Simple module configuration
- ✅ Guards for route protection
- ✅ Decorators for data extraction
- ✅ TypeScript support
- ✅ Error handling utilities
- ✅ Debug logging
### What You Need to Implement
1. **Application Logic**
- Define operation types
- Set credit costs
- Implement business logic
- Handle errors
2. **Frontend Integration**
- Token storage
- API client with auto-refresh
- Error handling UI
- Purchase flow (if needed)
3. **Testing**
- Unit tests with mocked services
- Integration tests
- End-to-end flows
---
## Performance Considerations
### Token Caching
- Frontend caches tokens in SecureStorage
- Token validation is fast (local check + remote if needed)
- Refresh only when needed (5-minute buffer)
### Credit Operations
- Pre-flight validation is lightweight
- Consumption happens after success
- No blocking during operations
### Best Practices
1. Always validate credits BEFORE expensive operations
2. Consume credits AFTER successful operations
3. Handle `InsufficientCreditsException` gracefully
4. Log all credit transactions for audit
---
## Next Steps
After understanding the architecture:
1. **Review the Integration Guide**: See `MANA_CORE_INTEGRATION_GUIDE.md`
2. **Follow the Checklist**: Use `MANA_CORE_INTEGRATION_CHECKLIST.md`
3. **Study the Code**: Examine Storyteller's implementation
4. **Test Thoroughly**: Ensure all flows work correctly
5. **Monitor in Production**: Track usage and errors
---
## Questions?
- **Full Guide**: `MANA_CORE_INTEGRATION_GUIDE.md`
- **Checklist**: `MANA_CORE_INTEGRATION_CHECKLIST.md`
- **Mana Docs**: https://docs.mana-core.com
- **GitHub**: https://github.com/Memo-2023/mana-core-nestjs-package