38 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)
- 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
│ └── 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)
│ ├── 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
- 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
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