41 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
- Go BFF API — all data fetched via
lib/bff.tsHTTP client calling the Go BFF server (no direct database access) - framer-motion for audio player animations (spring enter/exit, minimize/expand transitions, audio wave bars)
- Typesense (via BFF) — typo-tolerant full-text search across all content
- Python 3 with BeautifulSoup4 +
indic-transliterationfor HTML extraction scripts
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/ → 3,787 transcriptions (lectures, conversations, philosophy, dictations)
│ │ ├── page.tsx → Browse by year / place / type (3 views)
│ │ ├── year/[year]/page.tsx → Year listing, grouped by month
│ │ ├── place/[place]/page.tsx → Place listing
│ │ ├── type/[type]/page.tsx → Type listing (lecture/conversation), year sidebar
│ │ └── [slug]/page.tsx → Individual transcription reading page
│ ├── search/ → Search page (server + client components)
│ │ ├── page.tsx → Server component (URL-driven state)
│ │ └── search-content.tsx → Client component (input, filters, results)
│ └── api/
│ ├── og/route.tsx → Dynamic OG image generator (Noto Sans, Prabhupāda image)
│ ├── books/ → Book/verse API routes
│ ├── search/route.ts → BFF search proxy (Typesense via /api/v1/search)
│ └── 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
│ ├── header-search.tsx → Header search button with framer-motion expand animation
│ ├── site-footer.tsx → Global footer (About + Home links)
│ ├── audio-player/ → Site-wide floating audio player
│ │ ├── audio-context.tsx → React context + provider, manages <audio> element
│ │ ├── floating-player.tsx → Floating player UI (desktop bar / mobile pill)
│ │ ├── audio-wave.tsx → Reusable animated audio wave bars
│ │ └── index.ts → Barrel exports
│ ├── logo.tsx → Theme-aware logo component
│ └── theme-provider.tsx → next-themes wrapper
├── lib/
│ ├── bff.ts → BFF API client (typed fetch wrapper: bff<T>(), bffList<T>(), bffOrThrow<T>())
│ ├── api.ts → Core data access (books, verses, prose chapters, glossary) — calls BFF API
│ ├── books.ts → Generic book data layer (replaces 29 individual book files)
│ ├── 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 — calls BFF API
│ ├── letters.ts → Letters data access (by year, recipient, location) — calls BFF API
│ ├── transcriptions.ts → Transcriptions data access — calls BFF API
│ ├── utils.ts → cn() helper
│ ├── [book].ts → Per-book data access layers (nod, tlc, iso, noi, ej, ek, etc.) — calls BFF API
│ ├── other-documents.ts → Other Documents data access — calls BFF API
│ ├── journals.ts → Journals data access — calls BFF API
│ └── magazines.ts → Magazines data access — calls BFF API
└── 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
Data Architecture
The knowledgebase never connects to MongoDB directly. All data is served by the Go BFF API server.
BFF Server
- URL: Configured via
BFF_URLenvironment variable (default:http://localhost:8080) - The BFF reads from MongoDB — the knowledgebase frontend has no database driver or connection string
- All API endpoints live under
/api/v1/...on the BFF server
BFF Client (lib/bff.ts)
The typed fetch wrapper provides three helpers:
bff<T>(path, options?)— Fetch JSON from the BFF. Returnsnullon 404, throwsBffErroron other failures.bffList<T>(path, options?)— Fetch a list. Returns[]on 404 (instead of null).bffOrThrow<T>(path, options?)— Fetch JSON, throwing on 404. Use when a missing resource should be an error.
Options include params (query parameters), revalidate (Next.js ISR seconds, default 60), and tags (cache tags).
Response Envelope
BFF responses use a { success: true, data: ... } envelope. The bff() client auto-unwraps this — callers receive the inner data value directly.
Case Mapping
The BFF uses snake_case JSON field names (Go convention). Each frontend data layer file (lib/letters.ts, lib/transcriptions.ts, lib/books.ts, etc.) maps BFF responses to camelCase TypeScript types used by React components.
Data Layer Files
Individual lib/*.ts files are thin wrappers that:
- Call a BFF endpoint via
bff()/bffList()/bffOrThrow() - Map the snake_case response to camelCase frontend types
- Export typed functions consumed by Next.js server components
Key data layers and their BFF endpoint prefixes:
lib/api.ts→/api/v1/books/*,/api/v1/glossary/*— Books, verses, prose chapters, glossarylib/books.ts→/api/v1/books/{code}/*— Generic book data layer (replaces 29 individual per-book files)lib/letters.ts→/api/v1/letters/*— Letters (by year, recipient, location)lib/transcriptions.ts→/api/v1/transcriptions/*— Transcriptions (by year, place, type)lib/disciples.ts→/api/v1/disciples/*— Disciples directorylib/other-documents.ts→/api/v1/other-documents/*— Other Documentslib/journals.ts→/api/v1/journals/*— Journalslib/magazines.ts→/api/v1/magazines/*— Magazines
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 filters via the BFF endpoint (matches any letter where that person appears)
- Multi-recipient groups are split by
,,;,and,& - Trailing punctuation (
:,,,.) cleaned from names
Transcriptions (stored in transcriptions collection)
3,787 transcriptions of Śrīla Prabhupāda's lectures and conversations (1966–1977), plus 59 philosophy discussions and 12 SB dictations.
- Lectures (2,179): Bhagavad-gītā, Śrīmad-Bhāgavatam, Caitanya-caritāmṛta, Nectar of Devotion, Īśopaniṣad, Brahma-saṁhitā, and general lectures
- Conversations (1,537): Morning walks, room conversations, interviews, press conferences, initiations
- Philosophy Discussions (59): Western philosophers discussed with Śyāmasundara and Hayagrīva
- SB Dictations (12): Śrīmad-Bhāgavatam 3rd Canto translation/purport dictations
- Audio: 99.1% have linked audio recordings from Cloudflare R2 (
audioUrlfield) - Empty content: 30 transcriptions (Hindi/Bengali lectures) have no English text but may have audio
Data layer: lib/transcriptions.ts (calls BFF API, NOT local JSON files or direct MongoDB)
Other
| Content | Collection |
|---|---|
| Glossary (2,749 entries) | glossary |
| Transcriptions (3,787 entries) | transcriptions collection |
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 |
Transcriptions
/transcriptions → Browse by year / place / type
/transcriptions?view=year → Year grid view
/transcriptions?view=place → Place grid view
/transcriptions?view=type → Lecture vs Conversation cards
/transcriptions/year/[year] → Year listing, grouped by month
/transcriptions/place/[place] → Place listing
/transcriptions/type/[type] → Type listing (lecture/conversation), year sidebar
/transcriptions/[slug] → Individual transcription reading page
Each transcription page shows:
- Title, type badge (Lecture/Conversation), date, place, reference, duration
- Participants list
- Play Audio button (links to Cloudflare R2 mp3)
- Content blocks: paragraphs with speaker labels, verses (centered italic), quotes (border-left), notes
- Prev/next navigation within same year
?hl=text highlight sharing support with OG image
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
Search (/search page) — Typo-tolerant, diacritic-insensitive full-text search across all content.
- Powered by Typesense via the BFF (
/api/v1/searchproxied through/api/search) - 9 indexed content types combined into 8 user-facing filters: Books (verses + prose), Letters, Transcriptions, Glossary, Essays, Journals, Magazines, Other Documents
- Books filter combines verses and prose into one tab (sends
type=verses,proseto the BFF) - Multi-select filters — clicking multiple type tabs combines them (e.g., Books + Letters); clicking "All" clears all filters
- URL state —
q,type, andpageare synced to the URL (e.g./search?q=foo&type=books,letters&page=2), so any search is shareable and bookmarkable - Pagination — appears both above the results (compact: prev/next + page count) and below them
- Result cards — the entire card is a clickable
Linkthat navigates to the source page - Header search —
HeaderSearchButtonon every page header expands into a search input on click; the/keyboard shortcut opens the search input from any page - 300ms debounce on input
- Highlighted snippets — matched text wrapped in
<mark>tags - Typo tolerance — "Krishna", "Krsna", "Krishn" all find Kṛṣṇa results
- Diacritic insensitivity —
_asciishadow fields indexed alongside originals (e.g., "Yashodanandana" matches "Yaśodanandana") - Prefix matching — partial words like "sarv dharman parit" match
sarva-dharmān parityajya - Glossary results — glossary pages read
?term=from the URL so a search result lands on the correct term (with diacritic-insensitive matching) - Defensive null handling — the frontend always treats a null
resultspayload as an empty array - Files:
app/search/page.tsx,app/search/search-content.tsx,app/api/search/route.ts,components/header-search.tsx
Search relevance. Search is tuned to find verses where the verse text itself contains the query, not commentaries that cite it. Verse purports are intentionally excluded from the default search so results stay focused on primary sources. In practice this means searching for sarva dharman parityajya returns BG 18.66 first (the actual verse) rather than the many commentaries that quote it.
Per-Page Filters
- 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
Audio Player
A site-wide floating audio player for transcription recordings (and future music library). Built with framer-motion for animations.
- Desktop: Centered floating bar (max-width 680px) with cover image, track info, transport controls (prev/play/next), volume slider, source link, close button
- Mobile: Full player shows two rows: track info row + centered transport controls
- Auto-minimize: After 8 seconds of inactivity on both mobile and desktop, the player auto-minimizes to a floating pill. The minimized pill shows cover image with a circular progress ring and audio wave animation. Tap/click to expand.
- X button behavior: Minimizes the player if audio is playing; stops playback entirely if audio is paused
- Clicking outside the player: Minimizes it (does not stop playback)
- Z-index:
z-40— below text selection toolbar (z-80), drawers (z-90), modals (z-100) - Hidden when selection toolbar is active on mobile to avoid overlap
- Forced dark surface (
bg-[#1c1c1e]) for accessibility contrast regardless of theme - Keyboard shortcuts: Space (play/pause), ←/→ (seek ±10s), ↑/↓ (volume), M (mute), Esc (close)
- Progress seeker: 8px tall bar at top of player, click/drag to seek
- Volume: Persisted to localStorage. Mobile relies on hardware volume buttons
- framer-motion: Spring animations for enter/exit, AnimatePresence for minimize/expand transitions, motion.div for audio wave bars
Components:
components/audio-player/audio-context.tsx— React context + provider, manages<audio>elementcomponents/audio-player/floating-player.tsx— Floating player UIcomponents/audio-player/audio-wave.tsx— Reusable animated audio wave barscomponents/audio-player/index.ts— Barrel exports
The AudioPlayerProvider wraps the entire app in layout.tsx. The FloatingPlayer is rendered before SiteFooter.
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
BFF_URL=http://localhost:8080 # Go BFF API server URL (default: http://localhost:8080)
ALLOW_RTF=true # Enable RTF viewer (development only)
NEXT_PUBLIC_SITE_URL=https://prabhupadasays.org # Public site URL for OG images
No new vars are needed for the frontend search feature — search goes through the BFF, which has
TYPESENSE_URLandTYPESENSE_API_KEYconfigured server-side.
How to Run
# 1. Start the Go BFF server (required — all data comes from the BFF)
cd spsays-bff && go run cmd/api/main.go # Starts on :8080 by default
# 2. Development (from knowledgebase/)
npm run dev # Next.js dev server with Turbopack
# 3. Build
npx next build
# Extraction & seeding scripts are in extractor/ — see extractor/scripts/
Note
: No
npx prisma generate,npx prisma db push, or MongoDB connection string needed in the frontend. The BFF server must be running for any page to load data.
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.
Transcription JSON Schema
{
"slug": "720911sb-los-angeles",
"name": "Śrīmad-Bhāgavatam 1.2.6",
"type": "lecture",
"date": "September 11, 1972",
"year": 1972,
"month": 9,
"day": 11,
"place": "Los Angeles",
"context": null,
"reference": "SB 1.2.6",
"durationMinutes": 45,
"participants": ["Prabhupāda", "Devotees"],
"audioUrl": "https://s3.prabhupadasays.com/sp-audio/...",
"content": [
{
"text": "So Kṛṣṇa consciousness movement...",
"format": "paragraph",
"alignment": "left",
"speaker": "Prabhupāda"
},
{
"text": "<i>oṁ namo bhagavate...</i>",
"format": "verse",
"alignment": "center",
"speaker": null
}
]
}
Content block formats: "paragraph" (body text), "verse" (centered italic), "quote" (translation/purport), "heading" (TEXT/TRANSLATION/PURPORT labels), "note" (editorial notes).
Known Issues
-
BFF dependency — The knowledgebase requires the Go BFF server to be running; all pages will fail to load data if the BFF is down.
-
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). -
Transcription BSON fallback — 1 document stores content as
contentJsonstring due to BSON wire protocol limits;getTranscription()transparently parses it -
Empty transcriptions — 30 entries have no English text content (Hindi/Bengali recordings); the UI shows "No transcription available" with the audio player still accessible
-
Audio player z-index — Player is hidden when text selection toolbar is active on mobile to avoid overlap
-
Search depends on Typesense — Search depends on Typesense being available via the BFF; if Typesense is down, search will return empty results but the rest of the site is unaffected.