diff --git a/docs/prp/13-backend-authentication.md b/docs/prp/13-backend-authentication.md new file mode 100644 index 0000000..baeda85 --- /dev/null +++ b/docs/prp/13-backend-authentication.md @@ -0,0 +1,318 @@ +# 13 - Backend Authentication Implementation + +## Overview + +This document outlines the authentication requirements and implementation details for the Fotospiel tenant backend. The system uses OAuth2 with PKCE (Proof Key for Code Exchange) for secure authorization, providing tenant-specific access tokens for API operations. + +## Authentication Flow + +### 1. Authorization Request +- **Endpoint**: `POST /oauth/authorize` +- **Method**: GET (redirect from frontend) +- **Parameters**: + - `client_id`: Fixed client ID for tenant-admin-app (`tenant-admin-app`) + - `redirect_uri`: Frontend callback URL (e.g., `https://tenant-admin-app.example.com/auth/callback`) + - `response_type`: `code` + - `scope`: `tenant:read tenant:write` (tenant-specific scopes) + - `state`: CSRF protection state parameter + - `code_challenge`: PKCE challenge (SHA-256 hash of code verifier) + - `code_challenge_method`: `S256` + +**Response**: Redirect to frontend with authorization code and state parameters. + +### 2. Token Exchange +- **Endpoint**: `POST /oauth/token` +- **Method**: POST +- **Content-Type**: `application/x-www-form-urlencoded` +- **Parameters**: + - `grant_type`: `authorization_code` or `refresh_token` + - `client_id`: `tenant-admin-app` + - `code`: Authorization code (for initial exchange) + - `redirect_uri`: Same as authorization request + - `code_verifier`: PKCE verifier (plain text) + - `refresh_token`: For token refresh (optional) + +**Response** (JSON): +```json +{ + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "refresh_token": "def50200...", + "expires_in": 3600, + "token_type": "Bearer", + "scope": "tenant:read tenant:write" +} +``` + +### 3. Token Refresh +- **Endpoint**: `POST /oauth/token` +- **Method**: POST +- **Content-Type**: `application/x-www-form-urlencoded` +- **Parameters**: + - `grant_type`: `refresh_token` + - `client_id`: `tenant-admin-app` + - `refresh_token`: Current refresh token + +**Response**: Same as token exchange (new access and refresh tokens). + +### 4. Token Validation +- **Endpoint**: `GET /api/v1/tenant/me` +- **Method**: GET +- **Authorization**: `Bearer {access_token}` +- **Purpose**: Validate token and return tenant information + +**Response** (JSON): +```json +{ + "tenant_id": "tenant-uuid", + "tenant_name": "Event Photo Company", + "credits": 150, + "role": "admin", + "email": "admin@eventphoto.com" +} +``` + +## Security Requirements + +### PKCE Implementation +- Validate `code_challenge_method` is `S256` +- Store `code_challenge` and `code_verifier` association temporarily (Redis, 5-minute expiry) +- Verify SHA-256 hash of `code_verifier` matches stored `code_challenge` during token exchange +- Reject requests without valid PKCE parameters + +### State Validation +- Generate cryptographically secure state parameter +- Store state in session or Redis with 5-minute expiry +- Validate state parameter matches stored value during callback +- Reject requests with state mismatch (CSRF protection) + +### Token Security +- Access tokens: JWT with 1-hour expiry, signed with RS256 +- Refresh tokens: Secure random 128-character strings, stored in database +- Refresh tokens: Single-use or rotation (new refresh token with each refresh) +- Rate limiting on token endpoints (100 requests/hour per IP) +- IP binding for refresh tokens (optional for enhanced security) + +### Scopes and Permissions +- `tenant:read`: Access to tenant data (events, photos, members) +- `tenant:write`: Create/update/delete tenant resources +- `tenant:admin`: Full administrative access (user management, billing) +- Token claims include `tenant_id` and `scope` for authorization + +## Database Schema + +### oauth_clients Table +```sql +CREATE TABLE oauth_clients ( + id VARCHAR(255) PRIMARY KEY, + client_id VARCHAR(255) UNIQUE NOT NULL, + client_secret VARCHAR(255), + redirect_uris TEXT, + scopes TEXT DEFAULT 'tenant:read tenant:write', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); +``` + +### oauth_codes Table (Temporary) +```sql +CREATE TABLE oauth_codes ( + id VARCHAR(255) PRIMARY KEY, + client_id VARCHAR(255) NOT NULL, + user_id VARCHAR(255) NOT NULL, + code VARCHAR(255) UNIQUE NOT NULL, + code_challenge VARCHAR(255) NOT NULL, + state VARCHAR(255), + redirect_uri VARCHAR(255), + scope TEXT, + expires_at TIMESTAMP NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_code (code), + INDEX idx_expires (expires_at) +); +``` + +### refresh_tokens Table +```sql +CREATE TABLE refresh_tokens ( + id VARCHAR(255) PRIMARY KEY, + tenant_id VARCHAR(255) NOT NULL, + token VARCHAR(255) UNIQUE NOT NULL, + access_token VARCHAR(255), + expires_at TIMESTAMP NOT NULL, + scope TEXT, + ip_address VARCHAR(45), + user_agent TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + revoked_at TIMESTAMP NULL, + INDEX idx_tenant (tenant_id), + INDEX idx_token (token), + INDEX idx_expires (expires_at) +); +``` + +### tenant_tokens Table (JWT Blacklist) +```sql +CREATE TABLE tenant_tokens ( + id VARCHAR(255) PRIMARY KEY, + tenant_id VARCHAR(255) NOT NULL, + jti VARCHAR(255) UNIQUE NOT NULL, -- JWT ID + token_type VARCHAR(50) NOT NULL, + expires_at TIMESTAMP NOT NULL, + revoked_at TIMESTAMP NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_jti (jti), + INDEX idx_tenant (tenant_id), + INDEX idx_expires (expires_at) +); +``` + +## API Endpoints + +### Authentication Endpoints +| Endpoint | Method | Description | Authentication | +|----------|--------|-------------|----------------| +| `/oauth/authorize` | GET | Authorization request | None | +| `/oauth/token` | POST | Token exchange/refresh | None | +| `/api/v1/tenant/me` | GET | Validate token | Bearer Token | + +### Protected Endpoints +All tenant API endpoints require `Authorization: Bearer {access_token}` header. + +#### Token Validation Middleware +```javascript +// Pseudocode +function validateTenantToken(req, res, next) { + const token = req.headers.authorization?.replace('Bearer ', ''); + if (!token) return res.status(401).json({ error: 'Missing token' }); + + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const { tenant_id, scope, exp, jti } = decoded; + + // Check if token is blacklisted + const blacklisted = await db.query('SELECT * FROM tenant_tokens WHERE jti = ? AND revoked_at IS NULL', [jti]); + if (blacklisted.length > 0) { + return res.status(401).json({ error: 'Token revoked' }); + } + + // Check expiry + if (Date.now() >= exp * 1000) { + return res.status(401).json({ error: 'Token expired' }); + } + + // Set tenant context + req.tenant = { id: tenant_id, scope }; + next(); + } catch (error) { + res.status(401).json({ error: 'Invalid token' }); + } +} +``` + +## Environment Variables + +### Backend (.env) +``` +JWT_SECRET=your-super-secret-jwt-signing-key +API_BASE_URL=https://api.fotospiel.com +OAUTH_CLIENT_SECRET=your-oauth-client-secret +DATABASE_URL=your-database-connection-string +REDIS_URL=redis://localhost:6379 +``` + +### Frontend (.env) +``` +VITE_API_URL=https://api.fotospiel.com +VITE_OAUTH_CLIENT_ID=tenant-admin-app +``` + +## Error Handling + +### Common Error Responses +```json +// 400 Bad Request +{ + "error": "invalid_request", + "error_description": "Missing required parameter: code" +} + +// 401 Unauthorized +{ + "error": "invalid_token", + "error_description": "Token signature invalid" +} + +// 403 Forbidden +{ + "error": "insufficient_scope", + "error_description": "Scope tenant:write required" +} +``` + +## Implementation Notes + +### 1. PKCE Storage +- Use Redis for temporary code_challenge storage (5-minute TTL) +- Key format: `pkce:{code_challenge}:{client_id}` +- Value: JSON with `code_verifier`, `user_id`, `redirect_uri`, `scope` + +### 2. Refresh Token Rotation +- Issue new refresh token with each refresh +- Revoke old refresh token immediately +- Limit refresh tokens per tenant to 5 active + +### 3. Rate Limiting +- Authorization requests: 10/minute per IP +- Token exchanges: 5/minute per IP +- Token validation: 100/minute per tenant + +### 4. Logging and Monitoring +- Log all authentication attempts (success/failure) +- Monitor token usage patterns +- Alert on unusual activity (multiple failed attempts, token anomalies) +- Track refresh token usage for security analysis + +### 5. Database Cleanup +- Cron job to remove expired authorization codes (daily) +- Remove expired refresh tokens (weekly) +- Clean blacklisted tokens after expiry (daily) + +## Testing Requirements + +### Unit Tests +- PKCE generation and validation +- State parameter security +- Token signing and verification +- Scope validation middleware + +### Integration Tests +- Complete OAuth2 flow (authorize → token → validate) +- Token refresh cycle +- Error scenarios (invalid code, expired tokens, state mismatch) +- Concurrent access testing + +### Security Tests +- CSRF protection validation +- PKCE bypass attempts +- Token replay attacks +- Rate limiting enforcement + +## Deployment Considerations + +### 1. Secrets Management +- Store JWT secret and OAuth client secret in secure vault (AWS Secrets Manager, HashiCorp Vault) +- Rotate secrets every 90 days +- Use different secrets for dev/staging/production + +### 2. Certificate Management +- Use Let's Encrypt or commercial SSL certificates +- Rotate certificates before expiry +- Enable HSTS headers + +### 3. Monitoring +- Track authentication success/failure rates +- Monitor token expiry patterns +- Alert on PKCE validation failures +- Log all security-related events + +This implementation provides secure, scalable authentication for the Fotospiel tenant system, following OAuth2 best practices with PKCE for public clients. \ No newline at end of file diff --git a/docs/prp/14-freemium-business-model.md b/docs/prp/14-freemium-business-model.md new file mode 100644 index 0000000..44e0ee4 --- /dev/null +++ b/docs/prp/14-freemium-business-model.md @@ -0,0 +1,183 @@ +# 14 - Freemium Business Model Implementation + +## Executive Summary + +This document details the Freemium business model for the Fotospiel tenant app, combining free access with in-app purchases for event credits. The model prioritizes user acquisition through a free app download while monetizing through value-driven upgrades. Key metrics: 5-10% conversion rate, ARPU €10-15, scalable to 100k+ users. + +## Model Analysis + +### Model A: Paid App (€4.99) with Free First Event +**Pros:** +- Higher paying user conversion (20-30% retention) +- Premium perception for professional users +- Stable revenue from app sales (70% net after store fees) +- No freeloader problem + +**Cons:** +- Lower acquisition (<5% download conversion) +- High churn if first event doesn't impress +- Slower scaling, higher marketing costs per install (€2-5) + +### Model B: Free App with In-App Purchases (Recommended Base) +**Pros:** +- 10x more downloads, viral potential +- Low acquisition costs (€0.50-1 per install) +- Flexible pricing (starter €4.99, pro €9.99) +- Better App Store ranking for free apps + +**Cons:** +- 80-95% freeloader rate +- Complex IAP setup and testing +- Requires strong onboarding to drive conversions + +### Hybrid Freemium Recommendation +**Core Strategy:** Free app with limited first event (50 photos, basic features), unlimited upgrades via IAP credits/subscriptions. + +**Pricing Structure:** +- **Free Tier:** 1 basic event (50 photos, standard tasks, no custom branding) +- **Consumable Credits:** + - Starter Pack: €4.99 for 5 events (100 photos each) + - Pro Pack: €14.99 for 20 events (unlimited photos) +- **Subscriptions:** + - Pro Unlimited: €4.99/month (all features, unlimited events) + - Agency: €19.99/month (multi-tenant, analytics, white-label) +- **Non-Consumables:** Lifetime Unlimited: €49.99 (one-time purchase) + +**Expected Metrics:** +- Downloads: 50k/year +- Conversion: 5-8% (2,500-4,000 paying users) +- ARPU: €12 (mix of one-time + recurring) +- Annual Revenue: €30,000-48,000 (after 30% store fees) + +## User Acquisition Strategy + +### App Store Optimization (ASO) +- **Keywords:** "Event Foto App", "Hochzeit Galerie", "Party Foto Sharing", "Event Planner kostenlos" +- **Screenshots:** 5-6 screens showing value (event creation, photo upload, QR sharing) +- **Description:** 4,000 chars emphasizing "Free start, upgrade anytime" +- **App Preview Video:** 30s demo of creating/sharing first event + +### Marketing Channels +- **Paid Ads:** Facebook/Instagram targeting wedding planners (€1-2/install) +- **Organic:** Wedding forums, photographer communities, local event groups +- **Partnerships:** Affiliate program for event agencies (20% commission) +- **Content Marketing:** Blog posts "How to create digital photo galleries for events" + +### Retention & Re-engagement +- **Push Notifications:** "Your event ends soon - extend for €2.99" (opt-in only) +- **Email Marketing:** Post-event surveys with upgrade offers +- **In-App Messaging:** Contextual upgrade prompts after value demonstration + +## Conversion Optimization + +### Onboarding Funnel +1. **Download → First Launch:** 90% completion target +2. **Onboarding Wizard → First Event:** 80% completion +3. **First Event Success → Upgrade Prompt:** 10% conversion +4. **Repeat Usage → Subscription:** 20% of one-time buyers + +### A/B Testing Plan +- **CTA Text:** "Get Started Free" vs "Create First Event" +- **Pricing Display:** Static prices vs dynamic local currency +- **Upgrade Timing:** After first photo upload vs after event sharing +- **Tools:** Firebase Remote Config + RevenueCat Experiments + +## Technical Requirements + +### Frontend (React/Capacitor) +- **IAP Integration:** RevenueCat SDK for cross-platform purchases +- **State Management:** Context API for credits, React Query for API sync +- **Offline Support:** Capacitor Storage for temporary event data +- **Analytics:** Firebase for funnel tracking, RevenueCat for purchase events + +### Backend API Extensions +- **Credit Management:** `/api/v1/tenant/credits` endpoints +- **Purchase Validation:** Webhook receiver from RevenueCat +- **Event Limiting:** Middleware checking credit balance before creation +- **Subscription Sync:** Real-time updates via WebSockets (optional) + +### Database Schema Additions +```sql +-- tenant_credits table +CREATE TABLE tenant_credits ( + tenant_id VARCHAR(255) PRIMARY KEY, + balance INTEGER DEFAULT 1, -- 1 free event + total_purchased INTEGER DEFAULT 0, + subscription_active BOOLEAN DEFAULT FALSE, + subscription_tier VARCHAR(50), + last_sync TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- purchase_history table +CREATE TABLE purchase_history ( + id VARCHAR(255) PRIMARY KEY, + tenant_id VARCHAR(255) NOT NULL, + package_id VARCHAR(255) NOT NULL, + credits_added INTEGER, + price DECIMAL(10,2), + currency VARCHAR(3), + platform VARCHAR(50), -- 'ios' or 'android' + transaction_id VARCHAR(255), + purchased_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) +); +``` + +## Risk Mitigation + +### Store Compliance +- **No Paywalls Before Value:** First event creation always free +- **Clear Descriptions:** App Store screenshots show free tier capabilities +- **Receipt Validation:** All purchases server-side verified +- **Refund Policy:** 14-day money-back for subscriptions + +### Technical Risks +- **IAP Failures:** Fallback to manual credit allocation via support +- **Sync Issues:** Offline-first approach, sync on reconnect +- **Store Rejections:** Beta testing with TestFlight/Internal Testing +- **Revenue Recognition:** Use RevenueCat for proper accounting + +### Business Risks +- **Low Conversion:** Monthly A/B testing and user surveys +- **Churn:** Re-engagement campaigns for inactive users +- **Competition:** Regular competitor analysis and feature updates +- **Platform Changes:** Monitor Apple/Google policy updates + +## Launch Timeline + +### Phase 1: MVP (4 weeks) +- Week 1: RevenueCat integration, basic credit system +- Week 2: IAP store page, purchase flow +- Week 3: Backend endpoints, database schema +- Week 4: Testing, beta distribution + +### Phase 2: Optimization (Ongoing) +- Month 1: A/B testing of upgrade prompts +- Month 2: Push notifications, email marketing +- Month 3: Subscription model introduction +- Quarterly: Feature updates based on user feedback + +## Success Metrics + +### Acquisition +- Downloads: 10k in first 3 months +- Cost per Install: <€1.50 +- App Store Rating: >4.5 stars + +### Conversion +- Free → Paid: 5% within 30 days +- First Event → Upgrade: 15% conversion +- Average Order Value: €8-12 + +### Retention +- Day 1 Retention: >40% +- Day 7 Retention: >25% +- Monthly Active Users: 20% of downloads + +### Revenue +- Month 1 Revenue: €1,000-2,000 +- ARPU: €0.50-1.00 overall +- LTV >3x acquisition cost + +This Freemium model balances user acquisition with sustainable revenue growth, leveraging the event-based nature of the app for recurring purchases while maintaining an accessible entry point. \ No newline at end of file diff --git a/docs/prp/tenant-app-specs/README.md b/docs/prp/tenant-app-specs/README.md new file mode 100644 index 0000000..1c7dd7f --- /dev/null +++ b/docs/prp/tenant-app-specs/README.md @@ -0,0 +1,43 @@ +# Detaillierte PRP für Tenant Admin App (Capacitor + Framework7) + +## Status +- **Aktiv**: Erste Version (2025-09-13) +- **Version**: 1.0.0 +- **Autor**: Sonoma (AI Architect) +- **Supersedes**: docs/prp/06-tenant-admin-pwa.md (erweitert und detailliert) + +## Überblick +Diese detaillierte Product Requirement Plan (PRP) beschreibt die Spezifikationen für die Tenant Admin App. Die App ist eine store-ready mobile Anwendung, die mit Capacitor für iOS und Trusted Web Activity (TWA) für Android gepackt wird. Die UI basiert auf Framework7 für ein natives Mobile-Erlebnis. Die App ermöglicht Tenant-Admins (z.B. Event-Organisatoren) die vollständige Verwaltung ihrer Events, Galerien, Mitglieder, Einstellungen und Käufe über eine API-first Backend-Integration. + +Die App ersetzt das frühere Filament-basierte Tenant-Panel und fokussiert auf Mobile-First-UX mit Offline-Fähigkeiten, Push-Notifications und sicherer Authentifizierung. Sie respektiert das Multi-Tenancy-Modell und GDPR-Anforderungen. + +## Kernziele +- **Deliverables**: Voll funktionsfähige App mit CRUD-Operationen für Tenant-Ressourcen (Events, Photos, Tasks, etc.). +- **UI/UX**: Framework7-Komponenten für konsistente, native Mobile-Interfaces (iOS/Android). +- **Technologie-Stack**: React/Vite (Core), Framework7 (UI), Capacitor (Native), OAuth2 + PKCE (Auth). +- **Distribution**: App Store (iOS), Google Play (Android), PWA-Install (Web). + +## Struktur dieser PRP +- **README.md**: Dieser Überblick. +- **functional-specs.md**: Funktionale Anforderungen, Capabilities und API-Integration. +- **pages-ui.md**: Detaillierte Seitenbeschreibungen, Framework7-Komponenten und Wireframe-Ideen. +- **settings-config.md**: App- und Tenant-spezifische Einstellungen, Capacitor-Plugins. +- **capacitor-setup.md**: Packaging, Distribution und Native-Features. + +## Referenzen +- **Haupt-PRP**: docs/prp/README.md +- **Tenancy**: docs/prp/02-tenancy.md +- **API**: docs/prp/03-api.md +- **Bestehende Tenant PWA**: docs/prp/06-tenant-admin-pwa.md +- **Addendum**: docs/prp-addendum-2025-09-08-tenant-admin-pwa.md +- **ADR**: docs/adr/ADR-0006-tenant-admin-pwa.md +- **Billing**: docs/prp/08-billing.md +- **Glossar**: docs/prp/99-glossary.md + +## Änderungen und Erweiterungen +Diese PRP erweitert die knappe Beschreibung in 06-tenant-admin-pwa.md um: +- Spezifische Seiten und UI-Elemente mit Framework7. +- Detaillierte Settings und Capacitor-Integration. +- Mobile-spezifische Features wie Push-Notifications und Offline-Sync. + +Für Feedback oder Änderungen: Siehe TODO.md oder Issues. \ No newline at end of file diff --git a/docs/prp/tenant-app-specs/api-usage.md b/docs/prp/tenant-app-specs/api-usage.md new file mode 100644 index 0000000..913091c --- /dev/null +++ b/docs/prp/tenant-app-specs/api-usage.md @@ -0,0 +1,257 @@ +# API-Nutzung der Tenant Admin App + +Diese Dokumentation beschreibt alle API-Endpunkte, die die Tenant Admin App mit der Backend-Hauptapp kommuniziert. Alle Requests sind tenant-scoped und erfordern JWT-Authentifizierung. + +## Authentifizierung + +### OAuth2 Flow (PKCE) +- **Start**: `GET /oauth/authorize` (Browser-Redirect mit PKCE-Challenge) + - **Params**: `client_id`, `redirect_uri`, `scope=tenant:read tenant:write`, `state`, `code_challenge`, `code_challenge_method=S256` + - **Response**: Authorization Code + +- **Token Exchange**: `POST /oauth/token` + - **Body**: `grant_type=authorization_code`, `client_id`, `code`, `redirect_uri`, `code_verifier` + - **Response**: `{ access_token, refresh_token, expires_in, token_type }` + - **Headers**: `Content-Type: application/x-www-form-urlencoded` + +- **Token Refresh**: `POST /oauth/token` + - **Body**: `grant_type=refresh_token`, `client_id`, `refresh_token` + - **Response**: Neuer Access/Refresh-Token + +- **Token Validation**: `GET /api/v1/tenant/me` + - **Headers**: `Authorization: Bearer {access_token}` + - **Response**: `{ id, email, tenant_id, role, name }` + +## Dashboard + +### Stats laden +- **GET /api/v1/tenant/dashboard** + - **Headers**: `Authorization: Bearer {token}` + - **Response**: `{ credits, active_events, new_photos, task_progress }` + - **Zweck**: Übersicht-Daten für Dashboard-Cards + +## Events + +### Events-Liste +- **GET /api/v1/tenant/events** + - **Headers**: `Authorization: Bearer {token}` + - **Params**: + - `page=1` (Pagination) + - `per_page=50` (max für Mobile) + - `status=draft|active|archived` (Filter) + - `search=query` (Suche in Titel/Ort) + - **Response**: `{ data: Event[], current_page, last_page, total }` + - **Event-Shape**: `{ id, title, date, location, status, photoCount, slug }` + +### Event erstellen +- **POST /api/v1/tenant/events** + - **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json` + - **Body**: `{ title, date, location, description }` + - **Response**: 201 Created mit erstelltem Event + - **Validierung**: Prüft Credit-Balance (1 Credit pro Event) + +### Event-Details +- **GET /api/v1/tenant/events/{id}** + - **Headers**: `Authorization: Bearer {token}` + - **Response**: Erweitertes Event mit `{ tasks[], members, stats { likes, views, uploads } }` + +### Event updaten +- **PATCH /api/v1/tenant/events/{id}** + - **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json`, `If-Match: {etag}` + - **Body**: Partial Event-Daten (title, date, location, description) + - **Response**: Updated Event + +### Event archivieren +- **DELETE /api/v1/tenant/events/{id}** + - **Headers**: `Authorization: Bearer {token}`, `If-Match: {etag}` + - **Response**: 204 No Content (soft-delete) + +## Photos + +### Photos laden +- **GET /api/v1/tenant/events/{event_id}/photos** + - **Headers**: `Authorization: Bearer {token}` + - **Params**: + - `page=1`, `per_page=50` + - `status=pending|approved|rejected|featured` + - `sort=date|likes` + - `since=cursor` (für Infinite Scroll) + - **Response**: `{ data: Photo[], current_page, last_page }` + - **Photo-Shape**: `{ id, eventId, url, thumbnail, uploadedAt, status, likes, views, uploader, etag }` + +### Upload-URL anfordern +- **POST /api/v1/tenant/events/{event_id}/photos** + - **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json` + - **Body**: `{ file_name, description? }` + - **Response**: `{ id, upload_url (S3 signed), thumbnail_url }` + +### Photo moderieren +- **PATCH /api/v1/tenant/photos/{id}** + - **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json`, `If-Match: {etag}` + - **Body**: `{ status: 'approved'|'rejected'|'featured', featured?, reason? }` + - **Response**: Updated Photo + +### Photo löschen +- **DELETE /api/v1/tenant/photos/{id}** + - **Headers**: `Authorization: Bearer {token}`, `If-Match: {etag}` + - **Response**: 204 No Content + +## Members + +### Mitglieder laden +- **GET /api/v1/tenant/events/{event_id}/members** + - **Headers**: `Authorization: Bearer {token}` + - **Params**: `page`, `per_page`, `status=pending|active|invited` + - **Response**: `{ data: Member[], current_page, last_page }` + - **Member-Shape**: `{ id, name, email, role, joinedAt, avatar?, status }` + +### Mitglied einladen +- **POST /api/v1/tenant/events/{event_id}/members** + - **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json` + - **Body**: `{ email, role: 'member'|'guest', name? }` + - **Response**: 201 Created, E-Mail wird versendet + +## Tasks + +### Tasks laden +- **GET /api/v1/tasks** + - **Headers**: `Authorization: Bearer {token}` + - **Params**: + - `global=true/false` (globale vs. tenant Tasks) + - `tenant_id=me` (nur eigene Tasks) + - `category=setup|photo|event|cleanup` + - **Response**: `{ data: Task[], global: boolean }` + - **Task-Shape**: `{ id, title, description?, category, isGlobal, tenantId?, createdAt, color? }` + +### Event-Tasks laden +- **GET /api/v1/tenant/events/{event_id}/tasks** + - **Headers**: `Authorization: Bearer {token}` + - **Response**: `{ data: EventTask[], overall_progress }` + - **EventTask-Shape**: `{ id, eventId, taskId, task: Task, order, completed, assignedTo?, progress }` + +### Tasks bulk zuweisen +- **POST /api/v1/tenant/events/{event_id}/tasks/bulk** + - **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json` + - **Body**: `{ task_ids: string[], order: number[] }` + - **Response**: Updated EventTasks mit neuer Reihenfolge + +## Settings + +### Settings laden +- **GET /api/v1/tenant/settings** + - **Headers**: `Authorization: Bearer {token}` + - **Response**: `{ primaryColor, tenantName, maxEventsPerMonth, enableTasks, enableEmotions, legalPages { impressumUrl, privacyUrl } }` + +### Settings updaten +- **PATCH /api/v1/tenant/settings** + - **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json` + - **Body**: Partial Settings-Daten + - **Response**: Updated Settings + +## Billing + +### Balance laden +- **GET /api/v1/tenant/credits/balance** + - **Headers**: `Authorization: Bearer {token}` + - **Response**: `{ balance: number }` + +### Ledger-Verlauf +- **GET /api/v1/tenant/ledger** + - **Headers**: `Authorization: Bearer {token}` + - **Params**: `page`, `per_page` (Pagination) + - **Response**: `{ data: LedgerEntry[], current_page, last_page }` + - **LedgerEntry**: `{ id, type, amount, credits, date, description, transactionId? }` + +### Kauf-Intent erstellen +- **POST /api/v1/tenant/purchases/intent** + - **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json` + - **Body**: `{ package_id }` + - **Response**: `{ checkout_url: string }` (Stripe-Checkout) + - **Nach dem Kauf**: Webhook-Handling auf Backend für Balance-Update + +## Allgemeine Headers + +Alle API-Requests enthalten: +- **Authorization**: `Bearer {access_token}` (JWT mit tenant_id) +- **Content-Type**: `application/json` (für POST/PATCH) +- **If-Match**: `{etag}` (für Concurrency-Control bei Updates) +- **Accept**: `application/json` + +## Error-Handling + +**Standard-Error-Response:** +```json +{ + "error": { + "code": "INSUFFICIENT_CREDITS", + "message": "Nicht genügend Credits verfügbar" + } +} +``` + +**HTTP Status Codes:** +- 200: Erfolg +- 201: Created +- 400: Bad Request (Validierungsfehler) +- 401: Unauthorized (Token-Refresh wird versucht) +- 403: Forbidden (RBAC-Verletzung) +- 404: Not Found +- 422: Unprocessable Entity +- 429: Rate Limited (Client retry mit Backoff) + +## Pagination + +Alle Listen-Endpunkte unterstützen: +- **page**: Aktuelle Seite (default 1) +- **per_page**: Einträge pro Seite (default 20, max 50 für Mobile) +- **Response**: `{ data: [], current_page, last_page, per_page, total }` + +## Headers für Concurrency + +Mutierende Endpunkte (PATCH/DELETE) erfordern: +- **If-Match**: `{etag}` aus GET-Response +- **Response**: 412 Precondition Failed bei Conflict + +## Sicherheit + +- **Tenant-Isolation**: Alle Endpunkte prüfen JWT-tenant_id gegen request tenant_id +- **RBAC**: Nur tenant_admin kann mutieren, member kann nur lesen/hochladen +- **Rate Limiting**: 100 Requests/Minute pro Tenant +- **ETag**: Automatische Concurrency-Control +- **No PII-Logging**: Keine sensiblen Daten in Logs + +## Testing + +### API-Test-Setup +1. **Backend starten**: Stelle sicher, dass die Hauptapp läuft und Endpunkte verfügbar sind. +2. **Token erzeugen**: Verwende Postman mit gültigem Access-Token. +3. **Endpoints testen**: Jeder Endpunkt einzeln mit curl oder Postman. + +### Beispiel curl (mit Token) +```bash +curl -H "Authorization: Bearer {token}" \ + -H "Content-Type: application/json" \ + https://api.fotospiel.com/api/v1/tenant/events +``` + +### Frontend-Test +1. `.env` mit korrekter API-URL konfigurieren. +2. `npm run dev` starten. +3. Browser-Network-Tab überprüfen für API-Calls. + +## Deployment + +### Environment-Variablen +- **REACT_APP_API_URL**: Backend-API-URL (Pflicht) +- **REACT_APP_OAUTH_CLIENT_ID**: OAuth-Client-ID (Pflicht) + +### Build & Deploy +1. **Development**: `npm run dev` +2. **Production**: `npm run build` +3. **Vorschau**: `npm run preview` + +### PWA-Installation +- App ist PWA-fähig (Manifest, Service Worker). +- Installierbar auf Desktop/Mobile via "Zum Startbildschirm hinzufügen". + +Für weitere Details siehe die spezifischen Dokumentationsdateien. \ No newline at end of file diff --git a/docs/prp/tenant-app-specs/capacitor-setup.md b/docs/prp/tenant-app-specs/capacitor-setup.md new file mode 100644 index 0000000..b6645b7 --- /dev/null +++ b/docs/prp/tenant-app-specs/capacitor-setup.md @@ -0,0 +1,155 @@ +# Capacitor Setup für die Tenant Admin App + +## Status +- **Version**: 1.0.0 (2025-09-13) +- **Fokus**: Mobile Packaging, Distribution und Native-Integration basierend auf ADR-0006. + +## Überblick +Die Tenant Admin App wird als Progressive Web App (PWA) entwickelt und mit Capacitor für native Mobile-Distribution gepackt. Dies ermöglicht: +- **Android**: Trusted Web Activity (TWA) für Chrome-basierte Installation (Google Play) oder voller Capacitor-Build bei Bedarf an Native APIs. +- **iOS**: Capacitor-App für App Store-Distribution mit Push-Notifications und Keychain-Support. +- **Web/PWA**: Fallback für Browser-Installation (A2HS) mit Service Worker. + +Der Build-Prozess integriert sich in das bestehende Vite-Setup (resources/js/admin). Nach `npm run build` wird `npx cap sync` ausgeführt, um die Web-Assets in native Projekte zu kopieren. + +## Projektstruktur +``` +apps/admin-pwa/ # React/Vite Source (Haupt-App) +├── src/ # Components, Pages, API +├── vite.config.ts # Framework7 + Capacitor-Integration +├── capacitor.config.ts # Native Config +├── android/ # Capacitor Android-Projekt (TWA oder App) +├── ios/ # Capacitor iOS-Projekt (Xcode) +└── package.json # Dependencies (framework7, @capacitor/*) + +packages/mobile/ # Shared Native-Config (optional) +├── fastlane/ # iOS/Android Deployment +├── assetlinks.json # TWA Digital Asset Links +└── privacy-manifest.json # iOS Privacy +``` + +## Packaging und Build-Prozess + +### 1. Vite + Framework7 Setup +- **Dependencies**: `framework7`, `framework7-react`, `@capacitor/core`, `@capacitor/cli`. +- **vite.config.ts** (Auszug): + ```typescript + import { defineConfig } from 'vite'; + import react from '@vitejs/plugin-react'; + import { framework7 } from 'framework7/vite'; + + export default defineConfig({ + plugins: [react(), framework7()], + build: { + outDir: 'dist', + sourcemap: true, + }, + define: { + __CAPACITOR__: true, // Enable Capacitor globals + }, + }); + ``` +- **Build-Skript** (package.json): `"build": "vite build && npx cap sync"`. + +### 2. Capacitor Initialisierung +- **Befehle**: + ``` + npx cap init com.fotospiel.tenantadmin "Event Photo Admin" + npx cap add android + npx cap add ios + npx cap sync # Kopiert dist/ in native Projekte + ``` +- **capacitor.config.ts** (siehe settings-config.md für erweiterte Plugins). + +### 3. Android Packaging (TWA bevorzugt) +- **Trusted Web Activity (TWA)**: Für store-ready Distribution ohne vollen Native-Wrapper. + - **Voraussetzungen**: App bound an `admin.fotospiel.app` (HTTPS); Digital Asset Links. + - **assetlinks.json** (public/.well-known/assetlinks.json): + ```json + [{ + "relation": ["delegate_permission/common.handle_all_urls"], + "target": { + "namespace": "android_app", + "package_name": "com.fotospiel.tenantadmin", + "sha256_cert_fingerprints": ["DE:AD:BE:EF:..."] // Von Play Console + } + }] + ``` + - **Build**: `npx cap open android` → Android Studio → Generate Signed Bundle (AAB für Play Store). + - **Vorteile**: Kleiner Footprint, Web-Push via Chrome; Fallback zu Capacitor bei Bedarf (z.B. Biometrie). + - **TWA-Tools**: `npm i -g @bubblewrap/cli` → `bubblewrap init --manifest=https://admin.fotospiel.app/manifest.json`. + +- **Vollständiger Capacitor-Build** (falls Native-Plugins benötigt): + - `npx cap sync android` + - `npx cap open android` → Build APK/AAB mit ProGuard. + +### 4. iOS Packaging (Capacitor) +- **Xcode-Setup**: `npx cap open ios` → Signing mit Apple Developer Account. +- **Privacy Manifest** (ios/App/App/PrivacyInfo.xcprivacy): + ```xml + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + + + + ``` +- **Build**: Archive in Xcode → Upload zu App Store Connect. +- **Entitlements**: Push-Notifications (APNs), Background App Refresh für Sync. + +### 5. Distribution und CI/CD +- **Google Play**: + - **TWA**: Internal Testing Track; Target SDK 34+; Feature: Installable. + - **Fastlane**: `packages/mobile/fastlane/android` mit `supply` für Metadata/Screenshots. + - **Versioning**: Align mit Backend (z.B. 1.0.0); Feature Flags via API. + +- **Apple App Store**: + - **Capacitor**: Review-Guidelines beachten (HTTPS-only, No Crash-Reporting ohne Consent). + - **Fastlane**: `packages/mobile/fastlane/ios` mit `deliver` für Upload. + - **Privacy**: Usage Descriptions in Info.plist (z.B. "Kamera für QR-Scans"). + +- **PWA-Fallback** (Web): + - **manifest.json**: `start_url: '/admin/'`, `display: 'standalone'`. + - **Service Worker**: Caching von Assets; Background Sync für Mutations. + - **Distribution**: Hosting auf `admin.fotospiel.app` mit A2HS-Prompt. + +### Native Features (Erweiterung zu settings-config.md) +- **Push-Notifications**: + - **Android**: FCM-Integration; Token an Backend (`POST /tenant/push-tokens`). + - **iOS**: APNs; Silent-Pushes für Sync-Triggers. + - **Cross-Platform**: Capacitor Push-Plugin handhabt Plattform-Unterschiede. + +- **Secure Storage**: + - **Tokens**: Capacitor Preferences mit Auto-Encryption. + - **Offline Data**: IndexedDB (Web) + Native Storage; Encryption via Web Crypto API. + +- **Background Processing**: + - **Sync**: Capacitor App-State-Listener für Foreground/Background; Queue Mutations. + - **iOS**: Background Fetch (via Plugin); Android: WorkManager für periodische Syncs. + +- **Biometrie (optional)**: `@capacitor-community/biometric-auth` für App-Lock. + +### Testing und Deployment +- **E2E-Tests**: Cypress für Web; Detox/Appium für Native (z.B. Push-Handling). +- **CI/CD**: GitHub Actions oder Gogs-Integration (siehe docs/prp/11-ops-ci-cd.md). + - Steps: Build → Test → Cap Sync → Fastlane Deploy (Staging → Production). +- **Version Alignment**: App-Version matcht Backend-API-Version; Changelog in Store-Listing. + +### Constraints & Red-Lines +- **GDPR**: Keine implizite Tracking; Explizite Consent für Push/Camera. +- **Security**: HTTPS-only; Token-Rotation alle 24h; No Jailbreak-Detection. +- **Performance**: Bundle-Size < 10MB (Web-Assets komprimiert); Lazy-Loading. + +Diese Setup ergänzt die funktionalen Specs und UI-Beschreibungen. Für Repo-Integration siehe ADR-0006. \ No newline at end of file diff --git a/docs/prp/tenant-app-specs/functional-specs.md b/docs/prp/tenant-app-specs/functional-specs.md new file mode 100644 index 0000000..5767aca --- /dev/null +++ b/docs/prp/tenant-app-specs/functional-specs.md @@ -0,0 +1,100 @@ +# Funktionale Spezifikationen für die Tenant Admin App + +## Status +- **Version**: 1.0.0 (2025-09-13) +- **Supersedes**: Teile von docs/prp/06-tenant-admin-pwa.md und docs/prp-addendum-2025-09-08-tenant-admin-pwa.md + +## Deliverables +Die Tenant Admin App muss folgende Kernfunktionen bereitstellen: +- **Event-Management**: CRUD-Operationen für Events (Erstellen, Bearbeiten, Archivieren, Veröffentlichen). +- **Gallery-Management**: Hochladen, Moderieren, Featured-Setten von Photos; Thumbnail-Generierung. +- **Member-Management**: Hinzufügen/Entfernen von Event-Mitgliedern; Rollen (Admin, Member). +- **Task & Emotion Management**: Zuweisen von Tasks und Emotions zu Events; Overrides für Tenant-spezifische Bibliotheken. +- **Settings-Management**: Tenant-spezifische Einstellungen (Theme, Limits, Legal Pages). +- **Billing & Purchases**: Kaufen von Event-Credits; Ledger-Übersicht; Integration mit Stripe. +- **Notifications**: Push-Benachrichtigungen für neue Photos, Event-Updates, niedrigen Credit-Balance. +- **Offline-Support**: Caching von Events und Photos; Queuing von Uploads/Mutations mit Sync bei Online-Wiederkehr. +- **Audit & Compliance**: Logging kritischer Aktionen; ETag-basierte Conflict-Resolution; GDPR-konforme Datenlöschung. + +Die App ist API-first und interagiert ausschließlich über den Backend-API-Endpunkt `/api/v1/tenant/*`. + +## Capabilities +### Authentifizierung & Autorisierung +- **OAuth2 Flow**: Authorization Code + PKCE für sichere Token-Erfassung. +- **Token-Management**: Refresh-Tokens mit automatischer Rotation; Secure Storage (Keychain/Keystore). +- **Tenant-Scoping**: Alle Requests enthalten `tenant_id` aus Token; Backend-Policies enforcen Isolation. +- **Roles**: Unterstützung für `tenant_admin` (volle CRUD), `member` (read-only + Uploads). + +### Core Features +- **Event Lifecycle**: + - Erstellen: Erfordert mind. 1 Event-Credit; Slug-Generierung (unique pro Tenant). + - Bearbeiten: Update von Datum, Ort, Tasks, Emotions, Join-Link. + - Veröffentlichen: Generiert QR-Code und Share-Link; aktiviert Guest-PWA-Zugriff. + - Archivieren: Soft-Delete mit Retention-Periode (GDPR); Credit-Rückerstattung optional. +- **Photo Management**: + - Upload: Signed URLs für direkte S3-Uploads; automatisierte Thumbnail-Generierung. + - Moderation: Approve/Reject/Feature; Bulk-Operations. + - Analytics: Stats zu Likes, Views, Uploads pro Event. +- **Task & Emotion System**: + - Bibliothek: Globale + Tenant-spezifische Tasks/Emotions. + - Zuweisung: Drag-and-Drop zu Events; Fortschritts-Tracking. +- **Billing Integration**: + - Credit-Balance: Anzeige und Kauf von Packs (z.B. 5 Events für 29€). + - Ledger: Historie von Käufen, Consumptions, Refunds. + - Stripe-Checkout: Server-side Intent-Erstellung; Webhook-Handling für Confirmation. + +### Offline & Sync +- **Service Worker**: Cache von App-Shell, Events, Photos (Cache-Control: max-age=5min für dynamische Daten). +- **Background Sync**: Queued Mutations (z.B. Photo-Approvals) syncen bei Connectivity. +- **Conflict Resolution**: ETag/If-Match Headers; Optimistic Updates mit Rollback bei Conflicts. + +### Error Handling & UX +- **Rate Limits**: 429-Responses handhaben mit Retry-Logic und User-Feedback ("Zu viele Anfragen, versuche es später"). +- **Offline Mode**: Degradiertes UI (Read-Only); Sync-Status-Indikator. +- **i18n**: Unterstützung für de/en; Locale aus User-Profile. + +## API-Integration +Die App konsumiert den API-Contract aus docs/prp/03-api.md. Schlüssel-Endpunkte: + +### Auth +- `POST /oauth/token`: PKCE-Code für Access/Refresh-Token. +- `POST /oauth/token/refresh`: Token-Rotation. + +### Events +- `GET /tenant/events`: Liste (paginiert, filterbar nach Status/Datum). +- `POST /tenant/events`: Erstellen (validiert Credit-Balance). +- `GET /tenant/events/{id}`: Details inkl. Tasks, Stats. +- `PATCH /tenant/events/{id}`: Update (ETag für Concurrency). +- `DELETE /tenant/events/{id}`: Archivieren. + +### Photos +- `GET /tenant/events/{event_id}/photos?since={cursor}`: Inkrementelle Liste. +- `POST /tenant/events/{event_id}/photos`: Metadata + signed Upload-URL. +- `PATCH /tenant/photos/{id}`: Moderation (approve, feature). +- `DELETE /tenant/photos/{id}`: Löschung mit Audit. + +### Tasks & Emotions +- `GET /tenant/tasks`: Tenant-Overrides + globale Bibliothek. +- `POST /tenant/events/{id}/tasks`: Zuweisung. +- Ähnlich für Emotions. + +### Settings +- `GET /tenant/settings`: Tenant-Konfig (Theme, Limits, Legal-Links). +- `PATCH /tenant/settings`: Update. + +### Billing +- `GET /tenant/ledger`: Credit-Historie. +- `POST /tenant/purchases/intent`: Stripe-Checkout-Session erstellen. +- `GET /tenant/credits/balance`: Aktueller Stand. + +### Pagination & Errors +- Standard: `page`, `per_page` (max 50 für Mobile). +- Errors: Parsen von `{ error: { code, message } }`; User-freundliche Messages (z.B. "Nicht genug Credits"). + +## Non-Functional Requirements +- **Performance**: Ladezeiten < 2s; Lazy-Loading für Galleries. +- **Sicherheit**: Kein PII-Logging; Token-Expiration-Handling; CSRF-Schutz via PKCE. +- **Accessibility**: Framework7 ARIA-Support; Dark Mode (System-Preference). +- **Testing**: Unit-Tests für API-Calls; E2E-Tests für Flows (Cypress). + +Für detaillierte UI-Seiten siehe pages-ui.md; für Settings siehe settings-config.md. \ No newline at end of file diff --git a/docs/prp/tenant-app-specs/pages-ui.md b/docs/prp/tenant-app-specs/pages-ui.md new file mode 100644 index 0000000..ffe7774 --- /dev/null +++ b/docs/prp/tenant-app-specs/pages-ui.md @@ -0,0 +1,186 @@ +# Seiten und UI-Design für die Tenant Admin App + +## Status +- **Version**: 1.0.0 (2025-09-13) +- **Fokus**: Mobile-First Design mit Framework7 v8+ für native iOS/Android-Look & Feel. + +## Allgemeines UI-Prinzipien +- **Framework7-Komponenten**: Toolbar (Navigation), List (Datenlisten), Card (Karten für Events/Photos), Modal (Details/Actions), Pull-to-Refresh (Sync), Infinite-Scroll (Pagination). +- **Theming**: System-Dark-Mode-Support; Tenant-spezifische Farben (Primary/Secondary aus Settings). +- **Navigation**: Tabbar unten (Dashboard, Events, Photos, Settings); Side-Menu für Profile/Logout. +- **Offline-Indikator**: Banner oben ("Offline-Modus: Änderungen werden synchronisiert"). +- **Loading**: Spinner für API-Calls; Skeleton-Screens für Listen. +- **i18n**: Rechts-nach-Links für de/en; Icons von Framework7-Icons (Material). + +## Benötigte Seiten und Komponenten + +### 1. Auth-Seiten (OAuth-Flow) +#### Login-Seite +- **Zweck**: OAuth-Authorization (PKCE-Challenge generieren, Redirect zu /oauth/authorize). +- **Layout**: + - Zentrale Card mit Logo, App-Name, "Mit Google/Email anmelden"-Buttons. + - Footer: "Noch kein Account? Registrieren" (Redirect zu Register). +- **Framework7-Komponenten**: + - `f7-page` mit `f7-navbar` (Titel: "Willkommen zur Event Photo App"). + - `f7-block` für Content; `f7-button` (large, filled) für OAuth-Start. + - `f7-preloader` während Redirect. +- **Wireframe-Beschreibung**: + ``` + [Navbar: Logo | Willkommen] + [Block: App-Beschreibung] + [Button: Anmelden mit Google] + [Button: Anmelden mit Email] + [Footer: Registrieren-Link] + ``` +- **API**: Kein direkter Call; Browser-Redirect zu Backend. + +#### Register-Seite (ähnlich Login) +- **Unterschiede**: Form für Email/Password + Terms-Checkbox; Submit zu `/oauth/register`. + +### 2. Dashboard (Home) +- **Zweck**: Übersicht über aktive Events, Stats, schnelle Actions. +- **Layout**: + - Top: Willkommens-Banner mit Tenant-Name, Credit-Balance. + - Stats-Cards: Aktive Events, Ungeprüfte Photos, Tasks-Fortschritt. + - Quick-Actions: "Neues Event erstellen", "Photos moderieren". +- **Framework7-Komponenten**: + - `f7-toolbar` unten: Tabs (Home, Events, Photos, Settings). + - `f7-card` für Stats (mit `f7-icon` und Zahlen). + - `f7-list` für Quick-Actions (link mit Arrow). + - `f7-pull-to-refresh` für Sync. +- **Wireframe-Beschreibung**: + ``` + [Toolbar: Home | Events | Photos | Settings] + [Banner: Hallo [Name]! 3 Credits übrig] + [Row: Card(Events: 2 aktiv) | Card(Photos: 15 neu) | Card(Tasks: 80%)] + [List: > Neues Event | > Moderieren | > Einstellungen] + ``` +- **API**: `GET /tenant/dashboard` (Stats); `GET /tenant/credits/balance`. + +### 3. Events-Übersicht +- **Zweck**: Liste aller Events mit Filter (aktiv/archiviert), Suche. +- **Layout**: + - Navbar: Suche-Feld, Filter-Button (Dropdown: Status, Datum). + - Infinite-Scroll-Liste von Event-Cards (Titel, Datum, Status-Tag, Photo-Count). + - FAB: "+" für Neues Event. +- **Framework7-Komponenten**: + - `f7-searchbar` in Navbar. + - `f7-list` mit `f7-list-item` (Thumbnail, Title, Subtitle: Datum, Badge: Status). + - `f7-fab` (floating action button). + - `f7-segmented` für Filter-Tabs. +- **Wireframe-Beschreibung**: + ``` + [Navbar: Suche | Filter ▼] + [Segmented: Alle | Aktiv | Archiviert] + [List-Item: [Thumb] Hochzeit Müller (15.09.) [Tag: Aktiv] 45 Photos] + [List-Item: ...] + [+ FAB unten rechts] + ``` +- **API**: `GET /tenant/events?page=1&status=active` (paginiert). + +### 4. Event-Details-Seite +- **Zweck**: Vollständige Event-Info, Edit-Modus, zugehörige Tasks/Photos. +- **Layout**: + - Tabs: Details, Tasks, Photos, Members, Stats. + - Edit-Button (öffnet Modal für Update). + - QR-Code-Section für Join-Link. +- **Framework7-Komponenten**: + - `f7-tabs` mit `f7-tab` für Subseiten. + - `f7-card` für Details (Datum, Ort, Beschreibung). + - `f7-qrcode` (via Plugin) für Share-Link. + - `f7-button` (edit-icon) → `f7-modal` mit Form. +- **Wireframe-Beschreibung**: + ``` + [Navbar: Event-Titel | Edit-Icon] + [Tabs: Details | Tasks | Photos | Members | Stats] + [Details-Tab: Card(Datum: 15.09., Ort: Berlin) | QR-Code: Scan zum Beitreten] + [Tasks-Tab: Checklist (Drag-to-reorder)] + [Photos-Tab: Grid von Thumbs] + ``` +- **API**: `GET /tenant/events/{id}`; `PATCH /tenant/events/{id}` (ETag). + +### 5. Photo-Gallery-Seite (pro Event) +- **Zweck**: Moderation von Photos; Grid-View mit Lightbox. +- **Layout**: + - Filter: Neu/Ungeprüft/Featured; Sortierung (Datum, Likes). + - Masonry-Grid von Photo-Cards (Thumb, Timestamp, Like-Count). + - Long-Press: Multi-Select für Bulk-Actions (Approve/Delete). +- **Framework7-Komponenten**: + - `f7-photoset` oder custom Grid mit `f7-card` (small). + - `f7-lightbox` für Fullscreen-View. + - `f7-checkbox` für Multi-Select. + - `f7-popover` für Actions (Approve, Feature, Delete). +- **Wireframe-Beschreibung**: + ``` + [Navbar: Photos (Event) | Filter ▼] + [Grid: 3xN Cards [Thumb | Zeit | Likes] [Checkbox]] + [Lightbox: Fullscreen Photo mit Zoom, Actions] + [Bottom-Bar (bei Select): Approve All | Delete Selected] + ``` +- **API**: `GET /tenant/events/{id}/photos`; `PATCH /tenant/photos/{id}` (Batch). + +### 6. Members-Seite +- **Zweck**: Verwalten von Event-Mitgliedern (Hinzufügen per Email, Rollen). +- **Layout**: Liste von User-Cards (Name, Rolle, Joined-At); Invite-Button. +- **Framework7-Komponenten**: + - `f7-list` mit `f7-list-item` (Avatar, Name, Badge: Rolle). + - `f7-modal` für Invite-Form (Email-Input, Send-Button). +- **Wireframe-Beschreibung**: + ``` + [Navbar: Members | + Invite] + [List: Anna (Admin) | Ben (Member) | ...] + [Modal: Email eingeben | Rolle wählen | Senden] + ``` +- **API**: `GET /tenant/events/{id}/members`; `POST /tenant/events/{id}/members`. + +### 7. Tasks-Seite +- **Zweck**: Bibliothek verwalten, zu Events zuweisen, Fortschritt tracken. +- **Layout**: Tabs: Meine Tasks, Bibliothek; Drag-and-Drop zwischen Listen. +- **Framework7-Komponenten**: + - `f7-tabs`; `f7-sortable-list` für Drag-and-Drop. + - `f7-checkbox` für Zuweisung. +- **Wireframe-Beschreibung**: + ``` + [Tabs: Events | Bibliothek] + [Sortable List: Task1 [Checkbox] | Task2 ...] + [Drag: Von Bibliothek zu Event-Liste] + ``` +- **API**: `GET /tenant/tasks`; `POST /tenant/events/{id}/tasks`. + +### 8. Settings-Seite +- **Zweck**: Tenant-Einstellungen bearbeiten (Theme, Limits, Legal). +- **Layout**: Accordion-Sections (Theme, Notifications, Legal, App). +- **Framework7-Komponenten**: + - `f7-accordion` für Sections. + - `f7-toggle`, `f7-select`, `f7-color-picker` für Optionen. +- **Wireframe-Beschreibung**: + ``` + [Navbar: Einstellungen] + [Accordion: Theme ▼ [Color-Picker] | Notifications [Toggle Push]] + [Legal: Impressum-Link bearbeiten] + [App: Logout-Button] + ``` +- **API**: `GET/PATCH /tenant/settings`. Details in settings-config.md. + +### 9. Billing-Seite +- **Zweck**: Credit-Balance anzeigen, Packs kaufen. +- **Layout**: Balance-Card; Liste von Purchase-Options; Ledger-Historie. +- **Framework7-Komponenten**: + - `f7-card` für Balance (mit Warning bei niedrig). + - `f7-list` für Packs (Preis, Events-Count, Buy-Button). + - `f7-infinite-scroll` für Ledger. +- **Wireframe-Beschreibung**: + ``` + [Card: Balance: 3 Credits | [Warning: Niedrig!]] + [List: 5 Events (29€) [Buy] | 10 Events (49€) [Buy]] + [Ledger: Kauf 29.09. +5 | Event-Erstellung -1] + ``` +- **API**: `GET /tenant/credits/balance`; `POST /tenant/purchases/intent`. + +## Zusätzliche UI-Elemente +- **Modals**: Confirm-Delete, Photo-Preview, Error-Alerts. +- **Notifications**: `f7-notification` für Sync-Erfolg, neue Photos. +- **Offline-Handling**: `f7-block` mit "Syncing..." Progress-Bar. +- **Accessibility**: ARIA-Labels für alle interaktiven Elemente; VoiceOver-Support. + +Für Capacitor-spezifische UI-Anpassungen siehe capacitor-setup.md. \ No newline at end of file diff --git a/docs/prp/tenant-app-specs/settings-config.md b/docs/prp/tenant-app-specs/settings-config.md new file mode 100644 index 0000000..85198cd --- /dev/null +++ b/docs/prp/tenant-app-specs/settings-config.md @@ -0,0 +1,124 @@ +# Settings und Konfiguration für die Tenant Admin App + +## Status +- **Version**: 1.0.0 (2025-09-13) +- **Fokus**: App-interne und tenant-spezifische Einstellungen; Integration mit Capacitor-Plugins. + +## App-interne Settings +Diese Settings werden lokal in der App gespeichert (via Capacitor Preferences oder IndexedDB) und beeinflussen das Verhalten der App: + +### Core App Settings +- **language**: String (default: 'de') – UI-Sprache; Sync mit User-Locale. +- **themeMode**: String ('system' | 'light' | 'dark') – Dark Mode-Präferenz; Framework7-Theming. +- **offlineMode**: Boolean (default: true) – Aktiviert Offline-Caching und Background-Sync. +- **pushNotifications**: Boolean (default: true) – Erlaubt Push-Registrierung. +- **autoSyncInterval**: Number (default: 300) – Sekunden bis automatischer Sync (min: 60). +- **maxPhotoCache**: Number (default: 100) – Anzahl gecachter Photos pro Event. + +### User-spezifische Settings +- **notificationPreferences**: Object + - `newPhotos`: Boolean – Benachrichtigung bei neuen Uploads. + - `eventUpdates`: Boolean – Bei Event-Änderungen (z.B. Veröffentlicht). + - `lowCredits`: Boolean – Warnung bei < 2 Credits. +- **privacySettings**: Object + - `shareAnalytics`: Boolean (default: false) – Anonyme Stats teilen. + - `dataRetention`: Number (default: 30) – Tage bis Auto-Delete von Cache. + +**Speicherung**: Capacitor Preferences API (`@capacitor/preferences`) für sichere, persistente Speicherung. Bei Web-Fallback: localStorage mit Encryption (via Crypto API). + +## Tenant-spezifische Optionen +Diese werden über API (`GET/PATCH /tenant/settings`) geladen und überschreiben globale Defaults. Sie definieren das Verhalten für den Tenant und seine Events: + +### Theme & Branding +- **primaryColor**: String (default: '#007AFF') – Hauptfarbe (iOS-Blau); verwendet in Framework7 CSS-Vars (`--f7-primary`). +- **secondaryColor**: String (default: '#5856D6') – Sekundärfarbe für Buttons/Accents. +- **logoUrl**: String – Custom Logo für App-Banner (URL zu S3/CDN). +- **tenantName**: String – Anzeigename (z.B. "Müller Hochzeit"); in Dashboard-Banner. + +### Event Limits & Features +- **maxEventsPerMonth**: Number (default: 5) – Limit pro Monat (enforced via Credits). +- **maxPhotosPerEvent**: Number (default: 1000) – Soft-Limit; Warnung bei Überschreitung. +- **enableTasks**: Boolean (default: true) – Tasks-System aktivieren. +- **enableEmotions**: Boolean (default: true) – Emotions/Reactions erlauben. +- **autoApprovePhotos**: Boolean (default: false) – Neue Uploads sofort freigeben (Risiko: Spam). + +### Legal & Compliance +- **legalPages**: Object (von Backend geladen, siehe docs/prp/02-tenancy.md) + - `impressumUrl`: String – Pflicht in DE; Customizable Link. + - `privacyUrl`: String – Datenschutzerklärung. + - `agbUrl`: String – Allgemeine Geschäftsbedingungen. +- **gdprRetentionDays**: Number (default: 30) – Automatische Löschung alter Photos/Events. +- **contactEmail**: String – Support-Email für In-App-Feedback. + +### Notifications & Integration +- **pushEnabled**: Boolean – Tenant-weit Push aktivieren (erfordert Plugin-Registrierung). +- **stripePublicKey**: String – Für Client-side Checkout (aus Env, nicht persistent). +- **eventJoinDomain**: String (default: 'events.fotospiel.app') – Custom Domain für Guest-PWA. + +**API-Handling**: Laden bei Login; Cache mit ETag; Update triggert UI-Refresh (z.B. Theme-Wechsel). Validation: Backend enforct Limits (z.B. Colors als HEX). + +## Capacitor-Plugins +Die App integriert folgende Plugins für native Features. Installation via `npx cap add` und Sync nach Build. + +### Essentielle Plugins +1. **@capacitor/preferences** (v6+) + - **Zweck**: Sichere Speicherung von App- und User-Settings. + - **Usage**: `Preferences.set({ key: 'themeMode', value: 'dark' })`; Migrate von localStorage. + - **iOS/Android**: Keychain/Keystore für Encryption. + +2. **@capacitor/push-notifications** (v6+) + - **Zweck**: Native Push für neue Photos, Event-Updates, Low-Credits. + - **Setup**: Registrierung bei App-Start (`PushNotifications.register()`); Token an Backend senden (`POST /tenant/devices`). + - **Events**: `registrationToken` (senden), `pushNotificationReceived` (In-App-Handling), `pushNotificationActionPerformed` (Tap-Actions). + - **Permissions**: Request bei erstem Login; Fallback zu Web Push in PWA/TWA. + +3. **@capacitor/storage** (v6+) + - **Zweck**: Offline-Caching von Events/Photos (als Alternative zu IndexedDB). + - **Usage**: `Storage.set({ key: 'event-123', value: JSON.stringify(data) })`; Size-Limit beachten (50MB). + - **Fallback**: Für Web; Sync mit Background-Sync. + +4. **@capacitor/camera** (v6+) + - **Zweck**: Direkte Kamera-Zugriff für Event-QR-Scans oder schnelle Photo-Uploads (Admin-Selfies). + - **Usage**: `Camera.getPhoto({ quality: 90, allowEditing: true })`; Upload via signed URL. + - **Permissions**: Camera/Mic; Privacy-Manifest für App Store. + +5. **@capacitor/network** (v6+) + - **Zweck**: Connectivity-Status überwachen; Offline-Modus triggern. + - **Usage**: `Network.addListener('networkStatusChange', handleOffline)`; UI-Update bei 'offline'. + - **Integration**: Deaktiviere Sync-Buttons; Zeige Cached-Data. + +### Optionale Plugins +- **@capacitor/haptics** (v6+): Vibration-Feedback bei Actions (z.B. Photo-Approve). +- **@capacitor/share** (v6+): Teilen von Event-QR-Codes via Native Share-Sheet. +- **@capacitor/device** (v6+): Geräte-Info (Model, OS) für Analytics; Token zu Backend. + +### Plugin-Konfiguration (capacitor.config.ts) +```typescript +import { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + appId: 'com.fotospiel.tenantadmin', + appName: 'Event Photo Admin', + webDir: 'dist', + bundledWebRuntime: false, + plugins: { + PushNotifications: { + presentationOptions: ["badge", "sound", "alert"] + }, + Camera: { + permissions: { + camera: true + } + } + } +}; + +export default config; +``` + +### Security & Privacy +- **Plugin-Permissions**: Explizite Requests; Erkläre Zweck im Onboarding (z.B. "Push für neue Photos"). +- **Data Storage**: Kein PII in Preferences; Tokens encrypted (siehe Auth-Specs). +- **App Store Compliance**: Privacy Manifest mit Usage-Descriptions (z.B. NSPhotoLibraryUsageDescription). + +Für detailliertes Packaging siehe capacitor-setup.md; UI-Integration in pages-ui.md. \ No newline at end of file