Falsafa
FrontendHigh-Level Design

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

BucketVisibilityContentsRead mechanism
falsafa_publicPublicBook cover images, profile avatars, category imagesDirect URL via Supabase Storage public URL
falsafa_privatePrivateBook 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):

  1. Client-side validation. The upload form validates file type (PDF, EPUB, MOBI, etc.), file size, and cover image type/size before submitting.
  2. 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).
  3. Cover upload. The cover image is uploaded to the falsafa_public bucket under a path derived from the book title. The public URL is saved for immediate use in the UI.
  4. Book file upload. The book file is uploaded to the falsafa_private bucket under original/{bookId}/{filename}.
  5. Database inserts. A row is inserted into books with the book metadata and cover URL. A row is inserted into user_library granting the uploader ownership.
  6. Backend processing. A POST request is sent to the Python backend at /character/processing to trigger character extraction and indexing. A processing status field in the books table tracks progress.

File Validation

Validation is per-purpose and configured through environment variables:

Upload typeAllowed typesSize limitEnv var
Book fileapplication/pdf, application/epub+zip, text/plain, etc.100 MBNEXT_PUBLIC_MAX_FILE_SIZE
Cover imageimage/jpeg, image/png, image/webp5 MBNEXT_PUBLIC_MAX_COVER_SIZE
Profile avatarimage/jpeg, image/png, image/webp2 MBHardcoded

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.

On this page