# Prabhupāda Says — Project Context ## What this project is A Next.js app presenting the books, letters, essays, lectures, and teachings of His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda in a modern, accessible, and searchable format with proper Unicode Sanskrit (IAST + Devanagari). Content is sourced from the pre-1980s Vedabase, extracted and indexed into MongoDB, and served via a Next.js frontend. Extraction scripts and raw data live separately in the `extractor/` directory. --- ## Tech Stack - **Next.js 16** with Turbopack, React 19, TypeScript - **Tailwind CSS v4** with `@tailwindcss/postcss` - **shadcn/ui** (base-nova style, lucide icons) — components: Button, Card, Badge, Tooltip, Input, Drawer - **next-themes** for dark/light/system mode - **vaul** for mobile drawer navigation - **Prisma v6** with MongoDB (provider `prisma-client-js`) - **MongoDB** native driver (`mongodb` package) for seeding (Prisma requires replica set for writes) - **Python 3** with BeautifulSoup4 + `indic-transliteration` for HTML extraction scripts - **Database**: MongoDB at `DATABASE_URL` env variable with `?authSource=admin` --- ## Project Structure The project is split into two directories: - **`knowledgebase/`** — Production Next.js app (~3.5MB excluding node_modules) - **`extractor/`** — Extraction scripts, seed scripts, raw data, legacy fonts (~750MB) ``` knowledgebase/ ├── app/ │ ├── page.tsx → Landing page (Books, Essays, Magazines, Letters, Transcriptions, etc.) │ ├── layout.tsx → ThemeProvider + TooltipProvider + TextSelectionToolbar + TextHighlighter │ ├── globals.css → Vintage color palette + reading settings CSS │ ├── about/page.tsx → About page (mission, data source, roadmap) │ ├── books/ → 37 book routes (verse-based + prose) │ │ ├── page.tsx → Books index (searchable grid, diacritic-aware search) │ │ ├── chapter-viewer.tsx → Shared client component for verse-based books │ │ ├── bg/, sb/, cc/, sb1962/, iso/, noi/, bs/, mm/, nbs/ → Verse-based books │ │ ├── kb/, nod/, tlc/, ej/, ek/, mg/, bbd/, owk/, rv/ → Prose books │ │ ├── poy/, pqpa/, ttp/, ochkm/, hkh/, lcl/, lob/ → More prose books │ │ ├── ssr/, ds/ → Hierarchical prose books (sub-chapters) │ │ └── sva/, gg/, mog/, cbhc/, bk/, pk/, va/ → Other books │ ├── magazines/ → Magazine browsing (BTG 1944-1960, BTG 1966-1973) │ ├── letters/ │ │ ├── page.tsx → Letters index with 3-way nav (year/recipient/location) │ │ ├── filter-year-browser.tsx → Shared component: sidebar years + month-grouped content │ │ ├── [slug]/page.tsx → Individual letter reader │ │ ├── year/[year]/ │ │ │ ├── page.tsx → Letters by year │ │ │ └── year-month-browser.tsx → Sidebar months + letter list │ │ ├── recipient/[name]/page.tsx → Letters by recipient (year sidebar + month groups) │ │ └── location/[name]/page.tsx → Letters by location (year sidebar + month groups) │ ├── essays/ → 23 essays across 6 groups │ ├── journals/ → Jaladuta Diary, The Beginning │ ├── other-documents/ → 12 miscellaneous documents │ ├── glossary/ │ │ ├── page.tsx → Redirects to /glossary/a │ │ ├── glossary-client.tsx → Client component (sidebar terms, single entry view, prev/next nav) │ │ └── [letter]/page.tsx → Dynamic route per letter (A-Z) │ ├── disciples/ → 4,747 initiated disciples directory │ │ ├── page.tsx → Disciples browser (letter nav, suffix filter, search, sort, pagination) │ │ └── disciples-browser.tsx → Client component │ ├── transcriptions/page.tsx → Coming Soon page │ └── api/ │ ├── og/route.tsx → Dynamic OG image generator (Noto Sans, Prabhupāda image) │ ├── books/ → Book/verse API routes │ └── glossary/route.ts → Glossary API ├── components/ │ ├── ui/ → shadcn components (button, card, badge, tooltip, input, drawer) │ ├── selection-toolbar/ → Text selection toolbar sub-components │ │ ├── shared.tsx → KautilyaIcon, types, hooks (useMediaQuery, useCopyFeedback) │ │ ├── floating-toolbar.tsx → Desktop floating pill / mobile bottom bar │ │ ├── share-modal.tsx → Share modal (desktop) / drawer (mobile) │ │ ├── collections-drawer.tsx → Save to collection drawer │ │ └── more-popover.tsx → More options popover (desktop) / drawer (mobile) │ ├── text-selection-toolbar.tsx → Main orchestrator (event listeners, state management) │ ├── text-highlighter.tsx → Processes incoming ?hl= URLs (scroll + highlight) │ ├── page-header.tsx → Shared header with ReadingSettings (max-w-5xl) │ ├── reading-settings.tsx → Theme/font/size/justify accessibility panel │ ├── mobile-nav.tsx → Left-slide drawer for mobile sidebar navigation │ ├── site-footer.tsx → Global footer (About + Home links) │ ├── logo.tsx → Theme-aware logo component │ └── theme-provider.tsx → next-themes wrapper ├── lib/ │ ├── db.ts → Prisma client singleton │ ├── api.ts → Core data access (books, verses, prose chapters, glossary) │ ├── constants.ts → Shared constants (BOOK_NAMES, CC_LILAS) │ ├── og.ts → OG image metadata builders (ogForVerse, ogForLetter, etc.) │ ├── text-highlight.ts → Text fragment encode/decode, highlight matching │ ├── source-reference.ts → Source reference from URL (for copy attribution) │ ├── disciples.ts → Disciples data access (by letter, place, year, search) │ ├── letters.ts → Letters data access (by year, recipient, location) │ ├── utils.ts → cn() helper │ ├── [book].ts → Per-book data access layers (nod, tlc, iso, noi, ej, ek, etc.) │ ├── other-documents.ts → Other Documents data access │ ├── journals.ts → Journals data access │ └── magazines.ts → Magazines data access ├── prisma/ │ └── schema.prisma → All models (Verse, BookMeta, ProseChapter, Essay, Letter, │ GlossaryEntry, Disciple, Transcription, etc.) └── public/ ├── fonts/Noto_Sans/static/ → NotoSans-Regular.ttf + NotoSans-Bold.ttf (OG images) ├── images/ → OG card image (Prabhupāda) ├── logo_dark.png → Logo for light theme ├── logo_light.png → Logo for dark theme └── robots.txt extractor/ → Extraction & seeding tools (not deployed) ├── scripts/ → Python extractors + TypeScript seed scripts ├── jsons/ → Extracted JSON data (books, letters, essays, etc.) ├── html/ → RTF→HTML converted files ├── rtfs/ → Original RTF source files ├── fonts/ → Legacy custom fonts (ScaGoudy, Indevr, Balaram, etc.) ├── app-rtfs/ → RTF viewer pages (archived) └── .venv/ → Python virtual environment ``` --- ## Database Schema (Prisma + MongoDB) ```prisma type Synonym { word String meanings String[] } model Verse { id String @id @default(auto()) @map("_id") @db.ObjectId book String // "bg" | "sb" | "cc" | "sb1962" | "iso" | "noi" division String? // null for BG/SB1962/ISO/NOI; canto for SB; lila for CC chapter Int verse Int verseEnd Int? reference String bookTitle String devanagari String bengali String? // only CC has Bengali transliteration String synonyms Synonym[] translation String purport String[] @@unique([book, division, chapter, verse]) @@index([book]) @@index([book, division]) @@index([book, division, chapter]) @@map("verses") } model BookMeta { id String @id @default(auto()) @map("_id") @db.ObjectId book String @unique data Json @@map("book_meta") } model ProseChapter { id String @id @default(auto()) @map("_id") @db.ObjectId book String volume Int // 0 = no volumes (sentinel for non-volume books) chapter Int? // null for intro segments title String type String // "chapter" | "intro-segment" | "conclusion" slug String order Int paragraphs String[] @@unique([book, volume, slug]) @@index([book]) @@index([book, volume]) @@index([book, volume, type]) @@map("prose_chapters") } model Essay { id String @id @default(auto()) @map("_id") @db.ObjectId slug String @unique title String author String year Int? group String? // e.g., "two-essays" order Int paragraphs String[] @@index([group]) @@map("essays") } model OtherDocumentMeta { id String @id @default(auto()) @map("_id") @db.ObjectId book String @unique data Json @@map("other_document_meta") } model OtherDocumentChapter { id String @id @default(auto()) @map("_id") @db.ObjectId book String chapter Int title String type String slug String order Int paragraphs String[] @@unique([book, slug]) @@index([book]) @@map("other_document_chapters") } model JournalMeta { id String @id @default(auto()) @map("_id") @db.ObjectId book String @unique data Json @@map("journal_meta") } model JournalChapter { id String @id @default(auto()) @map("_id") @db.ObjectId book String chapter Int title String type String slug String order Int paragraphs String[] @@unique([book, slug]) @@index([book]) @@map("journal_chapters") } model MagazineMeta { id String @id @default(auto()) @map("_id") @db.ObjectId book String @unique data Json @@map("magazine_meta") } model MagazineIssue { id String @id @default(auto()) @map("_id") @db.ObjectId book String volume Int part Int title String slug String order Int paragraphs String[] paragraphsJson String? // JSON string fallback for large issues (BSON wire protocol workaround) @@unique([book, slug]) @@index([book]) @@index([book, volume]) @@map("magazine_issues") } model Letter { id String @id @default(auto()) @map("_id") @db.ObjectId slug String @unique recipients String[] // array of individual recipient names recipientDisplay String // original combined string for display date String? dateRef String? year Int? month Int? day Int? location String? salutation String? paragraphs String[] @@index([year]) @@index([recipients]) @@index([location]) @@index([year, month]) @@map("letters") } model GlossaryEntry { id String @id @default(auto()) @map("_id") @db.ObjectId term String definition String definitionHtml String @@unique([term]) @@map("glossary") } model Disciple { id String @id @default(auto()) @map("_id") @db.ObjectId initiatedName String suffix String // "Dasa" | "Devi Dasi" | "Sw" initiationDate DateTime? // 1st of the month (exact day unknown unless verified) initiationPlace String? karmiName String? // pre-initiation (birth) name avatar String? // URL to profile photo about String? // biographical notes tags String[] isVerified Boolean @default(false) @@index([initiatedName]) @@index([initiationPlace]) @@index([initiationDate]) @@index([suffix]) @@index([tags]) @@map("disciples") } ``` --- ## Disciples Collection Scraped from `https://sp.krishna.com/disciples_a` through `disciples_y` (21 letter pages; F, Q, W, X, Z have no pages). - **Total**: 4,747 disciples - **3,296** Dasa, **1,450** Devi Dasi, **1** Svāmī - **4,554** have initiation dates (month + year); **193** are missing dates - **4,703** have initiation places; **44** are missing places - Initiation dates are set to the **1st day of the month** (exact day unknown from this source) - On the UI, exact dates should only be shown when `isVerified` is `true` - `karmiName`, `avatar`, `about`, and `tags` are empty by default — intended for manual curation Data files: `data/disciples_a_b_c_d_e.json`, `data/disciples_g_to_l.json`, `data/disciples_m_n_o_p.json`, `data/disciples_r_s_t.json`, `data/disciples_u_v_y.json` Seed script: `npx tsx scripts/seed-disciples.ts` --- ## Books Extracted ### Verse-based Books (stored in `verses` collection) | Book | Code | Verses | Chapters | Division | |------|------|--------|----------|----------| | Bhagavad-gītā As It Is | `bg` | 653 | 18 | — | | Śrīmad-Bhāgavatam | `sb` | 8,258 | 213 | 10 cantos | | Śrī Caitanya-caritāmṛta | `cc` | 11,348 | 62 | 3 līlās | | SB First Canto (1962 Edition) | `sb1962` | 762 | 19 | — | | Śrī Īśopaniṣad | `iso` | 19 | — | Invocation + 18 mantras | | The Nectar of Instruction | `noi` | 11 | — | 11 texts | | Śrī Brahma-saṁhitā | `bs` | 62 | 1 (Ch. 5) | — | | Mukunda-mālā-stotra | `mm` | 6 | 1 | — | | Nārada-bhakti-sūtra | `nbs` | 8 | 1 | — | ### Prose Books (stored in `prose_chapters` collection) | Book | Code | Chapters | Source | |------|------|----------|--------| | Kṛṣṇa Book | `kb` | 89 (2 volumes) | other.html | | The Nectar of Devotion | `nod` | 51 (4 parts) | other.html | | Teachings of Lord Caitanya | `tlc` | 32 (2 parts) | other.html (1968 ed., plain English) | | Easy Journey to Other Planets | `ej` | 2 | other.html | | Elevation to Kṛṣṇa Consciousness | `ek` | 6 | other.html | | Kṛṣṇa Consciousness: The Matchless Gift | `mg` | 7 | other.html | | Beyond Birth and Death | `bbd` | 5 | other.html | | On the Way to Kṛṣṇa | `owk` | 5 | other.html | | Rāja-vidyā: The King of Knowledge | `rv` | 8 | other.html | | The Perfection of Yoga | `poy` | 11 | other.html | | Perfect Questions Perfect Answers | `pqpa` | 9 | other.html | | Transcendental Teachings of Prahlāda Mahārāja | `ttp` | 5 | other.html | | On Chanting the Hare Kṛṣṇa Mantra | `ochkm` | 4 | other.html | | The Kṛṣṇa Consciousness Handbook | `hkh` | 19 | other.html | | The Science of Self-Realization | `ssr` | 50 sub-chapters (8 parents) | other.html | | Dialectic Spiritualism | `ds` | 36 sub-chapters (13 parents) | other.html | | Life Comes from Life | `lcl` | 16 | other.html | | Light of the Bhāgavata | `lob` | 48 | other.html | | Teachings of Lord Kapila | `tlk` | 18 | other.html | | Teachings of Queen Kuntī | `tqk` | 26 | other.html | | Gītār Gān | `gg` | 18 | other.html (Bengali poetic BG) | | Songs of the Vaiṣṇava Ācāryas | `sva` | 67 songs (4 parts, hierarchical) | other.html | | Message of Godhead | `mog` | 3 | others-before-1977.html | | Śrī Caitanya-bhāgavata Commentary | `cbhc` | 4 | others-before-1977.html | | Bhagavāner Kathā | `bk` | 2 | others-before-1977.html (ScaGoudy) | | Prayers of King Kulaśekhara (1958) | `pk` | 6 | others-before-1977.html | | Vaiśiṣṭyāṣṭakam | `va` | 8 | others-before-1977.html | ### Essays (stored in `essays` collection) | Essay | Slug | Group | Year | |-------|------|-------|------| | Krishna The Reservoir Of Pleasure | `krishna-reservoir-of-pleasure` | `two-essays` | 1966 | | Who Is Crazy? | `who-is-crazy` | `two-essays` | 1966 | | The Spiritual Masters | `the-spiritual-masters` | `cc-essays` | 1960 | | The Absolute Truth | `the-absolute-truth` | `cc-essays` | 1957 | | The Causes of Lord Caitanya's Incarnation | `causes-of-lord-caitanyas-incarnation` | `cc-essays` | 1957 | | The Confidential Reasons for Lord Caitanya's Appearance | `confidential-reasons-for-lord-caitanyas-appearance` | `cc-essays` | 1957 | | The Glories of Lord Nityānanda | `glories-of-lord-nityananda` | `cc-essays` | 1957 | | Man Is the Architect of His Own Fortune | `man-is-the-architect-of-his-own-fortune` | `pre-1977-essays` | — | | What Is the Matter with the World? | `what-is-the-matter-with-the-world` | `pre-1977-essays` | 1957 | | Religion Is Godly Life | `religion-is-godly-life` | `pre-1977-essays` | — | | Truth and Beauty | `truth-and-beauty` | `pre-1977-essays` | 1958 | | Misuse of Public Fund in the Name of Religion | `misuse-of-public-fund-in-the-name-of-religion` | `pre-1977-essays` | 1958 | | Perfection at Home | `perfection-at-home` | `pre-1977-essays` | — | | How Should One Cultivate Human Spirit | `how-should-one-cultivate-human-spirit` | `pre-1977-essays` | 1961 | | Viswa Dharma | `viswa-dharma` | `pre-1977-essays` | — | | Glorification of Śrīla Bhaktisiddhānta Sarasvatī Ṭhākura | `glorification-of-srila-bhaktisiddhanta-sarasvati-thakura` | `pre-1977-essays` | 1952 | | Who Is Crazy? (Back to Godhead #66) | `who-is-crazy-btg66` | `pre-1977-essays` | — | | Manifestation of Dharma in Human Being | `manifestation-of-dharma-in-human-being` | `pre-1977-essays` | 1972 | | Message of Krishna Consciousness | `message-of-krishna-consciousness` | `pre-1977-essays` | 1972 | | A Wrong Civilization | `a-wrong-civilization` | `pre-1977-essays` | 1936 | | Vedānta-sūtra (Typed Transcript) | `vedanta-sutra-typed` | `typed-transcripts` | 1969 | | Shaktipujah | `shaktipujah` | `reviews` | — | | Devotee and the Divinity | `devotee-and-the-divinity` | `standalone` | — | ### Other Documents (stored in `other_document_meta` + `other_document_chapters` collections) | Document | Code | Chapters | |----------|------|----------| | An Analysis of Bhagwat Geeta | `analysis-bg` | 3 | | Solution of Present Crisis by Bhagwat Geeta | `solution-crisis` | 4 | | Śrī Caitanya Mahāprabhu | `sri-caitanya` | 3 | | Conception of Geeta Nagari on the Principles of Gandhi | `geeta-nagari` | 1 | | The Real Peace Formula | `real-peace-formula` | 3 | | International Institution for God Consciousness | `intl-institution-god-consciousness` | 1 | | "Srimad Bhawatam" India's Message of Peace and Goodwill | `srimad-bhawatam-message` | 1 | | Viraha Aṣṭaka | `viraha-astaka` | 8 | | Vṛndāvana Bhajana | `vrndavana-bhajana` | 1 | | Prayer unto the Lotus Feet of Kṛṣṇa | `prayer-unto-lotus-feet-of-krsna` | 1 | | Märkine Bhägavata-dharma | `markine-bhagavata-dharma` | 1 | | Jaladuta Pamphlet | `jaladuta-pamphlet` | 1 | ### Journals (stored in `journal_meta` + `journal_chapters` collections) | Journal | Code | Chapters | Structure | |---------|------|----------|-----------| | The Jaladuta Diary, 1965 | `jaladuta-diary` | 85 | Preface, Introduction, 83 day entries grouped by month (Apr–Nov 1965) | | The Beginning — The 1966 New York Journal | `the-beginning` | 215 | Introduction, 3 place-based chapters with day entries, Memoranda, Epilogue, 20 Excerpts | ### Magazines (stored in `magazine_meta` + `magazine_issues` collections) | Magazine | Code | Issues | Articles | Flag | Source | |----------|------|--------|----------|------|--------| | Back to Godhead (1944–1960) | `btg` | 29 | 89 | Pre 1978 | btg-1960.html | | Back to Godhead (1966–1973) | `btg-1978` | 30 | 1,035 | Pre 1978 | btg-1978.html | ### Letters (stored in `letters` collection) | Metric | Value | |--------|-------| | Total letters | 6,866 | | Unique recipients (individual) | 2,243 | | Unique locations | 164 | | Year range | 1947–1977 | | Total paragraphs | 52,261 | **Top recipients**: Satsvarupa (182), Brahmananda (168), Hansadutta (117), Tamala Krsna (115), Gurudasa (103), Mukunda (105), Madhudvisa (90), Karandhara (90) **Top locations**: Los Angeles (1,392), Bombay (1,086), Vrindaban (532), Mayapur (305), London (264), Calcutta (250), Honolulu (239) **Schema notes**: - `recipients` is an array of individual names (e.g., `["Mukunda", "Janaki"]`) - `recipientDisplay` is the original combined string (e.g., `"Mukunda, Janaki"`) - Searching for a recipient uses Prisma `{ has: name }` to match any letter where that person appears - Multi-recipient groups are split by `,`, `;`, ` and `, ` & ` - Trailing punctuation (`:`, `,`, `.`) cleaned from names ### Other | Content | Collection | |---------|-----------| | Glossary (2,749 entries) | `glossary` | --- ## Font Encoding System ### ScaGoudy → IAST mapping (used in BG, SB, CC, ISO, NOI, NoD, and most 1969+ books) ``` ä→ā Ä→Ā å→ṛ Å→Ṛ ñ→ṣ Ñ→Ṣ ö→ṭ Ö→Ṭ ë→ṇ Ë→Ṇ ò→ḍ Ò→Ḍ ç→ś Ç→Ś ì→ṅ ï→ñ ü→ū Ü→Ū é→ī É→Ī à→ṁ ù→ḥ è→ṝ û→ṁl ÿ→ḷ ``` ### Bengali fonts (Inbenr/Inbeni in CC) Custom-encoded fonts where ASCII codepoints render as Bengali script. Fixed by `fix-bengali-encoding.py`. ### RM Devanagari font (used in ISO, NOI) Custom-encoded Devanagari font (p51 CSS class). The text appears as garbled ASCII without the font. **Skipped during extraction** — Unicode Devanagari is generated from IAST transliteration instead. ### Devanagari generation IAST transliteration → Devanagari via `indic-transliteration` library. Key fixes: - `join_virama_words()` — joins virāma + consonant AND virāma + vowel - `normalize_devanagari_anusvara()` — ङ् → ं before velars, ञ् → ं before palatals ### Books without ScaGoudy encoding - **TLC (1968 Edition)** — plain English transliterations ("Krishna" not "Kṛṣṇa") - **Two Essays (1966)** — plain English - **GG (Gītār Gān)** — Bengali poetic text (ScaGoudy decoded for transliteration) - **LCL (Life Comes from Life)** — dialogue book, ScaGoudy decoded - **MOG, CBHC, PK** — pre-1977 handwritten documents, plain English - **BK (Bhagavāner Kathā)** — pre-1977, uses ScaGoudy encoding - **CC Essays, Vedānta-sūtra transcript** — plain English - All other books from other.html use ScaGoudy encoding --- ## Book Types and URL Patterns ### Verse-based books (use ChapterViewer client component) | Route Pattern | Books | |---------------|-------| | `/books/bg/[chapter]/[verse]` | BG | | `/books/sb/[canto]/[chapter]/[verse]` | SB | | `/books/cc/[lila]/[chapter]/[verse]` | CC | | `/books/sb1962/[chapter]/[verse]` | SB1962 | | `/books/iso/[mantra]` | Īśopaniṣad (verse + intro segments) | | `/books/noi/[text]` | Nectar of Instruction (verse + intro segments) | | `/books/bs/[chapter]/[verse]` | Brahma-saṁhitā (chapter 5, 62 verses) | | `/books/mm/[chapter]/[verse]` | Mukunda-mālā-stotra (6 mantras) | | `/books/nbs/[chapter]/[verse]` | Nārada-bhakti-sūtra (8 sūtras) | ### Prose books (use per-book data layers + reading pages) | Route Pattern | Books | |---------------|-------| | `/books/kb/[volume]/[slug]` | Kṛṣṇa Book | | `/books/{code}/[chapter]` | NoD, TLC, EJ, EK, MG, BBD, OWK, RV, POY, PQPA, TTP, OCHKM, HKH, LCL, LOB, TLK, TQK, GG, MOG, CBHC, BK, PK | ### Hierarchical prose books (sub-chapters as separate pages) | Route Pattern | Books | |---------------|-------| | `/books/ssr/[chapter]` | Science of Self-Realization (slugs: "1-1", "1-2", "intro-foreword", etc.) | | `/books/ds/[chapter]` | Dialectic Spiritualism (slugs: "1-1" = Socrates, "1-2" = Plato, etc.) | | `/books/sva/[chapter]` | Songs of the Vaiṣṇava Ācāryas (slugs: "1-1" = Śrī Guru Praṇāma, etc.) | ### Essays | Route | Content | |-------|---------| | `/essays` | Searchable essay grid (23 essays across 6 groups) | | `/essays/[slug]` | Individual essay reader | ### Other Documents | Route | Content | |-------|---------| | `/other-documents` | Searchable other documents grid (12 documents) | | `/other-documents/[slug]` | Document index (chapter listing) | | `/other-documents/[slug]/[chapter]` | Individual chapter reader | ### Journals | Route | Content | |-------|---------| | `/journals` | Journals index (grid) | | `/journals/[slug]` | Journal chapter listing (hierarchical: place → month → day) | | `/journals/[slug]/[chapter]` | Individual journal entry reader (slug-based, e.g., `apr-3`, `sep-17`, `excerpt-...`) | ### Magazines | Route | Content | |-------|---------| | `/magazines` | Magazines index (grouped by flag: "Pre 1978 Editions") | | `/magazines/[slug]` | Magazine issue listing (grouped by volume) | | `/magazines/[slug]/[issue]` | Individual issue reader (slug-based, e.g., `v1-p1`, `no-17`) | ### Letters | Route | Content | |-------|---------| | `/letters` | Letters index with 3-way navigation tabs | | `/letters?view=year` | Year grid (1947–1977) with search | | `/letters?view=recipient` | Recipient list (2,243 individuals) with search + pagination | | `/letters?view=location` | Location grid (164 locations) with search + pagination | | `/letters/year/1968` | All letters from a specific year | | `/letters/recipient/Mukunda` | All letters to/including a specific recipient | | `/letters/location/Los%20Angeles` | All letters from a specific location | | `/letters/[slug]` | Individual letter reader with prev/next navigation | ### Other routes | Route | Content | |-------|---------| | `/` | Landing page (responsive 3-column grid) | | `/books` | Searchable book grid | | `/glossary` | Searchable glossary (2,749 entries) | | `/journals` | Journals (2 journals, 300 chapters) | | `/magazines` | Magazines (2 magazines, 59 issues, Pre 1978) | | `/letters` | Letters (6,866 letters, 3-way navigation) | | `/rtfs` | RTF viewer (gated by ALLOW_RTF=true) | | `/api/verify-access` | Password protection endpoint | --- ## Volume Convention Books without volumes use `volume: 0` as a sentinel value in the `prose_chapters` collection. This satisfies the Prisma schema's `@@unique([book, volume, slug])` constraint without requiring schema changes. - KB uses `volume: 1` and `volume: 2` - All other prose books use `volume: 0` --- ## Hierarchical Books (SSR, DS) SSR and DS have parent chapters with sub-chapters stored as individual `prose_chapters` docs: - Sub-chapter slugs: `"1-1"`, `"1-2"`, `"2-1"`, etc. - Parent chapter info stored in `intro.json` metadata: ```json { "chapters": [ { "number": 1, "title": "Learning the Science of the Soul", "subChapters": [ { "slug": "1-1", "title": "Seeing the Aim of Human Life" }, { "slug": "1-2", "title": "Your Original Consciousness Is Kṛṣṇa Consciousness" } ] } ] } ``` - Sidebar UI shows parent headings (non-clickable) with sub-chapters indented below - Prev/next navigation skips parent headings --- ## UI Features ### Reading Settings (accessibility) - **Theme**: Light / Dark / System toggle - **Serif Font**: Toggle to switch reading content to Georgia/serif - **Font Size**: Slider (XS → XXL) using CSS `zoom` on `main` and `aside` - **Justify Text**: Toggle for justified text alignment on reading content - Settings persist in `localStorage` under `spsays_reading_prefs` - Applied via CSS classes on `` element ### Mobile Navigation - Left-slide drawer (vaul) triggered by a menu button next to the Previous button - Only visible below `lg` breakpoint - Shows the full sidebar navigation grouped by section - Implemented in all 24+ reader pages via shared `MobileNav` component ### Search - Books page: diacritic-aware search (typing "Krsna" matches "Kṛṣṇa") - Glossary page: full-text search across terms and definitions - Uses Unicode NFD normalization + manual IAST character stripping ### Color Palette - **Light mode ("Aged Parchment")**: Warm cream backgrounds, deep sepia text, saffron/ochre primary - **Dark mode ("Ancient Manuscript")**: Deep warm brown backgrounds, parchment text, golden saffron primary ### Text Selection Toolbar - Global floating toolbar appears on text selection across all reading pages (except RTFs) - **Desktop**: floating pill above selection; **Mobile**: fixed bottom bar - Actions: Ask Kautilya (Phase II), Share, Copy (with source reference), More - **Share**: modal (desktop) / bottom drawer (mobile) — share to feed, copy highlight link - **More**: popover (desktop) / bottom drawer (mobile) — bookmark, save to collection, copy link, mention - **Copy** appends source reference: title, chapter/verse, highlight URL - All toolbar surfaces use dark contrast treatment (bg-black, border-white/10) - Kautilya lotus icon for the AI companion button - On iOS Safari mobile, selection is saved/restored when drawers open/close to prevent focus conflicts ### Text Highlight Links - Selected text encoded as compact URL fragment: `?hl=prefix§suffix§length` - Uses `§` delimiter (safe for Sanskrit, English, and all Vedic text) - Short selections (≤8 words) use full text as prefix - Incoming `?hl=` URLs: text is found in DOM, wrapped in ``, scrolled to, highlighted permanently - `TextHighlighter` component runs on page load via `useSearchParams` - Server-side `extractMatchedText()` searches paragraphs for OG image quote extraction - Case-insensitive matching for both DOM highlighting and server-side text extraction - Cross-paragraph matching via position mapping (spaces inserted at element boundaries) ### Dynamic OG Images - `/api/og` route generates 1200×630 PNG images using `next/og` (Satori) - Left panel: Prabhupāda image with quote mark and branding (from PNG) - Right panel: title (bold), detail, quote text, "Read more at prabhupadasays.org" - Font: Noto Sans Regular + Bold loaded from `public/fonts/Noto_Sans/static/` — full IAST diacritical support - All 104 content pages have `generateMetadata` with contextual fallback descriptions - When `?hl=` is present, the actual selected text is extracted from DB content for the OG quote ### Site Footer - Global footer on every page with © year, About link, Home link ### Consistent Container Width - All pages use `max-w-5xl` for both header and body containers --- ## Environment Variables ``` DATABASE_URL=mongodb://user:pass@host:port/spsays?authSource=admin NEXT_PUBLIC_SITE_URL=https://prabhupadasays.org ``` --- ## How to Run ```bash # Development (from knowledgebase/) npm run dev # Prisma npx prisma generate # Regenerate Prisma client after schema changes # Build npx next build # Extraction & seeding scripts are in extractor/ — see extractor/scripts/ # BFF API server (from ../spsays-bff/) make run # Build + start Go API on :8080 ``` --- ## Verse JSON Schema (BG/SB/CC/SB1962/ISO/NOI) ```json { "book_title": "Śrīmad-Bhāgavatam", "canto": 1, "chapter": 1, "verse": 1, "verse_end": null, "reference": "SB 1.1.1", "devanagari": "ॐ नमो भगवते वासुदेवाय\nजन्माद्यस्य यतो ...", "bengali": null, "transliteration": "om namo bhagavate vāsudevāya\njanmādy asya yato ...", "synonyms": [ { "word": "om", "meanings": ["O my Lord"] }, { "word": "namaḥ", "meanings": ["offering my obeisances"] } ], "translation": "I offer my obeisances unto Lord Śrī Kṛṣṇa...", "purport": ["paragraph 1...", "paragraph 2..."] } ``` ## Prose Chapter JSON Schema ```json { "book": "ek", "chapter": 1, "title": "Choosing Human and Animal Lives", "type": "chapter", "paragraphs": ["heading", "body text...", "
verse
"] } ``` ## Intro Segment JSON Schema ```json { "slug": "preface", "title": "Preface", "type": "intro-segment", "book": "ek", "order": 2, "paragraphs": ["paragraph 1...", "paragraph 2..."] } ``` ## Essay JSON Schema ```json { "slug": "krishna-reservoir-of-pleasure", "title": "Krishna The Reservoir Of Pleasure", "author": "His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda", "year": 1966, "group": "two-essays", "order": 1, "paragraphs": ["paragraph 1...", "paragraph 2..."] } ``` ## Glossary JSON Schema ```json { "title": "Glossary of Vedic Terms", "description": "A comprehensive glossary...", "totalEntries": 2749, "letters": ["A", "B", "C", ...], "entries": [ { "term": "Ācārya", "definition": "a spiritual master who teaches by his own example...", "definition_html": "a spiritual master who teaches by his own example..." } ] } ``` Glossary is browsed via `/glossary/{letter}` routes (A-Z). Each letter page shows terms grouped by base letter (diacritical variants mapped: Ā→A, Ś→S, Ṛ→R, etc.). Single entry view with prev/next navigation. --- ## Known Issues 1. **MongoDB BSON wire corruption**: The MongoDB server occasionally corrupts large BSON documents. Workaround: seed using `insertOne` + `$push` for paragraphs one at a time. 2. **SB verse numbering**: 5 duplicate verse reference tags in the HTML. Fixed by using the TEXT N header as authoritative. 3. **RTF routes gated**: `/rtfs` only accessible when `ALLOW_RTF=true`. 4. **`scripts/` excluded from tsconfig**: Prevents TypeScript build errors from seed scripts. 5. **CSS zoom for font scaling**: `zoom` property works in Chrome/Safari/Edge but may not work in older Firefox (< 126). A `transform: scale()` fallback is provided via `@supports not (zoom: 1.1)`. 6. **Password protection requires ACCESS_KEY at runtime**: The `PasswordGate` component checks the server at runtime via `/api/verify-access`. The env var must be available when the server is running, not just at build time.