A web site to read and share comments about Bible verses.
This project started in 2020 as a place to share interpretations of the
Bible and answer difficult verses, born from personal note-taking on
Bible margins. The current incarnation lives as a Next.js + MongoDB
application under nextjs/.
- Next.js 15 — App Router, Server Components, Server Actions, Route Handlers
- MongoDB via Mongoose — persistence layer
- NextAuth.js v5 — credentials auth with bcrypt password hashing
- Tailwind v4 —
@themetokens in CSS, notailwind.config.tscolors - next-themes — dark mode (
attribute="class", system-aware) - pino — structured server logs (
logger.errorwired into all5xxpaths) - Sentry — optional error reporting (no-op without
SENTRY_DSN) - Zod — request body validation across 9 schemas
- Vitest — unit tests for use cases + helpers (89 tests)
- Cypress 15 — integration + E2E tests with
mongodb-memory-server(~58 tests across auth, RBAC, comments, discussions, mentions, notifications, moderation, search, SEO)
The Next.js app under nextjs/src/ follows Clean
Architecture, separating domain logic from framework specifics.
src/
├── domain/ # Entities (Comment, Discussion, User, ...) + repository interfaces
├── application/ # Use cases — orchestrate domain operations
├── infrastructure/ # Mongoose models + repository implementations
├── lib/ # Auth, logger, parse-body, schemas, share-verse, mentions
├── services/ # Client-side service façades (single source of HTTP/Action calls)
├── app/ # Next.js routes
│ ├── actions/ # Server Actions (comments, discussions, users, moderation, notifications)
│ ├── api/ # Route Handlers (reads + endpoints called by services)
│ ├── (pages)/ # SSR pages: home, profile, chapter, discussion, admin, ...
│ └── _components/ # Shared client components scoped to app/
├── components/ # Reusable presentational components
└── contexts/ # NotificationContext (toasts)
Data flow for mutations (Server Actions):
Client component
└─> services/{comments,discussions,users,moderation,notifications}.ts
└─> app/actions/*.ts (use server)
└─> application/use-cases/*
└─> infrastructure/repositories/Mongo*Repository
└─> Mongoose models
Data flow for reads: the same services hit axios.get('/api/...'),
which lands on a Route Handler that calls a use case. Reads stay on
HTTP because they often run under cache: "no-store" in client effects
and don't need the bundle savings of Server Actions.
The discriminated union returned by each Server Action,
ActionResult<T> = { ok: true, data: T } | { ok: false, error: string },
gets translated back to an axios-shaped Error by
services/_action-error.ts so
existing catch blocks that read err.response?.status keep working.
- Bible reading — 30,000+ verses across 66 books, with comments attached per verse or per chapter title
- Tagged comments — devotional, exegetical, personal, inspired (multi-tag); like / report / edit / delete with owner+moderator gates
- Discussions — open-ended threads anchored to a verse, with per-answer editing
@mentions— parsed in comments and discussion answers; targets receive a notification- Notification feed — bell with badge in Header, polling every 60s, mark-as-read on click + mark-all-read
- Moderation panel at
/admin/moderation— reports list, clear reports, delete comment, promote/demote moderators by email - Profile — user comments + favorites tabs, profile fields (belief, state), change password, delete account
- Search — unified endpoint
/api/search/unifiedcovering verses, comments, and users; debounced header dropdown - Copy verse with reference to clipboard
- Dark mode + adjustable text size (persisted in
localStorage) - Mobile responsive — sidebar drawer, swipe between chapters, keyboard nav (← / → / Esc) on the chapter page
- SEO —
generateMetadataper page,app/sitemap.ts,app/robots.ts, OG/Twitter cards
cd nextjs
cp .env.local.example .env.local # set MONGODB_URI, NEXTAUTH_SECRET
npm install
npm run dev # http://localhost:3000 (start a Mongo separately, or use `npm run dev:mongo` for an in-memory one)npm run dev orchestrates an in-memory Mongo instance and pipes its
URI into the Next.js process — no Docker needed for local development.
Run the unit tests:
npm testRun the Cypress integration suite end-to-end with the same in-memory Mongo:
npm run cy:test # headless (CI-equivalent)
npm run cy:test:dev # interactive (next dev + cypress open)See nextjs/cypress/README.md for the
full Cypress setup, fixtures, and which specs are wired up.
Bundle analysis:
npm run analyze # writes HTML report under .next/analyze/The original architecture (a Python web scraper in scrapy/, a
CRA + Material UI React frontend in frontend/, an Express +
SQLite backend in backend/) was migrated fully to Next.js +
MongoDB. The legacy directories were removed once feature parity
hit 100%.
A Program Violin for His Glory ~ Jennifer Jeon <3

