Falsafa
BackendHigh-Level Design

Data Ownership

Where every piece of backend-owned data lives: Supabase for relational, Qdrant for vectors, TypeSense for BM25, Redis for caches and locks, the local filesystem for system prompt backups.

The backend owns a small, well-defined set of data. The rest of the system lives in Supabase and is read or written by the frontend. This page lists exactly what the backend creates, where it stores it, and how it is keyed.

Tables

DataStoreKey
BooksSupabase books tablebook_id
CharactersSupabase characters tablecharacter_id
Chat sessionsSupabase chat_sessions tablesession_id
Chat messagesSupabase messages tablesession_id + created_at
System prompts (backup)Backend filesystem/prompts/{book_id}/{safe_name}.md

The frontend creates books and chat sessions. The backend writes characters and chat messages, and updates books.processing_status after ingestion completes.

Indexes

DataStoreKey
Book text (vectors)Qdrant collection {book_id}chunk_index
Book text (BM25)TypeSense collection {book_id}{book_id}:{chunk_index}

Qdrant collections use cosine distance with EMBEDDING_DIMENSION dimensionality (driven by the configured embedding provider). TypeSense collection names match the book_id exactly.

Redis Keys

DataKeyValue
Session context cachechat:sess:{session_id}Last 10 messages + summary
Character cachechat:char:{character_id}Full character row
Book cachechat:book:{book_id}Book + category data
Query-rewrite cachechat:qr:{character_id}:{hash}Narrative + keyword queries
Session write lockchat:lock:{session_id}Hex token, 30s TTL
Job queueprocessing_queue (list)Job dicts

The job queue is a single Redis FIFO list shared by all backend instances. RPUSH enqueues, LPOP dequeues. There is no separate dead-letter queue; failed jobs are logged with their job id.

Filesystem

System prompts are written to SYSTEM_PROMPT_STORAGE_PATH/{book_id}/{safe_name}.md as a backup. The same text is also stored in the Supabase characters table. The filesystem copy is the source of truth only if the database row is ever lost.

Lifecycle

  • Books are created by the frontend, owned by the frontend, and read by the backend for validation. The backend updates processing_status but no other field.
  • Characters are created by the backend during ingestion. The frontend reads them to render the book-detail page and the chat UI.
  • Chat sessions are created by the frontend. The backend reads them and updates message_count and preview after each chat.
  • Chat messages are written by the backend only. The frontend reads them to render the conversation.
  • Qdrant and TypeSense collections are created by the backend during ingestion and never deleted. The frontend does not read from them directly.
  • Redis caches are best-effort. They are repopulated from Supabase on miss and expire after 3600s.
  • Redis locks have a 30-second TTL. The lock is released earlier via a Lua CAS script when work completes normally.
  • System prompt files are written once during ingestion. They are never deleted or rotated by the backend.

On this page