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