huge documentaton restructure for docusaurus

This commit is contained in:
Codex Agent
2025-11-20 10:44:29 +01:00
parent 0127114e59
commit 6afa44d947
87 changed files with 18867 additions and 4102 deletions

18
docs/process/README.md Normal file
View File

@@ -0,0 +1,18 @@
# Process & Planning Hub
This directory centralizes living planning artefacts that previously sat in scattered folders.
## Structure
- `changes/` — dated session logs, retro notes, and ad-hoc findings. Drop a new Markdown file per session (`YYYY-MM-DD-topic.md`) and reference it from epics when relevant.
- `todo/` — backlog of active epics or initiatives. Each file focuses on a single problem space (e.g. `security-hardening-epic.md`) and contains goals, status, and actionable checklists.
- `roadmap.md` — top-level view that summarizes what is in progress, what is queued up next, and which epics have been completed recently.
## Workflow
1. After every planning or incident-review session, capture the outcome in `changes/`.
2. Update the relevant `todo/*.md` files with new tasks, decisions, or links back to change logs.
3. Keep `roadmap.md` in sync with the current quarters priorities so product/ops can scan it quickly.
4. When an initiative is completed and no longer useful operationally, move its Markdown file to `docs/archive/` to keep the active backlog lightweight.
> Tip: Link to concrete specs (PRP chapters, ops runbooks) from each epic so contributors know where implementation details live.

View File

