File Storage
Supabase Storage with two buckets (public/private), the book upload pipeline, file validation, and signed URL generation.
The frontend uses Supabase Storage as its sole file store. Two buckets serve different access patterns. Everything goes through the book upload pipeline; there is no generic file upload endpoint.
Buckets
| Bucket | Visibility | Contents | Read mechanism |
|---|---|---|---|
falsafa_public | Public | Book cover images, profile avatars, category images | Direct URL via Supabase Storage public URL |
falsafa_private | Private | Book files (PDFs and other formats) | Signed URLs, one-hour expiry |
Public files are served directly from Supabase's CDN via the storage URL pattern. Private files require a signed URL that is generated by the backend processing pipeline after the book is processed.
Book Upload Pipeline
The upload flow is the only active file write path. It lives in lib/book-upload/upload-service.ts and is orchestrated by a server action (uploadBookAction in app/upload-book/actions.ts):
- Client-side validation. The upload form validates file type (PDF, EPUB, MOBI, etc.), file size, and cover image type/size before submitting.
- Server-side validation. The server action re-validates all fields - book title min length 1, author min length 1, description min length 10, language (one of English, Urdu, both).
- Cover upload. The cover image is uploaded to the
falsafa_publicbucket under a path derived from the book title. The public URL is saved for immediate use in the UI. - Book file upload. The book file is uploaded to the
falsafa_privatebucket underoriginal/{bookId}/{filename}. - Database inserts. A row is inserted into
bookswith the book metadata and cover URL. A row is inserted intouser_librarygranting the uploader ownership. - Backend processing. A POST request is sent to the Python backend at
/character/processingto trigger character extraction and indexing. A processing status field in thebookstable tracks progress.
File Validation
Validation is per-purpose and configured through environment variables:
| Upload type | Allowed types | Size limit | Env var |
|---|---|---|---|
| Book file | application/pdf, application/epub+zip, text/plain, etc. | 100 MB | NEXT_PUBLIC_MAX_FILE_SIZE |
| Cover image | image/jpeg, image/png, image/webp | 5 MB | NEXT_PUBLIC_MAX_COVER_SIZE |
| Profile avatar | image/jpeg, image/png, image/webp | 2 MB | Hardcoded |
Signed URLs
Signed URLs are generated by the backend after book processing completes. The frontend fetches them through GET /api/files/download/[fileId], which calls Supabase Storage's createSignedUrl() with a one-hour expiry. The user's library page uses these URLs to serve book downloads.
The backend also receives a signed URL for the book file so it can read the content during character extraction. This URL has the same one-hour expiry and is included in the POST body sent to /character/processing.
Profile Images
Profile avatars follow a simpler upload pattern: the user uploads an image via the settings page, which hits POST /api/profile/image/upload. The image is stored in falsafa_public with a profile-specific prefix. The profile helper (fetchProfile in lib/profile.ts) returns the public URL.
Health Checks
GET /api/media/health verifies that the Supabase Storage client can list buckets. This endpoint is used by the admin panel's system health monitor.
Chat Pipeline
SSE streaming from the frontend: session lifecycle, message proxying, SSE parsing, user preferences per character, and how the frontend creates, lists, and manages chat sessions.
Payment Flow
Stripe checkout integration: PaymentIntent creation, webhook processing with signature verification, library assignment on purchase completion, and debug-mode mock payments.