huge documentaton restructure for docusaurus
This commit is contained in:
@@ -81,7 +81,7 @@ apps/guest-pwa/
|
||||
usePollStats.ts // polls /events/:slug/stats every 10s
|
||||
usePollGalleryDelta.ts // polls /events/:slug/photos?since=...
|
||||
i18n/
|
||||
config.ts // i18next init with react-i18next, backend loadPath '/lang/{{lng}}/guest.json'
|
||||
config.ts // i18next init with react-i18next, backend loadPath '/lang/\{\{lng\}\}/guest.json'
|
||||
de.json // Namespace: guest (e.g., { "gallery": { "title": "Galerie" } })
|
||||
en.json
|
||||
main.tsx
|
||||
@@ -146,7 +146,7 @@ State & Data
|
||||
- TanStack Query for server data (events, photos); optimistic updates for likes.
|
||||
- Zustand store for local-only state (profile, queue, banners).
|
||||
- IndexedDB for upload queue; CacheStorage for shell/assets.
|
||||
- i18n: react-i18next; load 'guest' namespace JSON from /lang/{locale}/guest.json; path-based detection for /de/e/:slug, /en/e/:slug; useTranslation('guest') in components.
|
||||
- i18n: react-i18next; load 'guest' namespace JSON from /lang/\{locale\}/guest.json; path-based detection for /de/e/:slug, /en/e/:slug; useTranslation('guest') in components.
|
||||
- Polling: focus-aware intervals (10s stats, 30s gallery); use document visibility to pause; backoff on failures.
|
||||
|
||||
Accessibility & Performance
|
||||
|
||||
@@ -32,14 +32,14 @@ Core Features
|
||||
- Masonry grid, lazy-load, pull-to-refresh; open photo lightbox with swipe.
|
||||
- Like (heart) with optimistic UI; share system sheet (URL to CDN variant).
|
||||
- Filters: emotion, featured, mine (local-only tag for items uploaded from this device).
|
||||
- Public share: host can hand out `https://app.domain/g/{token}`; guests see a themed, read-only gallery with per-photo downloads.
|
||||
- Public share: host can hand out `https://app.domain/g/\{token\}`; guests see a themed, read-only gallery with per-photo downloads.
|
||||
- Banner on gallery header highlights approaching expiry (D-7/D-1) and offers CTA to upload remaining shots before the deadline.
|
||||
- Safety & abuse controls
|
||||
- Rate limits per device and IP; content-length checks; mime/type sniffing.
|
||||
- Upload moderation state: pending → approved/hidden; show local status.
|
||||
- Notification Center
|
||||
- Header bell opens a drawer that merges upload queue stats with server-driven notifications (photo highlights, major achievements, host broadcasts, upload failure hints, feedback reminders).
|
||||
- Data fetched from `/api/v1/events/{token}/notifications` with `X-Device-Id` for per-device read receipts; guests can mark items as read/dismissed and follow CTAs (internal routes or external links).
|
||||
- Data fetched from `/api/v1/events/\{token\}/notifications` with `X-Device-Id` for per-device read receipts; guests can mark items as read/dismissed and follow CTAs (internal routes or external links).
|
||||
- Pull-to-refresh + background poll every 90s to keep single-day events reactive without WS infrastructure.
|
||||
- When push is available (VAPID keys configured) the drawer surfaces a push toggle, persists subscriptions via `/push-subscriptions`, and the service worker refreshes notifications after every push message.
|
||||
- Operations playbook: see `docs/ops/guest-notification-ops.md` for enabling push, required queues, and cron health checks.
|
||||
@@ -71,7 +71,7 @@ Core Pages (Pflichtseiten)
|
||||
- Behavior: Nicht verpflichtend, aber empfohlen; Name kann jederzeit im Settings Sheet angepasst oder geloescht werden.
|
||||
- Startseite (Home/Feed)
|
||||
- Purpose: Central hub; begruesst Gaeste mit ihrem hinterlegten Namen und fuehrt zu den wichtigsten Aktionen.
|
||||
- Header: Eventtitel plus Live-Kennzahlen (online Gaeste, geloeste Aufgaben); hero-card zeigt "Hey {Name}!".
|
||||
- Header: Eventtitel plus Live-Kennzahlen (online Gaeste, geloeste Aufgaben); hero-card zeigt "Hey \{Name\}!".
|
||||
- Highlights: Drei CTA-Karten fuer Aufgabe ziehen, Direkt-Upload und Galerie sowie ein Button fuer die Upload-Warteschlange.
|
||||
- Content: EmotionPicker und GalleryPreview bilden weiterhin den Einstieg in Spielstimmung und aktuelle Fotos.
|
||||
- Aufgaben-Flow
|
||||
@@ -93,20 +93,20 @@ Technical Notes
|
||||
- Storage: IndexedDB for queue + cache; `CacheStorage` for shell/assets.
|
||||
- Background Sync: use Background Sync API when available; fallback to retry on app open.
|
||||
- Accessibility: large tap targets, high contrast, keyboard support, reduced motion.
|
||||
- i18n: react-i18next with JSON files (`public/lang/{locale}/guest.json`); default `de`, fallback `en`; path-based detection (/de/, /en/); RTL not in MVP. Strings for UI (e.g., gallery, upload, tasks) extracted via i18next-scanner; integrate with prefixed routing and middleware.
|
||||
- i18n: react-i18next with JSON files (`public/lang/\{locale\}/guest.json`); default `de`, fallback `en`; path-based detection (/de/, /en/); RTL not in MVP. Strings for UI (e.g., gallery, upload, tasks) extracted via i18next-scanner; integrate with prefixed routing and middleware.
|
||||
- Media types: Photos only (no videos) — decision locked for MVP and v1.
|
||||
- Realtime model: periodic polling (no WebSockets). Home counters every 10s; gallery delta every 30s with exponential backoff when tab hidden or offline.
|
||||
|
||||
API Touchpoints
|
||||
- GET `/api/v1/events/{token}` — public event metadata (when open) + theme.
|
||||
- GET `/api/v1/events/{token}/photos` — paginated gallery (approved only).
|
||||
- POST `/api/v1/events/{token}/photos` — signed upload initiation; returns URL + fields.
|
||||
- GET `/api/v1/events/\{token\}` — public event metadata (when open) + theme.
|
||||
- GET `/api/v1/events/\{token\}/photos` — paginated gallery (approved only).
|
||||
- POST `/api/v1/events/\{token\}/photos` — signed upload initiation; returns URL + fields.
|
||||
- POST (S3) — direct upload to object storage; then backend finalize call.
|
||||
- POST `/api/v1/photos/{id}/like` — idempotent like with device token.
|
||||
- GET `/api/v1/events/{token}/notifications` — list guest notifications (requires `X-Device-Id`).
|
||||
- POST `/api/v1/events/{token}/notifications/{notification}/read|dismiss` — mark/dismiss notification with device identity.
|
||||
- POST `/api/v1/events/{token}/push-subscriptions` — register a browser push subscription (requires `X-Device-Id` + VAPID public key).
|
||||
- DELETE `/api/v1/events/{token}/push-subscriptions` — revoke a stored push subscription by endpoint.
|
||||
- POST `/api/v1/photos/\{id\}/like` — idempotent like with device token.
|
||||
- GET `/api/v1/events/\{token\}/notifications` — list guest notifications (requires `X-Device-Id`).
|
||||
- POST `/api/v1/events/\{token\}/notifications/\{notification\}/read|dismiss` — mark/dismiss notification with device identity.
|
||||
- POST `/api/v1/events/\{token\}/push-subscriptions` — register a browser push subscription (requires `X-Device-Id` + VAPID public key).
|
||||
- DELETE `/api/v1/events/\{token\}/push-subscriptions` — revoke a stored push subscription by endpoint.
|
||||
|
||||
Limits (MVP defaults)
|
||||
- Max uploads per device per event: 50
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
- **Guest Join Tokens** — *Owner: Guest Platform*
|
||||
Hash stored join tokens, add anomaly metrics (usage spikes, stale tokens), and tighten gallery/photo rate limits with visibility in storage dashboards. Join-token access is now logged to `event_join_token_events` with summaries surfaced in the Event admin modal.
|
||||
- **Public API Resilience** — *Owner: Core API*
|
||||
Ensure gallery/download endpoints serve signed URLs, expand abuse throttles (token + IP), and document incident response runbooks in ops guides. See `docs/deployment/public-api-incident-playbook.md` for the response checklist.
|
||||
Ensure gallery/download endpoints serve signed URLs, expand abuse throttles (token + IP), and document incident response runbooks in ops guides. See `docs/ops/deployment/public-api-incident-playbook.md` for the response checklist.
|
||||
- **Media Pipeline & Storage** — *Owner: Media Services*
|
||||
Introduce antivirus + EXIF scrubbing workers, stream uploads to disk to avoid buffering, and enforce checksum verification during hot→archive transfers with configurable alerts from `StorageHealthService`.
|
||||
- Queue `media-security` (job: `ProcessPhotoSecurityScan`) performs antivirus + EXIF sanitisation per upload; configure via `config/security.php`.
|
||||
@@ -23,4 +23,4 @@
|
||||
- **Frontend & CSP** — *Owner: Marketing Frontend*
|
||||
Replace unsafe-inline allowances (Stripe/Matomo) with nonce or hashed CSP rules, gate analytics injection behind consent, and localise cookie-banner copy that discloses data sharing.
|
||||
|
||||
Progress updates belong in `docs/changes/` and roadmap status in `docs/implementation-roadmap.md`.
|
||||
Progress updates belong in `docs/process/changes/` and roadmap status in `docs/process/roadmap.md`.
|
||||
|
||||
@@ -13,36 +13,36 @@
|
||||
## Backend (Laravel/PHP)
|
||||
- **Config**: `config/app.php` – `locale => 'de'`, `fallback_locale => 'en'`, `available_locales => ['de', 'en']`.
|
||||
- **Translation Files**:
|
||||
- PHP arrays: `resources/lang/{locale}/{group}.php` (e.g., `marketing.php`, `auth.php`, `legal.php`) for Blade and API responses.
|
||||
- JSON for PWAs: `public/lang/{locale}/{namespace}.json` (e.g., `public/lang/de/marketing.json`) – migrated from PHP where possible; loaded via dedicated route.
|
||||
- PHP arrays: `resources/lang/\{locale\}/\{group\}.php` (e.g., `marketing.php`, `auth.php`, `legal.php`) for Blade and API responses.
|
||||
- JSON for PWAs: `public/lang/\{locale\}/\{namespace\}.json` (e.g., `public/lang/de/marketing.json`) – migrated from PHP where possible; loaded via dedicated route.
|
||||
- **Routing**:
|
||||
- Prefixed groups: `Route::prefix('{locale?}')->where(['locale' => 'de|en'])->middleware('SetLocale')` in `routes/web.php`.
|
||||
- Fallbacks: Non-prefixed routes redirect to `/de/{path}` (e.g., `/login` → `/de/login`).
|
||||
- Prefixed groups: `Route::prefix('\{locale?\}')->where(['locale' => 'de|en'])->middleware('SetLocale')` in `routes/web.php`.
|
||||
- Fallbacks: Non-prefixed routes redirect to `/de/\{path\}` (e.g., `/login` → `/de/login`).
|
||||
- Auth routes (login, register, logout): Prefixed and named (e.g., `Route::get('/login', ...)->name('login')`).
|
||||
- API routes: Locale from header/session; no URL prefix for `/api/v1`.
|
||||
- **Middleware**: `SetLocale` – Extracts locale from URL segment(1), sets `App::setLocale()`, stores in session; defaults to 'de'.
|
||||
- **JSON Loader Route**: `Route::get('/lang/{locale}/{namespace}.json', ...)` – Serves from `public_path('lang/{locale}/{namespace}.json')`; Vite proxy forwards requests.
|
||||
- **JSON Loader Route**: `Route::get('/lang/\{locale\}/\{namespace\}.json', ...)` – Serves from `public_path('lang/\{locale\}/\{namespace\}.json')`; Vite proxy forwards requests.
|
||||
- **DB Translations**: Use JSON fields with spatie/laravel-translatable or native casts; admin UI (Filament) for editing per locale.
|
||||
- **Legal Pages**: Dynamic via LegalPage model; rendered with `__($key)` or JSON for PWAs.
|
||||
|
||||
## Frontend (React/Vite PWAs)
|
||||
- **Library**: react-i18next with i18next-http-backend for async JSON loads.
|
||||
- **Setup** (`resources/js/i18n.js`):
|
||||
- Init: `i18n.use(Backend).use(LanguageDetector).init({ lng: 'de', fallbackLng: 'en', ns: ['marketing', 'auth'], backend: { loadPath: '/lang/{{lng}}/{{ns}}.json' } })`.
|
||||
- Init: `i18n.use(Backend).use(LanguageDetector).init({ lng: 'de', fallbackLng: 'en', ns: ['marketing', 'auth'], backend: { loadPath: '/lang/\{\{lng\}\}/\{\{ns\}\}.json' } })`.
|
||||
- Detection: Path-based (`order: ['path']`, `lookupFromPathIndex: 0`) for prefixed URLs; cookie/session fallback.
|
||||
- Provider: Wrap `<App>` in `<I18nextProvider i18n={i18n}>` in `app.tsx`.
|
||||
- Provider: Wrap `<App>` in `<I18nextProvider i18n=\{i18n\}>` in `app.tsx`.
|
||||
- **Usage**:
|
||||
- Hook: `const { t } = useTranslation('namespace');` in components (e.g., `t('marketing.home.title')`).
|
||||
- Interpolation: Placeholders `{count}`; pluralization via i18next rules.
|
||||
- Interpolation: Placeholders `\{count\}`; pluralization via i18next rules.
|
||||
- Dynamic Keys: Avoid; use namespaces for organization.
|
||||
- **Inertia Integration**:
|
||||
- Page Resolver: `resolvePageComponent(`./Pages/${name}.tsx`, import.meta.glob('./Pages/**/*.tsx'))` – Matches capital 'Pages' directory.
|
||||
- Page Resolver: `` resolvePageComponent(`./Pages/\${name}.tsx`, import.meta.glob('./Pages/**/*.tsx')) `` – Matches capital 'Pages' directory.
|
||||
- Props: Pass `locale` from middleware to pages.
|
||||
- Links: `<Link href={`/${locale}/path`}>` for prefixed navigation (e.g., Header.tsx).
|
||||
- Links: `<Link href={`/${'{'}locale{'}'}/path`}>` für prefixed navigation (e.g., Header.tsx).
|
||||
- **Marketing Frontend**:
|
||||
- Namespaces: `marketing` (Home, Packages, Blog, Features), `auth` (Login, Register).
|
||||
- Components: All hard-coded strings replaced (e.g., Home.tsx: `t('marketing.hero.title')`); SEO meta via `Head` with `t()`.
|
||||
- Header: Locale selector; dynamic links (e.g., `/${locale}/login` with `t('auth.header.login')`).
|
||||
- Header: Locale selector; dynamic links (e.g., `/\{locale\}/login` with `t('auth.header.login')`).
|
||||
- **Guest/Tenant PWAs**:
|
||||
- Similar setup; load JSON on app init.
|
||||
- Guest: Anonymous, locale from URL or default 'de'; strings for UI (e.g., gallery, upload).
|
||||
@@ -53,15 +53,15 @@
|
||||
|
||||
## SEO & Accessibility
|
||||
- **Multilingual URLs**: `/de/home`, `/en/home`; 301 redirects for non-prefixed.
|
||||
- **Hreflang**: `<link rel="alternate" hreflang="de" href="/de/home">` in `<Head>`.
|
||||
- **Canonical**: `<link rel="canonical" href={currentUrl}>` based on detected locale.
|
||||
- **Hreflang**: `<link rel="alternate" hreflang="de" href="/de/home">` in `<Head>`.
|
||||
- **Canonical**: `<link rel="canonical" href=\{currentUrl\}>` based on detected locale.
|
||||
- **Meta**: Translated via `t('seo.title')`; og:locale='de_DE'.
|
||||
- **Sitemap**: Generate with `de/` and `en/` variants; update `public/sitemap.xml`.
|
||||
- **Robots.txt**: Allow both locales; noindex for dev.
|
||||
- **Accessibility**: ARIA labels with `t()`; screen reader support for language switches.
|
||||
|
||||
## Migration from PHP to JSON
|
||||
- Extract keys from `resources/lang/{locale}/marketing.php` to `public/lang/{locale}/marketing.json`.
|
||||
- Extract keys from `resources/lang/\{locale\}/marketing.php` to `public/lang/\{locale\}/marketing.json`.
|
||||
- Consolidate: Remove duplicates; use nested objects (e.g., `{ "header": { "login": "Anmelden" } }`).
|
||||
- Fallback: PHP arrays remain for backend; JSON for PWAs.
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ This document details the Package-based business model for the Fotospiel tenant
|
||||
- No freeloader problem
|
||||
|
||||
**Cons:**
|
||||
- Lower acquisition (<5% download conversion)
|
||||
- Lower acquisition (lower than 5% download conversion)
|
||||
- High churn if first event doesn't impress
|
||||
- Slower scaling, higher marketing costs per install (€2-5)
|
||||
|
||||
@@ -132,8 +132,8 @@ See 15-packages-design.md for updated schema: `packages`, `event_packages`, `ten
|
||||
|
||||
### Acquisition
|
||||
- Downloads: 10k in first 3 months
|
||||
- Cost per Install: <€1.50
|
||||
- App Store Rating: >4.5 stars
|
||||
- Cost per Install: less than €1.50
|
||||
- App Store Rating: more than 4.5 stars
|
||||
|
||||
### Conversion
|
||||
- Free → Paid: 5% within 30 days
|
||||
@@ -141,13 +141,13 @@ See 15-packages-design.md for updated schema: `packages`, `event_packages`, `ten
|
||||
- Average Order Value: €8-12
|
||||
|
||||
### Retention
|
||||
- Day 1 Retention: >40%
|
||||
- Day 7 Retention: >25%
|
||||
- Day 1 Retention: more than 40%
|
||||
- Day 7 Retention: more than 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
|
||||
- LTV more than 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.
|
||||
@@ -29,7 +29,7 @@ Ziel: Vollständige Migration zu Inertia.js für SPA-ähnliche Konsistenz, mit e
|
||||
### 3. Page-Komponenten
|
||||
- Alle Marketing-Seiten als React/TSX (resources/js/pages/marketing/*.tsx):
|
||||
- z.B. Packages.tsx: Rendert Paket-Karten in Grid/Carousel (shadcn), mit Modal für Details/Upsell.
|
||||
- Wrapper: In App.tsx oder router.tsx: if (route.startsWith('/marketing')) return <MarketingLayout><Page /></MarketingLayout>;
|
||||
- Wrapper: In App.tsx oder router.tsx: if (route.startsWith('/marketing')) return `<MarketingLayout><Page /></MarketingLayout>`;
|
||||
- Migration-Reihenfolge:
|
||||
1. Statische Seiten (Home, Blog-Index): Von Blade zu Inertia.
|
||||
2. Dynamische (Packages, Register): Props integrieren.
|
||||
|
||||
@@ -21,21 +21,21 @@
|
||||
- Dynamische Darstellung: Features map() aus JSON, partial Limits (max_photos, max_tenants).
|
||||
- Hero-Section: Aurora-Gradient (bg-aurora-enhanced), Playfair Display Überschrift, Montserrat Text.
|
||||
- Konsistentes Layout: MarketingLayout (Header mit Nav, Footer mit Legal-Links).
|
||||
- CTA: Links zu /buy-packages/{id}, Hover-Transitions.
|
||||
- CTA: Links zu /buy-packages/\{id\}, Hover-Transitions.
|
||||
- Fonts: font-display (Playfair), font-sans-marketing (Montserrat).
|
||||
|
||||
### Offene/Mögliche Verbesserungen
|
||||
1. **Multi-Step-Modal auf Card-Click**: Dialog (shadcn) mit Tabs (Step 1: Details + Social Proof/Testimonials (3 Cards mit Stars); Step 2: Upsell-Tabelle (shadcn Table, Spalten: Features/Limits, Zeilen: alle Packages, Highlight selected mit bg-[#FFB6C1]); Step 3: CTA (usePage().props.auth ? Link /buy-packages : /register?package_id, localStorage pre-fill für Name/Email)).
|
||||
2. **Erweiterte Limits-Darstellung**: Vollständig in Cards (gallery_days, max_guests, max_tasks als <li>, watermark/branding als Badge/Check/X-Icons).
|
||||
2. **Erweiterte Limits-Darstellung**: Vollständig in Cards (gallery_days, max_guests, max_tasks als <li>, watermark/branding als Badge/Check/X-Icons).
|
||||
3. **UI-Enhancements**: Progress Bar (33/66/100% für Steps), Micro-Interactions (Card-Hover: scale-105/shadow-lg), FAQ-Section (Accordion mit 4 Fragen: Free-Paket, Upgrade, Reseller, Zahlung), Testimonials-Section (3 Cards mit Quotes/Ratings).
|
||||
4. **Desktop Pricing Table**: Toggle-Button neben Grid (View: Table-Modus, Vergleichs-View mit Checkmarks für Features).
|
||||
5. **Weitere**: A/B-Testing (CTAs), Accessibility (ARIA-Labels für Carousel/Modal, Keyboard-Nav), SEO (Head meta description pro Package), Performance (Lazy Testimonials), Integration (Track Clicks mit Analytics).
|
||||
|
||||
## Implementierungs-Plan (Code-Modus)
|
||||
1. **Modal hinzufügen**: useState für open/selected/step; Dialog mit Tabs; Step 1: Details + Testimonials; Step 2: Table (alle Packages); Step 3: CTA (auth-check, pre-fill).
|
||||
2. **Limits erweitern**: In Cards <li> für gallery_days/max_guests/max_tasks; Badges für watermark/branding.
|
||||
2. **Limits erweitern**: In Cards <li> für gallery_days/max_guests/max_tasks; Badges für watermark/branding.
|
||||
3. **UI-Verbesserungen**: Progress in Modal, Hover auf Cards, FAQ-Accordion, Testimonials-Section.
|
||||
4. **Pricing Table**: useState für viewMode (Grid/Table); Table mit Check/X für Features.
|
||||
5. **Test**: npm run build/dev; Browser: Card-Click → Modal-Steps, Tabelle-Vergleich, CTA-Redirect, Responsiveness.
|
||||
|
||||
Nach Umsetzung: Update PRP (docs/prp/15-packages-design.md mit UI-Details).
|
||||
Nach Umsetzung: Update PRP (docs/prp/15-packages-design.md mit UI-Details).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# API-Nutzung der Tenant Admin App
|
||||
|
||||
Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Requests sind tenant-scoped und erfordern ein Sanctum Personal Access Token (PAT) mit der Fähigkeit `tenant-admin` bzw. `tenant:<id>`.
|
||||
Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Requests sind tenant-scoped und erfordern ein Sanctum Personal Access Token (PAT) mit der Fähigkeit `tenant-admin` bzw. `tenant:\{id\}`.
|
||||
|
||||
## Authentifizierung
|
||||
|
||||
@@ -30,7 +30,7 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
|
||||
### Stats laden
|
||||
- **GET /api/v1/tenant/dashboard**
|
||||
- **Headers**: `Authorization: Bearer {token}`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`
|
||||
- **Response**: `{ active_package, active_events, new_photos, task_progress }`
|
||||
- **Zweck**: Übersicht-Daten für Dashboard-Cards (active_package: current tenant package info)
|
||||
|
||||
@@ -38,7 +38,7 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
|
||||
### Events-Liste
|
||||
- **GET /api/v1/tenant/events**
|
||||
- **Headers**: `Authorization: Bearer {token}`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`
|
||||
- **Params**:
|
||||
- `page=1` (Pagination)
|
||||
- `per_page=50` (max für Mobile)
|
||||
@@ -49,32 +49,32 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
|
||||
### Event erstellen
|
||||
- **POST /api/v1/tenant/events**
|
||||
- **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`, `Content-Type: application/json`
|
||||
- **Body**: `{ title, date, location, description, package_id }`
|
||||
- **Response**: 201 Created mit erstelltem Event
|
||||
- **Validierung**: Prüft Tenant-Package (Reseller-Limit) und erstellt Event-Package (Einmalkauf oder Free)
|
||||
|
||||
### Event-Details
|
||||
- **GET /api/v1/tenant/events/{slug}**
|
||||
- **Headers**: `Authorization: Bearer {token}`
|
||||
- **GET /api/v1/tenant/events/\{slug\}**
|
||||
- **Headers**: `Authorization: Bearer \{token\}`
|
||||
- **Response**: Erweitertes Event mit `{ tasks[], members, stats { likes, views, uploads } }`
|
||||
|
||||
### Event updaten
|
||||
- **PATCH /api/v1/tenant/events/{slug}**
|
||||
- **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json`, `If-Match: {etag}`
|
||||
- **PATCH /api/v1/tenant/events/\{slug\}**
|
||||
- **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/{slug}**
|
||||
- **Headers**: `Authorization: Bearer {token}`, `If-Match: {etag}`
|
||||
- **DELETE /api/v1/tenant/events/\{slug\}**
|
||||
- **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}`
|
||||
- **GET /api/v1/tenant/events/\{event_id\}/photos**
|
||||
- **Headers**: `Authorization: Bearer \{token\}`
|
||||
- **Params**:
|
||||
- `page=1`, `per_page=50`
|
||||
- `status=pending|approved|rejected|featured`
|
||||
@@ -84,34 +84,34 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
- **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`
|
||||
- **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}`
|
||||
- **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}`
|
||||
- **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}`
|
||||
- **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`
|
||||
- **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
|
||||
|
||||
@@ -119,7 +119,7 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
|
||||
### Tasks laden
|
||||
- **GET /api/v1/tasks**
|
||||
- **Headers**: `Authorization: Bearer {token}`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`
|
||||
- **Params**:
|
||||
- `global=true/false` (globale vs. tenant Tasks)
|
||||
- `tenant_id=me` (nur eigene Tasks)
|
||||
@@ -128,14 +128,14 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
- **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}`
|
||||
- **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`
|
||||
- **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
|
||||
|
||||
@@ -143,12 +143,12 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
|
||||
### Settings laden
|
||||
- **GET /api/v1/tenant/settings**
|
||||
- **Headers**: `Authorization: Bearer {token}`
|
||||
- **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`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`, `Content-Type: application/json`
|
||||
- **Body**: Partial Settings-Daten
|
||||
- **Response**: Updated Settings
|
||||
|
||||
@@ -156,33 +156,33 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
|
||||
### Balance laden
|
||||
- **GET /api/v1/tenant/credits/balance**
|
||||
- **Headers**: `Authorization: Bearer {token}`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`
|
||||
- **Response**: `{ balance: number }`
|
||||
|
||||
### Ledger-Verlauf
|
||||
- **GET /api/v1/tenant/credits/ledger**
|
||||
- **Headers**: `Authorization: Bearer {token}`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`
|
||||
- **Params**: `page`, `per_page` (Pagination)
|
||||
- **Response**: `{ data: LedgerEntry[], current_page, last_page }`
|
||||
- **LedgerEntry**: `{ id, type, amount, credits, date, description, transactionId? }`
|
||||
|
||||
### Credits kaufen (In-App)
|
||||
- **POST /api/v1/tenant/credits/purchase**
|
||||
- **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`, `Content-Type: application/json`
|
||||
- **Body**: `{ package_id: string, credits_added: number, platform?: 'capacitor'|'web', transaction_id?: string, subscription_active?: boolean }`
|
||||
- **Response**: `{ message, balance, subscription_active }`
|
||||
- **Hinweis**: Wird nach erfolgreichen In-App-Kuferfolgen aufgerufen, aktualisiert Balance & Ledger.
|
||||
|
||||
### Credits synchronisieren
|
||||
- **POST /api/v1/tenant/credits/sync**
|
||||
- **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json`
|
||||
- **Headers**: `Authorization: Bearer \{token\}`, `Content-Type: application/json`
|
||||
- **Body**: `{ balance: number, subscription_active: boolean, last_sync: ISODateString }`
|
||||
- **Response**: `{ balance, subscription_active, server_time }`
|
||||
- **Hinweis**: Client meldet lokalen Stand; Server gibt Quelle-der-Wahrheit zurcck.
|
||||
|
||||
### Kauf-Intent erstellen
|
||||
- **POST /api/v1/tenant/purchases/intent**
|
||||
- **Headers**: `Authorization: Bearer {token}`, `Content-Type: application/json`
|
||||
- **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
|
||||
@@ -190,9 +190,9 @@ Diese Dokumentation beschreibt alle API-Endpunkte der Tenant Admin App. Alle Req
|
||||
## Allgemeine Headers
|
||||
|
||||
Alle API-Requests enthalten:
|
||||
- **Authorization**: `Bearer {access_token}` (Sanctum PAT mit Fähigkeit `tenant:{id}`)
|
||||
- **Authorization**: `Bearer \{access_token\}` (Sanctum PAT mit Fähigkeit `tenant:\{id\}`)
|
||||
- **Content-Type**: `application/json` (für POST/PATCH)
|
||||
- **If-Match**: `{etag}` (für Concurrency-Control bei Updates)
|
||||
- **If-Match**: `\{etag\}` (für Concurrency-Control bei Updates)
|
||||
- **Accept**: `application/json`
|
||||
|
||||
## Error-Handling
|
||||
@@ -227,12 +227,12 @@ Alle Listen-Endpunkte unterstützen:
|
||||
## Headers für Concurrency
|
||||
|
||||
Mutierende Endpunkte (PATCH/DELETE) erfordern:
|
||||
- **If-Match**: `{etag}` aus GET-Response
|
||||
- **If-Match**: `\{etag\}` aus GET-Response
|
||||
- **Response**: 412 Precondition Failed bei Conflict
|
||||
|
||||
## Sicherheit
|
||||
|
||||
- **Tenant-Isolation**: Middleware vergleicht PAT-Fähigkeit (`tenant:{id}`) mit dem angefragten Tenant
|
||||
- **Tenant-Isolation**: Middleware vergleicht PAT-Fähigkeit (`tenant:\{id\}`) mit dem angefragten Tenant
|
||||
- **RBAC**: Nur tenant_admin kann mutieren, member kann nur lesen/hochladen
|
||||
- **Rate Limiting**: 100 Requests/Minute pro Tenant
|
||||
- **ETag**: Automatische Concurrency-Control
|
||||
@@ -247,7 +247,7 @@ Mutierende Endpunkte (PATCH/DELETE) erfordern:
|
||||
|
||||
### Beispiel curl (mit Token)
|
||||
```bash
|
||||
curl -H "Authorization: Bearer {token}" \
|
||||
curl -H "Authorization: Bearer \{token\}" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://api.fotospiel.com/api/v1/tenant/events
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user