Files
spsays-bff/PROJECT_CONTEXT.md
T
2026-05-09 23:19:19 +05:30

17 KiB
Raw Blame History

Prabhupāda Says — BFF (Backend for Frontend)

What this project is

A Go-based Backend for Frontend (BFF) API server for prabhupadasays.org. It sits between the Next.js frontend (and future mobile apps) and the data layer — aggregating content from MongoDB, user data from PostgreSQL, search from Meilisearch, caching from DragonflyDB, and media from S3 into a unified API surface.


Tech Stack

  • Go 1.23 — API server
  • Chi v5 — lightweight HTTP router with middleware support
  • Zap — structured logging (uber-go/zap)
  • MongoDB — content database (books, verses, letters, essays, glossary, disciples, transcriptions)
  • PostgreSQL — relational data (users, bookmarks, collections, mentions, URL shortener)
  • Meilisearch — typo-tolerant full-text search across all content
  • DragonflyDB — Redis-compatible cache (API responses, rate limiting, sessions)
  • AWS S3 — media storage (avatars, images, audio files)
  • FCM + APNs — push notifications for Android and iOS
  • JWT — stateless authentication

Architecture

┌──────────────┐     ┌─────────────────────────────────────────┐
│  Next.js     │────▶│  Go BFF API (:8080)                      │
│  (frontend)  │     │                                          │
├──────────────┤     │  cmd/api/main.go → server.go → handlers │
│  Mobile Apps │────▶│                                          │
│  (future)    │     │  ┌──────────┐  ┌───────────────┐        │
└──────────────┘     │  │ Handlers │──│ Services      │        │
                     │  └──────────┘  └───────┬───────┘        │
                     │                        │                │
                     │  ┌─────────────────────┼──────────┐     │
                     │  ▼         ▼           ▼     ▼    ▼     │
                     │ Mongo   Postgres   Meili   S3  Dragonfly│
                     │ (content)(users,   (search)(media)(cache)│
                     │          mentions,                       │
                     │          URL short,                      │
                     │          relations)                      │
                     └─────────────────────────────────────────┘

Project Structure

spsays-bff/
├── cmd/
│   └── api/
│       └── main.go              → Entry point (config, logger, server, graceful shutdown)
├── internal/
│   ├── config/
│   │   └── config.go            → Environment config (all services: Mongo, Postgres, Meili, S3, etc.)
│   ├── server/
│   │   └── server.go            → Chi router setup, global middleware, route registration
│   ├── handler/                  → HTTP handlers (one file per domain)
│   │   ├── health.go            → Health check endpoint
│   │   ├── book.go              → Book routes (SB, CC, KB, BG, generic verse & prose)
│   │   ├── letter.go            → Letter routes (by year, recipient, location)
│   │   ├── essay.go             → Essay routes
│   │   ├── glossary.go          → Glossary routes (letters, terms)
│   │   ├── disciple.go          → Disciple routes (filter, search, aggregations)
│   │   ├── journal.go           → Journal routes
│   │   ├── magazine.go          → Magazine routes
│   │   ├── other_document.go    → Other-document routes
│   │   └── transcription.go     → Transcription routes (by year, place, type, slug)
│   ├── service/                  → Business logic layer (orchestrates repositories)
│   ├── repository/               → Data access layer (Mongo, Postgres, Meili, S3, Dragonfly)
│   │   ├── mongo.go             → MongoDB connection + database handle
│   │   ├── book_repo.go         → Book / verse queries
│   │   ├── letter_repo.go       → Letter queries
│   │   ├── essay_repo.go        → Essay queries
│   │   ├── glossary_repo.go     → Glossary queries
│   │   ├── disciple_repo.go     → Disciple queries
│   │   ├── journal_repo.go      → Journal queries
│   │   ├── magazine_repo.go     → Magazine queries
│   │   ├── other_document_repo.go → Other-document queries
│   │   └── transcription_repo.go → Transcription queries (with contentJson fallback)
│   ├── middleware/
│   │   ├── logger.go            → Zap-based request logging (method, path, status, duration)
│   │   ├── auth.go              → JWT Bearer token authentication + context user extraction
│   │   └── ratelimit.go         → In-memory token bucket rate limiter (→ DragonflyDB in production)
│   └── model/
│       ├── content.go           → Content models (Book, Verse, Letter, Essay, GlossaryEntry,
│       │                           Disciple, Transcription, ContentBlock, Synonym)
│       └── user.go              → User models (User, Bookmark, Collection, Mention, ShortURL)
├── pkg/                          → Public packages (importable by other projects)
│   ├── response/
│   │   └── response.go          → Standardized API response helpers (JSON, Error, Envelope, Meta)
│   ├── validator/
│   │   └── validator.go         → Field validation (Required, MaxLength, Email, In, etc.)
│   ├── push/                     → Push notification sender (FCM + APNs) — placeholder
│   └── shorturl/                 → URL shortener logic — placeholder
├── migrations/                   → PostgreSQL migrations (goose or golang-migrate)
├── go.mod                        → Module: github.com/prabhupadasays/spsays-bff
├── go.sum
├── Makefile                      → build, run, dev, test, clean, lint, tidy
├── .env.example                  → Template for all environment variables
└── .gitignore

