huge documentaton restructure for docusaurus
This commit is contained in:
43
docs/process/todo/localized-seo-hreflang-strategy.md
Normal file
43
docs/process/todo/localized-seo-hreflang-strategy.md
Normal 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 visitor’s 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?
|
||||
131
docs/process/todo/media-streaming-upload-refactor.md
Normal file
131
docs/process/todo/media-streaming-upload-refactor.md
Normal 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 25 MB 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` (≈6 MB). 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: 25 MB (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 1 MB) 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.
|
||||
28
docs/process/todo/paddle-catalog-sync.md
Normal file
28
docs/process/todo/paddle-catalog-sync.md
Normal 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).
|
||||
14
docs/process/todo/paddle-migration.md
Normal file
14
docs/process/todo/paddle-migration.md
Normal 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).
|
||||
67
docs/process/todo/security-hardening-epic.md
Normal file
67
docs/process/todo/security-hardening-epic.md
Normal 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.
|
||||
Reference in New Issue
Block a user