Files
spsays-training/PROJECT_CONTEXT.md
T

810 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/ → 2,749 searchable Sanskrit terms
│ ├── 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 (lectures & conversations)
│ └── 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 `<html>` 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
### 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 `<mark>`, scrolled to, highlighted permanently
- `TextHighlighter` component runs on page load via `useSearchParams`
- Server-side `extractMatchedText()` searches paragraphs for OG image quote extraction
### 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 TTF from `public/fonts/Noto_Sans/static/`)
- Full IAST diacritical support (ā, ī, ū, ṛ, ṣ, ṇ, ṭ, ḍ, ś, ñ, ṅ, ḥ, ṁ)
- Every content page has `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 # used for OG image URLs
```
---
## 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/
```
---
## 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": "<b>I offer my obeisances unto Lord Śrī Kṛṣṇa...</b>",
"purport": ["paragraph 1...", "paragraph 2..."]
}
```
## Prose Chapter JSON Schema
```json
{
"book": "ek",
"chapter": 1,
"title": "Choosing Human and Animal Lives",
"type": "chapter",
"paragraphs": ["<b>heading</b>", "body text...", "<div style=\"text-align:center\"><i>verse</i></div>"]
}
```
## 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..."
}
]
}
```
---
## 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.