@@ -0,0 +1,16 @@
# Session Changes — 2025-09-08
Summary
- Split PRP into docs/prp/* and added addendum + ADR for Tenant Admin PWA.
- Guest PWA: routes/components scaffold, bottom nav, header + settings sheet, theme toggle; polling hooks; upload (client compress <1.5 MB), offline queue + BG sync; gallery filters + lightbox; likes API/UI; SW runtime cache.
- Super Admin (Filament 4): resources for Tenants, Events, Photos, Legal Pages; dashboard widgets; photo moderation; event toggle; join link + selfhosted QR.
- CSV imports + templates for Emotions and Tasks with de/en localization; forms updated to JSON casts.
- Backend public API: stats/photos with ETag/304; upload endpoint; photo like.
- Tenant Admin PWA: auth shell (token), events list/create/edit, event detail (stats, QR, invite), photo moderation.
- Migrations: tenants table; users.tenant_id/role; events.tenant_id; model casts/relations added.
- Artisan: media:backfill-thumbnails; tenant:add-dummy; tenant:attach-demo-event.
Notes
- Security hardening intentionally minimal per instruction (token login for tenant admin).
- QR codes generated server-side via simple-qrcode.
- No secrets committed. Local gogs.ini used only for pushing to Gogs.

View File

@@ -0,0 +1,40 @@
# Registrierungs-Fixes: Redirect, Error-Clearing und Role-Handling (2025-10-02)
## Problem-Beschreibung
- **Redirect-Fehler**: Bei erfolgreicher Registrierung (free oder paid Package) wurde onSuccess in Register.tsx ausgelöst, aber kein Redirect zu /dashboard oder /buy-packages/\{id\} erfolgte. Ursache: Backend Inertia::location (302) wurde von Inertia mit preserveState: true ignoriert, da SPA-State erhalten blieb.
- **Persistente Errors**: Server-Errors (z.B. invalid email) verschwanden nicht bei Korrektur-Input; nur Passwort-Match hatte client-side Clear.
- **Role-Assignment**: Default 'user' für new Users; Upgrade zu 'tenant_admin' bei free Package (sofort im Controller), paid (nach Webhook-Payment).
- **Weitere Bugs**: Tenant::create 'name' falsch ($request->name statt first+last_name); Linter/TS Errors (Return-Types, router.visit unknown).
## Fixes
### Backend (MarketingRegisterController.php)
- **JSON-Response für Redirect**: Ersetzt Inertia::location durch response()->json(['success' => true, 'redirect' => $url]) für free (Zeile 141) und paid (Zeile 133). Kompatibel mit Inertia onSuccess (page.props.success/redirect prüfen).
- **Tenant Name Fix**: 'name' => $request->first_name . ' ' . $request->last_name (Zeile 71); slug entsprechend angepasst.
- **Role-Logic**: 'role' => 'user' in User::create (Zeile 66); für free: Update zu 'tenant_admin' nach TenantPackage::create (Zeile 129), Re-Login (Zeile 130). Für paid: Kein Upgrade bis Webhook (Paddle).
- **Return-Type**: store() zu JsonResponse (Zeile 44); use JsonResponse hinzugefügt (Zeile 22).
### Frontend (Register.tsx)
- **onSuccess-Handling**: Prüfe page.props.success && router.visit(page.props.redirect as string) (Zeile 66-68); Fallback zu data.package_id ? `` `/buy-packages/\${data.package_id}` `` : '/dashboard' (Zeile 71-75); console.log für Debug (Zeile 67, 74).
- **Error-Clearing**: Erweitert onChange für alle Inputs (first_name Zeile 123, last_name 148, email 173, address 198, phone 223, username 248): if (e.target.value.trim() && errors[field]) setError(field, ''); für privacy_consent (Zeile 325): if (checked) setError('privacy_consent', ''); Passwort behält Match-Check (Zeile 277, 305).
- **General Errors Key**: nutze `<div key={"general-errors-" + Object.keys(errors).join('-')}>` (Zeile 347) für Re-Render bei Error-Änderungen.
### Tests (RegistrationTest.php)
- **JSON-Asserts**: assertJsonStructure(['success', 'redirect']) und assertJson(['success' => true]) in test_registration_creates_user_and_tenant (Zeile 37-39) und test_registration_without_package (Zeile 78-80).
- **Neuer Test**: test_registration_with_paid_package_returns_json_redirect (Zeile 132): assertStringContainsString('buy-packages', redirect); role 'user' (kein Upgrade).
- **Validation/Email**: Unverändert, assertSessionHasErrors (Zeile 107).
## Verification
- **Backend**: php artisan test --filter RegistrationTest; prüfe JSON-Response in Browser-Network-Tab (POST /register -> 200 JSON).
- **Frontend**: Registrierung mit free: Redirect zu /verification.notice; paid: zu /buy-packages/10; Errors clear bei Input (z.B. invalid email -> input valid -> error gone).
- **Role**: DB-Check: free -> 'tenant_admin', paid -> 'user' (Upgrade via Webhook).
- **Linter/TS**: Keine Errors; Intelephense fixed durch JsonResponse use und as string cast.
## PRP-Update (docs/prp/13-backend-authentication.md)
- Hinzugefügt: Section "Role Flow in Registration": Default 'user'; Upgrade 'tenant_admin' bei free Package (Controller); paid via Webhook (Stripe invoice.paid, Paddle IPN); JSON-Success für Inertia-Forms (preserveState + onSuccess visit).
## Best Practices
- Inertia-Forms: Bei preserveState JSON-Response für custom Redirects verwenden, statt location() (vermeidet State-Ignorieren).
- Error-Clearing: Client-side onChange clear für UX (non-empty Input); Keys für conditional Elements (Re-Render).
- GDPR: Privacy-Consent required; no PII in Logs.
Date: 2025-10-02

View File

@@ -0,0 +1,39 @@
# Checkout Refactor TODOs (2025-10-05)
## Scope
- Marketing checkout only; guest and admin PWAs stay untouched.
- Replace existing marketing purchase wizard and supporting auth/payment endpoints.
## Action Items
### Wizard Foundations
- [x] Rebuild the package step with a side panel for comparable packages and reset payment state when the selected package changes (see `resources/js/pages/marketing/checkout/steps/PackageStep.tsx`).
- [x] Redesign the payment step: Stripe and Paddle happy path, failure, retry; add subscription handling for reseller plans. *(Stripe intent lifecycle + Paddle subscription flow now share status alerts, retry logic, and plan gating in `PaymentStep.tsx`.)*
- [x] Update the confirmation step and surface the admin link inside `resources/js/pages/Profile/Index.tsx`. *(Handled via `ConfirmationStep.tsx` + wizard callbacks redirecting to `/settings/profile` and `/event-admin`.)*
### Authentication & Profile Data
- [x] Refactor `resources/js/pages/auth/LoginForm.tsx` and `RegisterForm.tsx` to hit the correct routes, surface inline validation errors, and provide success callbacks.
- [x] Add optional comfort login: Google sign-in and enrichment of missing registration fields via the payment provider, combining the prior step 2/3 concept.
### Backend Alignment
- [x] Implement a dedicated `CheckoutController` plus marketing API routes, migrating any remaining checkout logic out of the marketing controller. *(Controller + routes now live in `app/Http/Controllers/CheckoutController.php` / `routes/web.php`.)*
- [x] Audit existing marketing payment flows (`resources/js/pages/marketing/PurchaseWizard.tsx`, `PaymentForm.tsx`) and plan removals or migration. *(Legacy components removed; new wizard replaces them.)*
### Quality & Rollout
- [x] Expand automated coverage: Playwright end-to-end scenarios for auth, payment success/failure, Google login; PHPUnit and webhook tests for new checkout endpoints. *(Feature + unit suites cover Stripe intents, Paddle webhooks, Google comfort login; Playwright CTA smoke in place—full payment journey available behind the `checkout` tag.)*
- [x] Update docs (PRP, docs/process/changes) and plan a feature-flag rollout for the new wizard.
## Notes
- Wizard auth now uses `/checkout/login` and `/checkout/register` JSON endpoints handled by `CheckoutController`.
- Ensure payment step parity during migration so existing paid funnels do not regress prior to feature flag activation.
- 2025-10-05: Checkout wizard skeleton created (`resources/js/pages/marketing/checkout/*`); awaiting payment/Auth wiring and backend API handoff.
- 2025-10-05: Payment architecture blueprint authored in docs/prp/marketing-checkout-payment-architecture.md.
- 2025-10-05: checkout_sessions migration + service scaffolding committed (app/Models/CheckoutSession.php, app/Services/Checkout/*, config/checkout.php).
### Payment Integration Plan
- [x] Define provider-agnostic payment state machine (intent creation, approval, capture, failure). See docs/prp/marketing-checkout-payment-architecture.md.
- [x] Scaffold checkout_sessions migration + service layer per docs/prp/marketing-checkout-payment-architecture.md.
- [x] Implement Stripe PaymentIntent endpoint returning `client_secret` scoped to wizard session. *(Covered by `CheckoutController::createPaymentIntent`.)*
- [x] Implement Paddle order creation/capture endpoints with metadata for tenant/package. *(Routes now exposed in `routes/web.php`; controller derives tenant context for authenticated users.)*
- [x] Add webhook handling matrix for Stripe invoice/payment events and Paddle subscription lifecycle.
- [x] Wire payment step UI to new endpoints with optimistic and retry handling. *(See `PaymentStep.tsx` for Stripe intent loading + Paddle order/subscription creation and capture callbacks.)*

View File

@@ -0,0 +1,22 @@
# Paddle SDK Migration to v1 Server SDK
## Summary
Migrated from deprecated `paypal/paypal-checkout-sdk` to `paypal/paypal-server-sdk ^1.0+` in PaddleController.php. The new SDK uses a Builder pattern for requests and dedicated Controllers for API calls, based on OAuth2 Client Credentials.
## Changes
- **Composer**: Removed `paypal/paypal-checkout-sdk`; retained/updated `paypal/paypal-server-sdk`.
- **Imports**: Replaced old classes (PaddleHttpClient, OrdersCreateRequest, etc.) with new (PaypalServerSdkClientBuilder, OrderRequestBuilder, OrdersController, etc.).
- **Constructor**: Updated to use `PaypalServerSdkClientBuilder` with `ClientCredentialsAuthCredentialsBuilder` and Environment (Sandbox/Production based on config/services.php).
- **createOrder**: Now uses `OrdersController->createOrder` with `OrderRequestBuilder` for intent, purchase units (AmountWithBreakdownBuilder), custom_id, and application_context.
- **captureOrder**: Now uses `OrdersController->captureOrder`; extracts custom_id from response->result->purchaseUnits for DB creation (PackagePurchase/TenantPackage).
- **createSubscription**: Now uses `SubscriptionsController->createSubscription` with `SubscriptionRequestBuilder` for plan_id, subscriber (NameBuilder), custom_id, and application_context.
- **Tests**: Updated tests/Feature/PurchaseTest.php to mock new SDK classes (e.g., OrdersController, SubscriptionsController) and responses; preserved test logic for flows, errors, idempotency.
- **Documentation**: Updated docs/prp/08-billing.md to reflect new SDK usage, flow, and migration notes.
## Testing
- Unit/Feature Tests: All Paddle-related tests pass with mocks simulating new API responses (statusCode 201, result structure).
- Integration: Verified with Sandbox keys; simulated orders/subscriptions create DB entries correctly; error handling intact.
- No Breaking Changes: Existing webhook logic and completePurchase calls unaffected; custom_id metadata preserved.
## Rationale
The old SDK is deprecated and not recommended by Paddle. The new v1 Server SDK aligns with modern standards, improves security (OAuth2), and supports future features. Migration maintains backward compatibility for frontend and DB logic.

View File

@@ -0,0 +1,86 @@
# Tenant Admin PWA — Onboarding + Management Fusion
## Context
- Goal: Merge the immersive onboarding / ordering flow from the legacy Capacitor app with the new `/event-admin` management experience inside Laravel.
- Desired outcome: Tenants land in a polished, mobile-first “welcome” journey when they first log in, complete package purchase + event setup, then switch to the operational dashboard once active.
## TODOs
1. **Audit Legacy Assets**
- Inventory screens/components from `fotospiel-tenant-app/tenant-admin-app` worth porting (intro carousel, package picker, CTA cards, animations, themed styles).
- Document any dependencies (Framework7, custom icons, animation libs) and decide whether to port or recreate with our current Tailwind/React stack.
2. **Bootstrap Welcome Route Namespace**
- Create `/event-admin/welcome/*` routes inside the Laravel tenant PWA.
- Establish shared layout primitives (full-height hero, gradient backgrounds, swipeable steps) to match native feel.
3. **Port UI Steps**
- Recreate the storytelling sequence (Brand intro → How it works → Package selection → Order CTA → First-event setup).
- Hook actions into existing APIs (packages, checkout, event creation) and leverage current auth context.
4. **Lifecycle Routing Logic**
- Add guard that directs tenants with no events / onboarding incomplete to the welcome flow after login.
- Provide quick access from dashboard back into the guided flow when creating additional events.
5. **Capacitor/TWA Packaging Prep**
- Ensure the merged `/event-admin` build is PWA-complete (manifest, offline) for future store submission.
- Plan thin Capacitor wrapper reuse; retire the legacy repo after migration.
6. **Documentation & Hand-off**
- Update PRP (tenant admin specs + onboarding) to reflect the unified experience.
- Record component inventory and routing rules so future agents can extend both modes consistently.
## Component Audit — 2025-10-10
### Legacy Welcome & Story Shell
- **Hero experience**: `App.tsx` renders a premium hero card with eyebrow, script headline, and dual CTA buttons (`/create-event`, `/tutorial`) layered on a soft gradient background with Framework7 cards and brand fonts.
- **Feature highlights**: A three-card grid introduces guest gallery, timeline/tasks, and invites; badges flag free or included items for unauthenticated vs. subscribed tenants.
- **Quick actions**: Responsive button stack that shifts based on auth state (`demo event`, `tutorial`, `events`, `login`) providing an immediate action list after the hero.
- **Credits strip**: `credits-card` combines balance chips, a RevenueCat-aware badge, and CTA to `/credits-store`; replicating this card gives tenants a quick read on package status.
### Monetisation & Ordering
- **IAP store** (`pages/IAPStorePage.tsx`): Uses `@revenuecat/purchases-capacitor` for offerings, purchase status banners, and analytics tracking; cards highlight price, credit count, and subscription state. Needs Paddle parity discussion before porting.
- **Credits context** (`contexts/AuthContext.tsx`): Persists tokens and credit balances via Capacitor Preferences and refresh logic; emits helper APIs `purchasePackage`, `getCreditsBalance`.
### Event Creation Wizard
- **Multi-step flow** (`pages/CreateEventWizard.tsx`): Three validated steps (Basics, Event type & mood, Confirmation) with segmented chips, animated progress bar, and analytics events (`trackEvent`). Integrates `EventService` for API calls and includes next/back navigation with swipe gestures.
- **Mood board**: Step includes card gallery, tags, and dynamic feature chips to capture desired vibes—helpful reference for onboarding's storytelling portion.
### Theme & Visual System
- **Design tokens** (`styles/tokens.css`): Brand palette, typography stack (Playfair Display, Montserrat, Lora, Great Vibes), spacing, radius, and shadow definitions exported as CSS variables.
- **Framework7 overrides** (`styles/theme.css`, `styles/fonts.css`): Maps tokens onto Framework7 CSS variables to achieve native-feel bars, cards, and typography.
- **Assets** (`src/assets/fonts/*`): Self-hosted font files referenced by tokens; need a Tailwind-friendly strategy (e.g., CSS `@font-face` via Vite) if we replicate the look.
### Supporting Utilities
- **Services**: `services/AuthService.ts`, `services/EventService.ts`, `services/analytics.ts` provide OAuth PKCE glue, event CRUD helpers, and event tracking (mixpanel-like contract).
- **i18n** (`src/i18n`): React context-based i18next with `en`/`de` copies for all hero/wizard strings; reuse dictionary keys where possible during port to keep translations aligned.
**Porting Recommendation**
- Rebuild the hero, feature cards, quick actions, and wizard using Tailwind + shadcn components inside Laravel PWA while reusing copy/structure.
- Lift design tokens into a Tailwind preset or CSS module so new welcome surfaces keep the premium typography without forcing Framework7 runtime.
- Treat RevenueCat-specific logic as optional: plan abstraction so Paddle packages in Laravel can slot in later if we skip native IAPs initially.
## Proposed Laravel PWA Welcome Primitives
- **`TenantWelcomeLayout`**: Full-height, gradient-backed shell with centered content column, safe-area padding, and optional bottom action rail. Applies the legacy token palette via Tailwind CSS variables and toggles between light/dark.
- **`WelcomeHero`**: Composable hero card exposing slots for eyebrow, headline, script subtitle, and dual CTA buttons. Ships with animation hooks (e.g., `framer-motion`/CSS fade) but degrades gracefully.
- **`WelcomeStepCard`**: Step wrapper with built-in progress indicator, icon slot, and scroll snap. Intended for storytelling slides (`How it works`, `Why Fotospiel`) before handing off to form-based steps.
- **`OnboardingCTAList`**: Responsive button group mirroring legacy quick actions; renders stacked buttons on mobile and inline actions on larger breakpoints. Consumes tenant/auth context to toggle copy.
- **`OnboardingHighlightsGrid`**: Reusable grid for feature cards (icon, title, badge, copy) using existing shadcn `Card` primitives to reproduce the premium look without Framework7.
- **`OnboardingProgressProvider`**: Lightweight Zustand or React context store that tracks completion state (welcome_seen, package_selected, event_created) for guards and resume logic.
- **Theming bridge**: Introduce `tenant-admin.css` (or Tailwind preset) that re-exports critical tokens (`--tenant-primary`, serif display font) so the welcome experience and management dashboard share a palette while staying Tailwind-native.
These primitives live under `resources/js/admin/onboarding/` and integrate with current router constants (`ADMIN_BASE_PATH`). They should support lazy-loading so existing dashboard bundle size remains manageable.
## Progress
- **Inline Checkout**: Die Order-Summary-Seite unterstützt jetzt Stripe-Kartenzahlungen (Payment Element) und Paddle (Orders API) direkt aus dem Onboarding heraus. Free-Packages lassen sich ohne Umweg aktivieren.
- Dashboard bewirbt die Welcome Journey (Actions + Hero Card) und leitet Tenants ohne Events weiterhin auf `/event-admin/welcome` um, während Fortschritt persistiert wird.
- Playwright-Skelett `tests/e2e/tenant-onboarding-flow.test.ts` angelegt und via `npm run test:e2e` ausführbar; Tests sind vorerst deaktiviert, bis Seed-Daten + Auth-Helper zur Verfügung stehen.
- Welcome Landing, Packages, Summary und Event-Setup sind zweisprachig (DE/EN) via react-i18next; LanguageSwitcher im Dashboard & Welcome-Layout steuert die Locale.
## Status — verbleibende Arbeiten
- Paddle-Testabdeckung (Playwright/RTL) und Error-UX gehören noch in die Roadmap, ebenso wie End-to-End-Validierung auf Staging.
## Notes
- Keep current management modules untouched until welcome flow is ready; ship incrementally behind feature flag if needed.
- Reuse new API helpers, QueryClient, and constants to avoid divergence between flows.

View File

@@ -0,0 +1,12 @@
# Coupon Ops Enhancements (2025-11-08)
## Summary
- Added `CouponRedemptionService` + Paddle webhook hooks so successful/failed redemptions are logged and counted.
- Exposed `/api/v1/marketing/coupons/preview` with per-IP rate limiting, structured logging, and localized responses.
- Marketing funnel + checkout wizard auto-prefill coupons from `?coupon=` links and persist selections through Paddle checkout.
- Super Admin dashboard now shows a "Coupon performance (30d)" widget with recent usage + discount totals.
- New artisan command `php artisan coupons:export` exports the last N days of redemptions to CSV for finance/reporting.
## Follow-ups
- Wire coupon analytics into the Matomo dashboard once new segments are defined.
- Expand fraud tooling with IP/device reputation once we roll out the affiliate program.

31
docs/process/roadmap.md Normal file
View File

@@ -0,0 +1,31 @@
# Product & Ops Roadmap
_Last updated: 2025-10-25_
This high-level view connects the active epics in `docs/process/todo/` so stakeholders can scan what is shipping now versus what is queued next. Detailed checklists live in the linked TODO files, and day-to-day notes go into `docs/process/changes/`.
-## Now (Q4 2025)
-
- **Security Hardening Epic** (`docs/process/todo/security-hardening-epic.md`)
Rolling out dual-key auth, hashed join tokens, signed asset URLs, streaming uploads, and webhook hardening. Tracks six workstreams (identity, tokens, API resilience, media services, billing, frontend/CSP).
- **Streaming Upload Refactor** (`docs/process/todo/media-streaming-upload-refactor.md`)
Designing the chunked upload/session pipeline (SEC-MS-02) to lift photo size caps and improve reliability before updating the guest PWA.
- **Paddle Billing Migration & Catalog Sync**
- Platform migration plan tracked in `docs/process/todo/paddle-migration.md` (env/config, service layer, admin billing).
- Catalog synchronization and Filament UX tracked in `docs/process/todo/paddle-catalog-sync.md`.
## Next Up (Q1 2026)
- **Localized SEO & Hreflang Strategy** (`docs/process/todo/localized-seo-hreflang-strategy.md`)
Route-prefix migration, hreflang/canonical cleanup, and sitemap realignment for the marketing site and checkout.
- **Paddle Customer Success Metrics** (spin-off from the migration tasks)
Finalize tenant ↔ Paddle sync, sandbox catalog seeding, and rollout/rollback procedures before GA. Captured in the remaining unchecked items of the Paddle TODO files.
## Recently Completed / Monitoring
- **Tenant Admin Onboarding Fusion** (`docs/archive/process/todo/tenant-admin-onboarding-fusion.md`) — Flow merged into the new PWA/TWA stack; keep monitoring localization coverage and checkout UX alignment.
- **Event Join Token Hardening** (`docs/archive/process/todo/event-join-token-hardening.md`) — All phases completed; continue monitoring default lifetime/rotation decisions.
- **Package Limit Experience Overhaul** (`docs/archive/process/todo/package-limit-experience-overhaul.md`) — Foundation live; alerts/reporting improvements now handled opportunistically.
- **Checkout Refactor & Package Limits** (`docs/process/changes/2025-10-05-checkout-refactor-todo.md`) — keep feature flags and alert thresholds under review but no net-new roadmap investment needed right now.
For historical roadmaps predating the split PRP, see `docs/archive/implementation-roadmap.md`. New initiatives should always start as a `docs/process/todo/*.md` file and be referenced here once prioritized.

View File

@@ -0,0 +1,43 @@
# Localized SEO hreflang Strategy TODO
## Goal
Establish a consistent canonical and hreflang setup for the marketing site so search engines can index German and English content without duplicate-content penalties.
## Status (Stand 18.02.2026)
- **Discovery:** In progress (route audit complete).
- **Implementation:** In progress (canonical and locale-prefixed routing live).
- **Validation:** Not started.
## Discovery
- [x] Audit current route map and localized content coverage (marketing pages, blog, checkout flow).
- Marketing routes live in `routes/web.php` without locale prefixes. Locale handling is session-based via `LocaleController::set`, `HandleInertiaRequests`, and `useLocalizedRoutes`.
- Slug coverage is mixed: `/contact` (EN) and `/kontakt` (DE) coexist, `/how-it-works` vs. `/so-funktionierts`, while other key pages only exist once (e.g. `/packages`, `/demo`, `/blog`, legal pages such as `/impressum` with no EN variant). Occasion detail routes are German-only (`/anlaesse/{type}` with `hochzeit`, `geburtstag`, etc.).
- Blog URLs are shared across locales (`/blog`, `/blog/{slug}`), with translated content injected server-side. Checkout surfaces (`/purchase-wizard/{package}`, `/checkout/{package}`) rely on shared slugs and localized copy but no alternate URLs.
- `MarketingLayout` currently generates a single canonical URL per request and an `x-default` alternate, but no locale-specific `hreflang` links. Canonical calculation removes a `/de|/en` prefix even though paths are prefix-free, so both locales resolve to the same canonical if we later introduce prefixed URLs.
- The sitemap at `public/sitemap.xml` already lists `/de/...` and `/en/...` alternates that the app does not currently serve, causing mismatch risk.
- [x] Decide on URL strategy (session-based locale vs. language-prefixed routes) and document migration implications.
- Decision: adopt path-prefixed locales (`/{locale}/{slug}`) for all marketing and checkout-facing routes, matching the i18n PRP guidance. Default requests (`/foo`) will 301 to the locale-specific URL using the visitors persisted preference or `de` fallback.
- Migration outline:
1. Introduce a `SetLocaleFromPath` middleware to extract the first segment and share it with Inertia; wire it into a `Route::group` with `prefix('{locale}')` (constrained to `de|en`) in `routes/web.php`.
2. Move existing marketing routes into the prefixed group, normalising slugs so EN and DE share identical structures where feasible (e.g. `/de/kontakt``/de/contact` or `/de/kontakt` mirrored by `/en/contact`). Keep legacy German-only slugs (`/so-funktionierts`, `/anlaesse/...`) behind per-locale path maps.
3. Add legacy fallback routes (without prefix) that permanently redirect to the new prefixed URLs to preserve existing backlinks and sitemap entries.
4. Ensure Inertia helpers (`useLocalizedRoutes`) and navigation components build URLs with the active locale segment instead of relying on session posts to `/set-locale`.
- Blog slugs remain language-agnostic identifiers under `/de/blog/{slug}` and `/en/blog/{slug}`; content localization continues via translated fields.
- [x] Identify required updates to `MarketingLayout`, sitemap generation, and Inertia responses for localized alternates.
- `MarketingLayout` needs to accept structured SEO props (canonical URL, title, description, alternates) instead of deriving everything client-side. It should emit `<link rel="alternate" hreflang="">` entries for each supported locale plus `x-default`, set `og:locale`/`og:locale:alternate`, and keep canonical URLs locale-specific (no prefix stripping).
- Server responses should standardise SEO data via a helper (e.g. `MarketingPage::make()` or dedicated view model) so each `Inertia::render` call provides `seo` props with `canonical`, `alternates`, and translated meta. `HandleInertiaRequests` can share `supportedLocales` and the resolved host, while a new `LocalizedUrlGenerator` service maps routes/slugs per locale.
- The static `public/sitemap.xml` must be regenerated (or replaced with an automated generator/Artisan command) once prefixed URLs exist, ensuring each entry carries self-referential canonicals and paired `xhtml:link` elements. Include blog detail pages and legal pages for both locales.
## Implementation
- [x] Ensure canonical URLs and hreflang tags are generated per locale with reciprocal references.
- [x] Expose locale-specific URLs in navigation, Open Graph tags, and any structured data.
- [x] Update translation files and config to support the chosen URL strategy.
## Validation
- [ ] Add automated checks (feature test or Playwright) verifying hreflang/canonical tags for both locales.
- [ ] Validate via Search Console-style inspection or lighthouse to confirm alternate links render correctly.
- [ ] Update docs (PRP + marketing playbooks) with the final hreflang strategy and operational guidance.
## Open Questions
- How will we handle locale fallbacks for missing translations when hreflang is enforced?
- Do we need localized sitemap indexes per language or a unified sitemap with hreflang annotations?

View File

@@ -0,0 +1,131 @@
# SEC-MS-02 — Streaming Upload Refactor (Requirements Draft)
**Goal**
Replace the current “single POST with multipart FormData” guest upload with a streaming / chunked pipeline that:
- avoids buffering entire files in PHP memory
- supports larger assets (target 25MB originals)
- keeps antivirus/EXIF scrubbing and storage accounting intact
- exposes clear retry semantics to the guest PWA
This document captures the scope for SEC-MS-02 and feeds into implementation tickets.
---
## 1. Current State (Baseline)
- Upload endpoint: `POST /api/v1/events/{token}/upload` handled by `EventPublicController::upload`.
- Laravel validation enforces `image|max:6144` (≈6MB). Entire file is received via `Request::file('photo')`.
- Storage flow: `Storage::disk($hotDisk)->putFile(...)` followed by synchronous thumbnail creation and `event_media_assets` bookkeeping.
- Device rate limiting: simple counter (`guest_name` = device id) per event.
- Security: join token validation + IP rate limiting; antivirus/exif cleanup handled asynchronously by `ProcessPhotoSecurityScan` (queued).
- Frontend: guest PWA uses `fetch` + FormData; progress handled by custom XHR queue for UI feedback.
Pain points:
- Upload size ceiling due to PHP post_max_size + memory usage.
- Slow devices stall the controller request; no streaming/chunk resume.
- Throttling/locks only consider completed uploads; partial data still consumes bandwidth.
---
## 2. Target Architecture Overview
### 2.1 Session-Based Chunk Upload
1. **Create session**
- `POST /api/v1/events/{token}/uploads` → returns `upload_id`, `upload_key`, storage target, chunk size.
- Validate join token + device limits *before* accepting session. Record session in new table `event_upload_sessions`.
2. **Upload chunks**
- `PUT /api/v1/events/{token}/uploads/{upload_id}/chunk` with headers: `Content-Range`, `Content-Length`, `Upload-Key`.
- Chunks written to hot storage *stream* destination (e.g. `storage/app/uploads/{upload_id}/chunk_{index}`) via `StreamedResponse`/`fopen`.
- Track received ranges in session record; enforce sequential or limited parallel chunks.
3. **Complete upload**
- `POST /api/v1/events/{token}/uploads/{upload_id}/complete`
- Assemble chunks → single file (use stream copy to final path), compute checksum, dispatch queue jobs (AV/EXIF, thumbnail).
- Persist `photos` row + `event_media_assets` references (mirroring current logic).
4. **Abort**
- `DELETE /api/v1/events/{token}/uploads/{upload_id}` to clean up partial data.
### 2.2 Storage Strategy
- Use `EventStorageManager` hot disk but with temporary “staging” directory.
- After successful assembly, move to final `events/{eventId}/photos/{uuid}.ext`.
- For S3 targets, evaluate direct multipart upload to S3 using pre-signed URLs:
- Option A (short-term): stream into local disk, then background job pushes to S3.
- Option B (stretch): delegate chunk upload directly to S3 using `createMultipartUpload`, storing uploadId + partETags.
- Ensure staging cleanup job removes abandoned sessions (cron every hour).
### 2.3 Metadata & Limits
- New table `event_upload_sessions` fields:
`id (uuid)`, `event_id`, `join_token_id`, `device_id`, `status (pending|uploading|assembling|failed|completed)`, `total_size`, `received_bytes`, `chunk_size`, `expires_at`, `failure_reason`, timestamps.
- Device/upload limits: enforce daily cap per device via session creation; consider max concurrent sessions per device/token (default 2).
- Maximum file size: 25MB (configurable via `config/media.php`). Validate at `complete` by comparing expected vs actual bytes.
### 2.4 Validation & Security
- Require `Upload-Key` secret per session (stored hashed) to prevent hijacking.
- Join token + device validations reused; log chunk IP + UA for anomaly detection.
- Abort sessions on repeated integrity failures or mismatched `Content-Range`.
- Update rate limiter to consider `PUT` chunk endpoints separately.
### 2.5 API Responses & Errors
- Provide consistent JSON:
- `201` create: `{ upload_id, chunk_size, expires_at }`
- chunk success: `204`
- complete: `201 { photo_id, file_path, thumbnail_path }`
- error codes: `upload_limit`, `chunk_out_of_order`, `range_mismatch`, `session_expired`.
- Document in `docs/prp/03-api.md` + update guest SDK.
### 2.6 Backend Jobs
- Assembly job (if asynchronous) ensures chunk merge is offloaded for large files; update `ProcessPhotoSecurityScan` to depend on final asset record.
- Add metric counters (Prometheus/Laravel events) for chunk throughput, failed sessions, average complete time.
---
## 3. Frontend Changes (Guest PWA)
- Replace current FormData POST with streaming uploader:
- Request session, slice file into `chunk_size` (default 1MB) using `Blob.slice`, upload sequentially with retry/backoff.
- Show granular progress (bytes uploaded / total).
- Support resume: store `upload_id` & received ranges in IndexedDB; on reconnect query session status from new endpoint `GET /api/v1/events/{token}/uploads/{upload_id}`.
- Ensure compatibility fallback: if browser lacks required APIs (e.g. old Safari), fallback to legacy single POST (size-limited) with warning.
- Update service worker/queue to pause/resume chunk uploads when offline.
---
## 4. Integration & Migration Tasks
1. **Schema**: create `event_upload_sessions` table + indices; optional `event_upload_chunks` if tracking per-part metadata.
2. **Config**: new entries in `config/media.php` for chunk size, staging path, session TTL, max size.
3. **Env**: add `.env` knobs (e.g. `MEDIA_UPLOAD_CHUNK_SIZE=1048576`, `MEDIA_UPLOAD_MAX_SIZE=26214400`).
4. **Cleanup Command**: `php artisan media:prune-upload-sessions` to purge expired sessions & staging files. Hook into cron `/cron/media-prune-sessions.sh`.
5. **Docs**: update PRP (sections 03, 10) and guest PWA README; add troubleshooting guide for chunk upload errors.
6. **Testing**:
- Unit: session creation, chunk validation, assembly with mocked storage.
- Feature: end-to-end upload success + failure (PHPUnit).
- Playwright: simulate chunked upload with network throttling.
- Load: ensure concurrent uploads do not exhaust disk IO.
---
## 5. Open Questions
- **S3 Multipart vs. Local Assembly**: confirm timeline for direct-to-S3; MVP may prefer local assembly to limit complexity.
- **Encryption**: decide whether staging chunks require at-rest encryption (likely yes if hot disk is shared).
- **Quota Enforcement**: should device/event caps be session-based (limit sessions) or final photo count (existing)? Combine both?
- **Backward Compatibility**: decide when to retire legacy endpoint; temporarily keep `/upload` fallback behind feature flag.
---
## 6. Next Steps
- Finalise design choices (S3 vs local) with Media Services.
- Break down into implementation tasks (backend API, frontend uploader, cron cleanup, observability).
- Schedule dry run in staging with large sample files (20+ MB) and monitor memory/CPU.
- Update SEC-MS-02 ticket checklist with deliverables above.

View File

@@ -0,0 +1,28 @@
# Paddle Catalog Sync Rollout
- [x] **Schema Prep**
- [x] Add migration for `paddle_sync_status`, `paddle_synced_at`, and `paddle_snapshot` JSON on `packages`.
- [x] Update `Package` model casts/fillable + ensure factory coverage.
- [ ] **Service Layer**
- [x] Scaffold `PaddleCatalogService` (product/price CRUD, custom data mapping).
- [ ] Add DTO helpers for Paddle product/price responses.
- [ ] Extend `PaddleClient` tests/mocks for catalog endpoints.
- [x] **Sync Logic**
- [x] Implement `SyncPackageToPaddle` job with create/update flows and metadata diffing.
- [x] Create `PaddlePackagePull` job for optional remote-to-local reconciliation.
- [x] Add `paddle:sync-packages` artisan command (`--dry-run`, `--package=`, `--pull`).
- [ ] **Admin UX**
- [x] Enhance Filament PackageResource with sync status badges + last sync timestamp.
- [ ] Add table/detail actions (“Sync to Paddle”, “Link existing Paddle entity”).
- [ ] Surface last error/log context in the admin sidebar panel.
- [ ] **Ops & Observability**
- [ ] Configure dedicated log channel/Slack hook for catalog sync outcomes.
- [ ] Document failure recovery playbook (retry, unlink, support escalation).
- [ ] **Testing & QA**
- [x] Unit tests for service + jobs using mocked Paddle API.
- [x] Feature test covering artisan command flow.
- [ ] Playwright smoke to confirm admin sync action displays status.
- [ ] **Rollout Checklist**
- [ ] Seed Paddle sandbox catalog via MCP server using migrated data.
- [ ] Verify legacy packages mapped to Paddle IDs before enabling auto-sync.
- [ ] Announce workflow change to admin users (release notes + docs update).

View File

@@ -0,0 +1,14 @@
# Paddle Billing Migration
- [x] Review current billing implementation (Stripe, Paddle, RevenueCat) across code, jobs, webhooks, docs.
- [x] Design Paddle data mappings for packages ↔ products/prices, including required metadata round-trip.
- [ ] Extend Laravel config/env handling for Paddle keys, webhook secrets, feature flags (sandbox + production).
- [ ] Build Paddle API service layer and register sandbox webhooks; document endpoints/events consumed.
- [ ] Add admin catalog sync UI for packages (create/update in Paddle, display sync status, store Paddle IDs).
- [ ] Implement tenant ↔ Paddle customer synchronization and related webhook handlers.
- [x] Replace marketing checkout payment step with Paddle-hosted checkout flow and success callbacks.
- [ ] Update tenant admin billing pages to read Paddle subscription/transaction data and manage plans.
- [ ] Define mobile/native billing strategy (RevenueCat vs Paddle) and align app logic.
- [ ] Add automated tests for Paddle integration (unit, feature, e2e) covering checkout, webhooks, sync.
- [ ] Populate Paddle sandbox catalog via MCP server and validate end-to-end activation flow.
- [ ] Draft production cutover procedure (catalog creation, flag switch, legacy shutdown, monitoring, rollback).

View File

@@ -0,0 +1,67 @@
# Security Hardening Epic (Q4 2025)
## Goal
Raise the baseline security posture across guest APIs, checkout, media storage, and identity flows so the platform can scale multi-tenant traffic with auditable, revocable access.
## Workstreams
1. **Identity & OAuth (Backend Platform)**
- Dual-key rollout for JWT signing with rotation runbook and monitoring.
- Refresh-token revocation tooling (per device/IP) and anomaly alerts.
- Device fingerprint/subnet allowances documented and configurable.
- **Tickets**
- `SEC-IO-01` — Document PAT revocation/rotation playbook (Week 1). Include scripted revocation of stale tokens and guidance for forced re-login. (Replace legacy OAuth key rotation runbook).
- `SEC-IO-02` — Build refresh-token management UI + audit logs (Week 2). *(Filament console + audit trail added 2025-10-23)*
- `SEC-IO-03` — Implement subnet/device matching configuration & tests (Week 3).
2. **Guest Join Tokens (Guest Platform)**
- Store hashed tokens with irreversible lookups; migrate legacy data.
- Add per-token usage analytics, alerting on spikes or expiry churn.
- Extend gallery/photo rate limits (token + IP) and surface breach telemetry in storage dashboards.
- **Tickets**
- `SEC-GT-01` — Hash join tokens + data migration script (Week 1).
- `SEC-GT-02` — Implement token analytics + Grafana dashboard (Week 2). *(Logging + Filament summaries delivered 2025-10-23; monitoring dashboard still pending)*
- `SEC-GT-03` — Tighten gallery/photo rate limits + alerting (Week 3).
3. **Public API Resilience (Core API)**
- Serve signed asset URLs instead of raw storage paths; expire appropriately.
- Document incident response runbooks and playbooks for abuse mitigation.
- Add synthetic monitors for `/api/v1/gallery/*` and upload endpoints.
- **Tickets**
- `SEC-API-01` — Signed URL middleware + asset migration (Week 1).
- `SEC-API-02` — Incident response playbook draft + review (Week 2). *(Runbook: `docs/ops/deployment/public-api-incident-playbook.md`, added 2025-10-23)*
- `SEC-API-03` — Synthetic monitoring + alert config (Week 3).
4. **Media Pipeline & Storage (Media Services)**
- Integrate antivirus/EXIF scrubbers and streaming upload paths to avoid buffering.
- Verify checksum integrity on hot → archive transfers with alert thresholds.
- Surface storage target health (capacity, latency) in Super Admin dashboards.
- **Tickets**
- `SEC-MS-01` — AV + EXIF scrubber worker integration (Week 1). *(Job: `ProcessPhotoSecurityScan`, queue: `media-security`)*
- `SEC-MS-02` — Streaming upload refactor + tests (Week 2). *(Requirements draft: `docs/process/todo/media-streaming-upload-refactor.md`, 2025-10-23)*
- `SEC-MS-03` — Checksum validation + alert thresholds (Week 3).
- `SEC-MS-04` — Storage health widget in Super Admin (Week 4).
5. **Payments & Webhooks (Billing)**
- Link Paddle webhooks to checkout sessions with idempotency locks.
- Add signature freshness validation + retry policies for provider outages.
- Pipe failed capture events into credit ledger audits and operator alerts.
- **Tickets**
- `SEC-BILL-01` — Checkout session linkage + idempotency locks (Week 1).
- `SEC-BILL-02` — Signature freshness + retry policy implementation (Week 2).
- `SEC-BILL-03` — Failed capture notifications + ledger hook (Week 3).
6. **Frontend & CSP (Marketing Frontend)**
- Replace `unsafe-inline` allowances with nonce/hash policies for Stripe + Matomo.
- Gate analytics script injection behind consent with localised disclosures.
- Broaden cookie banner layout to surface GDPR/legal copy clearly.
- **Tickets**
- `SEC-FE-01` — CSP nonce/hashing utility + rollout (Week 1).
- `SEC-FE-02` — Consent-gated analytics loader refactor (Week 2).
- `SEC-FE-03` — Cookie banner UX update + localisation (Week 3).
## Deliverables
- Updated docs (`docs/prp/09-security-compliance.md`, runbooks) with ownership & SLAs.
- Feature flags / configuration toggles for rollouts (JWT KID, signed URLs, CSP nonces).
- Monitoring dashboards + alerting coverage per workstream.
- Integration and Playwright coverage validating the hardened flows.