API Routes

All routes are prefixed with /api/v1.

Health

Method Route Description
GET /health Server health check

Books

Method Route Description
GET /api/v1/books List all books (lightweight summaries)
GET /api/v1/books/sb SB book metadata
GET /api/v1/books/sb/{canto} SB canto chapter listing
GET /api/v1/books/sb/{canto}/{chapter} SB chapter verse index
GET /api/v1/books/sb/{canto}/{chapter}/verses SB paginated verses
GET /api/v1/books/sb/{canto}/{chapter}/{verse} SB single verse
GET /api/v1/books/cc CC book metadata
GET /api/v1/books/cc/{lila} CC līlā chapter listing
GET /api/v1/books/cc/{lila}/{chapter} CC chapter verse index
GET /api/v1/books/cc/{lila}/{chapter}/verses CC paginated verses
GET /api/v1/books/cc/{lila}/{chapter}/{verse} CC single verse
GET /api/v1/books/kb KB book metadata
GET /api/v1/books/kb/{volume} KB volume chapter listing
GET /api/v1/books/kb/{volume}/{slug} KB single chapter
GET /api/v1/books/bg BG book metadata
GET /api/v1/books/bg/{chapter} BG chapter verse index
GET /api/v1/books/bg/{chapter}/verses BG paginated verses
GET /api/v1/books/bg/{chapter}/{verse} BG single verse
GET /api/v1/books/{code} Any other book metadata
GET /api/v1/books/{code}/chapters Prose book chapter listing (no paragraphs)
GET /api/v1/books/{code}/chapters/{slug} Prose book single chapter
GET /api/v1/books/{code}/{chapter} Verse book chapter index
GET /api/v1/books/{code}/{chapter}/verses Verse book paginated verses
GET /api/v1/books/{code}/{chapter}/{verse} Verse book single verse

Letters

Method Route Description
GET /api/v1/letters Total letter count
GET /api/v1/letters/years Year → count aggregation
GET /api/v1/letters/recipients Recipient → count aggregation
GET /api/v1/letters/locations Location → count aggregation
GET /api/v1/letters/year/{year} Letters for a year
GET /api/v1/letters/recipient/{name} Letters for a recipient
GET /api/v1/letters/location/{name} Letters from a location
GET /api/v1/letters/{slug} Single letter

Essays

Method Route Description
GET /api/v1/essays All essay summaries
GET /api/v1/essays/{slug} Single essay

Glossary

Method Route Description
GET /api/v1/glossary All glossary entries
GET /api/v1/glossary/letters Letter → count mapping
GET /api/v1/glossary/letter/{letter} Entries for a letter (with diacritical grouping)
GET /api/v1/glossary/letter/{letter}/terms Term names only for sidebar
GET /api/v1/glossary/term/{term} Single entry by term

Disciples

Method Route Description
GET /api/v1/disciples Filtered list (?letter=&suffix=)
GET /api/v1/disciples/count Total + filtered counts
GET /api/v1/disciples/letters Letter → count aggregation
GET /api/v1/disciples/suffixes Suffix → count aggregation
GET /api/v1/disciples/search Search by name (?q=)

Journals

Method Route Description
GET /api/v1/journals All journal metadata
GET /api/v1/journals/{book} Single journal meta
GET /api/v1/journals/{book}/chapters Journal chapters
GET /api/v1/journals/{book}/chapters/{slug} Single chapter

Magazines

Method Route Description
GET /api/v1/magazines All magazine metadata
GET /api/v1/magazines/{book} Single magazine meta
GET /api/v1/magazines/{book}/issues Magazine issues
GET /api/v1/magazines/{book}/issues/{slug} Single issue

Other Documents

Method Route Description
GET /api/v1/other-documents All document metadata
GET /api/v1/other-documents/{book} Single document meta
GET /api/v1/other-documents/{book}/chapters Document chapters
GET /api/v1/other-documents/{book}/chapters/{slug} Single chapter

Transcriptions

Method Route Description
GET /api/v1/transcriptions Total transcription count
GET /api/v1/transcriptions/years Year → count aggregation
GET /api/v1/transcriptions/places Place → count aggregation
GET /api/v1/transcriptions/types Type distribution ({lectures, conversations})
GET /api/v1/transcriptions/year/{year} Transcriptions for a year (summaries)
GET /api/v1/transcriptions/place/{place} Transcriptions for a place (summaries)
GET /api/v1/transcriptions/type/{type} Transcriptions by type (lecture or conversation)
GET /api/v1/transcriptions/adjacent/{slug} Prev/next within same year (?year=N)
GET /api/v1/transcriptions/{slug} Single transcription (full content + audio URL)

