# Request Flow Two representative request paths through the stack: a **page load** (SSR) and a **media playback** (presigned URL → direct MinIO stream). ## SSR Page Load — Browse / Book Detail ```mermaid sequenceDiagram actor C as Browser / iOS App participant CD as Caddy :443 participant UI as SvelteKit UI :3000 participant BE as Backend API :8080 participant MS as Meilisearch :7700 participant PB as PocketBase :8090 participant VK as Valkey :6379 participant MN as MinIO :9000 C->>CD: HTTPS GET /browse CD->>UI: proxy /* UI->>BE: GET /api/catalogue?page=1&sort=popular BE->>MS: search(query, filters, sort) MS-->>BE: [{slug, title, …}, …] BE-->>UI: {books[], page, total, has_next} UI-->>CD: SSR HTML CD-->>C: 200 HTML Note over C,UI: Infinite scroll — client fetches next page C->>CD: HTTPS GET /api/browse-page?page=2 CD->>UI: proxy (SvelteKit API route) UI->>BE: GET /api/catalogue?page=2 BE->>MS: search(…) MS-->>BE: next page BE-->>UI: {books[], …} UI-->>C: JSON ``` ## Audio Playback — Presigned URL Flow ```mermaid sequenceDiagram actor C as Browser / iOS App participant CD as Caddy :443 participant UI as SvelteKit UI :3000 participant BE as Backend API :8080 participant VK as Valkey :6379 participant MN as MinIO :9000 C->>CD: GET /api/presign/audio/{slug}/{n}?voice=af_bella CD->>BE: proxy /api/* BE->>VK: GET presign:audio:{slug}:{n}:{voice} alt cache hit VK-->>BE: presigned URL (TTL remaining) BE-->>C: 302 redirect → presigned URL else cache miss BE->>MN: GeneratePresignedURL(audio-bucket, key, 1h) MN-->>BE: presigned URL BE->>VK: SET presign:audio:… EX 3500 BE-->>C: 302 redirect → presigned URL end C->>MN: GET presigned URL (direct, no proxy) MN-->>C: audio/mpeg stream ``` ## Chapter Read — SSR + Content Fetch ```mermaid sequenceDiagram actor C as Browser / iOS App participant CD as Caddy :443 participant UI as SvelteKit UI :3000 participant BE as Backend API :8080 participant PB as PocketBase :8090 participant MN as MinIO :9000 C->>CD: HTTPS GET /books/{slug}/chapters/{n} CD->>UI: proxy /* UI->>PB: getBook(slug) + listChapterIdx(slug) PB-->>UI: book meta + chapter list UI->>BE: GET /api/chapter-markdown/{slug}/{n} BE->>MN: GetObject(chapters-bucket, {slug}/{n}.md) MN-->>BE: markdown text BE-->>UI: markdown body Note over UI: marked() → HTML UI-->>CD: SSR HTML CD-->>C: 200 HTML ```