Data Model
TypeScript type system, core entities (Book, Character, Session), Supabase table mapping, snake_case/camelCase conversion pattern, and the type modules that mirror the DB schema.
The frontend's data model is defined entirely in TypeScript and mirrors the Supabase PostgreSQL schema. There is no ORM - queries are written as raw Supabase client calls with typed results.
Type Organization
Types are spread across three files in lib/types/:
| File | Domain | Key types |
|---|---|---|
index.ts | Domain models | Book, BookCharacter, Category, Profile, BookCategory, BookComment, BookRating |
chat.ts | Chat domain | StreamEvent, ChatSession, ChatMessage, Character, AISettings, PreferenceReturn, PreferenceModifiers, ValidPreferences |
database.ts | Generated from Supabase | Database, Tables, TablesInsert, TablesUpdate (from supabase db types) |
Domain types use camelCase properties. The Database generated types use snake_case. Conversion between the two happens at the data access layer.
Core Entities
Profile
Maps to the profiles table. Core fields: id (UUID, FK to auth.users), email, display_name, avatar_url, bio, status (active | blocked), created_at.
Book
Maps to the books table. Represents a published book with its characters:
| Field | Type | Source |
|---|---|---|
id | UUID | auto-generated |
title | string | user input |
author | string | user input |
description | string | user input |
language | "english" | "urdu" | "both" | user input |
coverUrl | string | null | Supabase Storage URL |
price | number | nullable, in cents |
status | BookStatus | "processing" | "processed" | "failed" |
categoryIds | number[] | FK to categories |
createdAt | string | auto-generated |
BookCharacter
Maps to the characters table. Each character belongs to one book: id, bookId, name, description, avatarUrl, color, emoji, createdAt.
ChatSession
Maps to the chat_sessions table. Links a user, a character, and a book: id, userId, characterId, bookId, createdAt, updatedAt.
ChatMessage
Maps to the messages table: id, sessionId, role ("user" | "assistant"), content, createdAt.
Category
Maps to the categories table: id (integer), name, slug, imageUrl, bookCount (computed), createdAt.
BookComment
Maps to the book_comments table: id, bookId, userId, content, createdAt, updatedAt. Includes a nested profile object with displayName and avatarUrl from a join.
Snake-Case Conversion
The conversion pattern is consistent across every DB query module:
// At the boundary - converting a DB row to a domain type
const book = toCamelCase(dbRow) as Book;
// At the boundary - converting a domain type to DB fields
const dbFields = toSnakeCase({ title, author });The utility functions in lib/utils/transform.ts handle deeply nested conversion. They are applied by each query function before returning results to callers. This keeps the rest of the application in camelCase while the schema remains in PostgreSQL snake_case.
Generated Type Safety
The lib/types/database.ts file is generated by supabase db types and includes the full schema as a nested type. The Supabase client factories use this type parameter:
export const supabase = createBrowserClient<Database>(
url, key
);This gives type-safe access to .from('books').select('*') queries - the result is typed to the tables.books.Row interface.
Tables Referenced
The frontend queries approximately 15 tables. Not all have corresponding domain types - some are accessed through generic Supabase queries with inline type assertions:
auth.users- Supabase-managed, never queried directly from the frontendprofiles- typed via Profile domain typeuser_roles- typed inline in auth middlewarebooks- typed via Book domain typebook_characters- via BookCharacterbook_categories- join table, typed inlinebook_comments- via BookCommentbook_ratings- via BookRatingchat_sessions- via ChatSessionmessages- via ChatMessageuser_preferences- via PreferenceReturnpurchases- typed inline in payment codeuser_library- typed inline in library queriesnotifications- typed inlinesettings- typed inline in admin code
Payment Flow
Stripe checkout integration: PaymentIntent creation, webhook processing with signature verification, library assignment on purchase completion, and debug-mode mock payments.
Admin Panel
Admin layout, server-side auth guard, stats dashboard, content moderation (books, comments, reports), user management, and system notification CRUD.