Authenticated (JWT required) — planned

Method Route Description
POST /api/v1/auth/register User registration
POST /api/v1/auth/login User login (returns JWT)
POST /api/v1/auth/refresh Refresh JWT token
GET /api/v1/users/me Get current user profile
PUT /api/v1/users/me Update current user profile
GET /api/v1/collections List user's collections
POST /api/v1/collections Create a collection
POST /api/v1/collections/:id/items Add item to collection
DELETE /api/v1/collections/:id/items/:itemId Remove item from collection
GET /api/v1/mentions List user's mentions
POST /api/v1/mentions Create a mention
POST /api/v1/s Create a short URL
POST /api/v1/notifications/register Register device for push notifications

Data Models

Content Models (MongoDB)

Model Collection Description
Book book_meta Book metadata (title, author, chapters, etc.)
Verse verses Individual verses (BG, SB, CC, ISO, NOI, BS, MM, NBS)
Letter letters 6,800+ letters (1947–1977)
Essay essays 23 standalone essays
GlossaryEntry glossary 2,749 Sanskrit/Vedic terms
Disciple disciples 4,747 initiated disciples
Transcription transcriptions 3,787 lectures, conversations, philosophy discussions, SB dictations

User Models (PostgreSQL)

Model Table Description
User users User accounts (email, name, avatar, role)
Bookmark bookmarks Saved content references with optional notes
Collection collections User-created collections of bookmarks
Mention mentions Content shared/tagged by users
ShortURL short_urls Shortened URLs with click tracking

API Response Format

All responses follow a consistent envelope:

{
  "success": true,
  "data": { ... },
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "total_pages": 8
  }
}

Error responses:

{
  "success": false,
  "error": {
    "code": 400,
    "message": "validation failed"
  }
}

Middleware Stack

Middleware Description
RequestID Generates unique request ID (chi built-in)
RealIP Extracts real client IP from proxy headers
Logger Zap-based structured request logging
Recoverer Panic recovery (chi built-in)
Compress Gzip compression (level 5)
CORS Cross-origin resource sharing (frontend URL whitelisted)
Auth JWT Bearer token validation (applied to protected routes)
RateLimit Token bucket rate limiter (in-memory → DragonflyDB in production)

Environment Variables

# Server
APP_ENV=development          # "development" | "production"
PORT=8080

# MongoDB (content)
MONGO_URI=mongodb://...      # required
MONGO_DB=spsays

# PostgreSQL (users, relations)
POSTGRES_URI=postgres://...

# Meilisearch
MEILISEARCH_HOST=http://localhost:7700
MEILISEARCH_API_KEY=

# DragonflyDB / Redis
REDIS_URI=redis://localhost:6379

# S3
S3_REGION=
S3_BUCKET=
S3_ACCESS_KEY=
S3_SECRET_KEY=
S3_ENDPOINT=              # optional — for MinIO or S3-compatible services

# Push Notifications
FCM_CREDENTIALS_FILE=     # path to Firebase service account JSON
APNS_KEY_FILE=            # path to APNs auth key (.p8)
APNS_KEY_ID=
APNS_TEAM_ID=
APNS_BUNDLE_ID=

# JWT
JWT_SECRET=               # required in production
JWT_EXPIRATION=24h

# Frontend (CORS)
FRONTEND_URL=http://localhost:3000

How to Run

# Setup
cp .env.example .env       # then fill in values

# Development (with live reload — requires air)
make dev

# Build + run
make run

# Build only
make build

# Run tests
make test

# Lint (requires golangci-lint)
make lint

# Tidy deps
make tidy

Relationship to Other Projects

Project Path Description
knowledgebase ../knowledgebase/ Next.js frontend — consumes this BFF's API
extractor ../extractor/ Python/TS extraction scripts + raw data + seed scripts
spsays-bff ./ (this project) Go BFF API server

The frontend currently fetches directly from MongoDB via Prisma. The migration plan:

  1. ✅ Done — BFF API routes matching current Prisma queries
  2. Add Meilisearch indexing + search endpoints
  3. Add PostgreSQL for user features (auth, bookmarks, collections, mentions)
  4. Switch frontend from Prisma to BFF API calls
  5. Add mobile app support (same API, push notifications)

Design Principles

  • internal/ — private to this module (handlers, services, repositories, middleware, models, config)
  • pkg/ — public packages that could be imported by other projects (response helpers, validators, push sender)
  • Repository pattern — data access isolated behind interfaces (easy to swap Mongo ↔ Postgres, mock for tests)
  • Service layer — business logic between handlers and repositories (orchestration, validation, caching)
  • Handler layer — thin HTTP handlers that parse requests, call services, return responses
  • No ORM — use native drivers (mongo-go-driver, pgx) for full control
  • Explicit book routing — SB, CC, and KB have dedicated route groups to avoid URL ambiguity with generic {code}/{chapter}/{verse} patterns