34 KiB
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 (
mongodbpackage) for seeding (Prisma requires replica set for writes) - Python 3 with BeautifulSoup4 +
indic-transliterationfor HTML extraction scripts - Database: MongoDB at
DATABASE_URLenv 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)
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
isVerifiedistrue karmiName,avatar,about, andtagsare 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:
recipientsis an array of individual names (e.g.,["Mukunda", "Janaki"])recipientDisplayis 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 + vowelnormalize_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: 1andvolume: 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.jsonmetadata:{ "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
zoomonmainandaside - Justify Text: Toggle for justified text alignment on reading content
- Settings persist in
localStorageunderspsays_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
lgbreakpoint - Shows the full sidebar navigation grouped by section
- Implemented in all 24+ reader pages via shared
MobileNavcomponent
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<mark>, scrolled to, highlighted permanently TextHighlightercomponent runs on page load viauseSearchParams- 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/ogroute generates 1200×630 PNG images usingnext/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
generateMetadatawith 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-5xlfor 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
# 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)
{
"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
{
"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
{
"slug": "preface",
"title": "Preface",
"type": "intro-segment",
"book": "ek",
"order": 2,
"paragraphs": ["paragraph 1...", "paragraph 2..."]
}
Essay JSON Schema
{
"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
{
"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
-
MongoDB BSON wire corruption: The MongoDB server occasionally corrupts large BSON documents. Workaround: seed using
insertOne+$pushfor paragraphs one at a time. -
SB verse numbering: 5 duplicate verse reference tags in the HTML. Fixed by using the TEXT N header as authoritative.
-
RTF routes gated:
/rtfsonly accessible whenALLOW_RTF=true. -
scripts/excluded from tsconfig: Prevents TypeScript build errors from seed scripts. -
CSS zoom for font scaling:
zoomproperty works in Chrome/Safari/Edge but may not work in older Firefox (< 126). Atransform: scale()fallback is provided via@supports not (zoom: 1.1). -
Password protection requires ACCESS_KEY at runtime: The
PasswordGatecomponent 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.