The Bible study app is currently a MonoGame C# desktop application (13 views, 3 SQLite databases, 31K verses, Greek/Hebrew interlinear, commentaries, cross-references, personal notes, pixel art atmosphere). To distribute it to a wider audience, we're building a web-first SaaS version with user accounts, tiered pricing, and AI Bible Q&A. The desktop app continues to exist — this is a new project.
| Decision | Choice |
|---|---|
| Frontend | SvelteKit (Svelte 5 runes) |
| Content DB | Turso (edge SQLite, same schema as bible.db) |
| User data / Auth | Supabase (PostgreSQL + Auth + RLS) |
| Payments | Stripe (via Supabase SvelteKit template) |
| AI model | Qwen 3.5 4B (Q4_K_M quantized, Ollama) |
| AI hosting | Hetzner CX32 (€7/mo, 4 vCPU, 8GB RAM, CPU inference) |
| Frontend hosting | Vercel (free tier) |
| Project location | ~/Code/BibleWeb/ (separate repo) |
| Styling | Tailwind CSS + custom pixel art theme |
| ORM | Drizzle (for Turso queries) |
| Search | Orama (client-side FTS, replaces FTS5 which Turso doesn't support) |
| Feature | Free | Pro ($5/mo) | Premium ($10/mo) |
|---|---|---|---|
| Bible reader (EN) | ✓ | ✓ | ✓ |
| Jesus speech highlighting | ✓ | ✓ | ✓ |
| Basic search | ✓ | ✓ | ✓ |
| Themes + Parables browser | ✓ | ✓ | ✓ |
| Notes (limit: 5) | ✓ | — | — |
| Notes (unlimited) | — | ✓ | ✓ |
| Note cross-linking | — | ✓ | ✓ |
| Dutch Statenvertaling | — | ✓ | ✓ |
| Parallel Gospel reader | — | ✓ | ✓ |
| Interlinear Greek/Hebrew | — | ✓ | ✓ |
| Commentaries | — | ✓ | ✓ |
| Cross-reference graph | — | ✓ | ✓ |
| Offline download | — | ✓ | ✓ |
| AI Bible Q&A | — | — | ✓ |
| Personal Translation Builder | — | — | ✓ |
| Note export | — | — | ✓ |
| Service | At launch (0-100 users) | Growing (100-1000) |
|---|---|---|
| Supabase | $0 (free tier) | $25/mo |
| Vercel | $0 (free tier) | $20/mo |
| Turso | $0 (free tier) | $0 |
| Hetzner CX32 (AI) | €7/mo | €7-17/mo |
| Stripe | % per transaction | % per transaction |
| Total | ~€7/mo | ~€50/mo |
~/Code/BibleWeb/
package.json
pnpm-workspace.yaml
turso.toml
drizzle.config.ts
apps/
web/ # SvelteKit app → Vercel
src/
lib/
server/
db.ts # Turso + Drizzle client
supabase.ts # Supabase server client
stripe.ts # Stripe helpers
ai.ts # Ollama API client (calls Hetzner)
tier.ts # Feature gating (free/pro/premium)
queries/ # Ported from BibleDatabase.cs (~30 methods)
verses.ts
greek-words.ts
strongs.ts
jesus-speech.ts
commentaries.ts
cross-refs.ts
pericopes.ts
themes.ts
parables.ts
search.ts
components/
bible/
VerseText.svelte
VerseList.svelte
InterlinearPopup.svelte
CommentaryDrawer.svelte
NoteEditor.svelte
SearchInput.svelte
ChapterNav.svelte
BookPicker.svelte
CrossRefGraph.svelte # Canvas 2D force-directed
ParallelColumns.svelte
layout/
Sidebar.svelte
CommandPalette.svelte
TierGate.svelte
ui/ # Button, Modal, Drawer, etc.
stores/
user.ts # $state rune-based
reader.ts # Current book/chapter/verse
settings.ts
notes.ts
i18n/
en.ts # Ported from Loc.cs (~200 keys)
nl.ts
index.ts
theme/
colors.ts # Ported from Theme.cs
fonts.css # m5x7 WOFF2 + Noto Sans
utils/
text.ts # Ported from TextUtils.cs
popup.ts # Ported from PopupBuilder.cs
routes/
+layout.svelte
+layout.server.ts # Supabase session + user tier
(app)/
read/[[book]]/[[chapter]]/+page.svelte # ReaderView
search/+page.svelte # SearchView
parallel/+page.svelte # PericopeList
parallel/[pericopeId]/+page.svelte # ParallelView
crossrefs/[book]/[chapter]/[verse]/+page.svelte # CrossRefView
themes/+page.svelte # ThemeBrowser
themes/[id]/+page.svelte
parables/+page.svelte # ParablesView
parables/[id]/+page.svelte
teachings/+page.svelte # JesusTeachingsView hub
notes/+page.svelte # NotesView
settings/+page.svelte # SettingsView
ask/+page.svelte # AI Bible Q&A (Premium)
(auth)/
login/+page.svelte
register/+page.svelte
callback/+server.ts
api/
webhooks/stripe/+server.ts
static/
backgrounds/ # Pre-rendered pixel art PNGs
fonts/m5x7.woff2
svelte.config.js
tailwind.config.ts
packages/
db/ # Shared Drizzle schema
src/schema/
bible.ts # Turso tables (books, verses, greek_words, etc.)
user.ts # Supabase tables (notes, translations, settings)
scripts/
migrate-bible-db.ts # Push bible.db → Turso
build-search-index.ts # Generate Orama index JSON from Turso
export-backgrounds.sh # Render pixel art scenes to PNGs
| MonoGame View | SvelteKit Route | Tier |
|---|---|---|
| MainMenu | Sidebar (always visible) | Free |
| Reader / JesusWords | /read/[[book]]/[[chapter]] |
Free |
| Search | /search |
Free |
| ChapterSelect | BookPicker modal in reader | Free |
| ThemeBrowser | /themes + /themes/[id] |
Free |
| Parables | /parables + /parables/[id] |
Free |
| JesusTeachings | /teachings |
Free |
| ParallelView | /parallel/[pericopeId] |
Pro |
| PericopeList | /parallel |
Pro |
| CrossRefGraph | /crossrefs/[book]/[chapter]/[verse] |
Pro |
| NotesView | /notes |
Free (5 limit) / Pro |
| Settings | /settings |
Free |
| (NEW) AI Chat | /ask |
Premium |
Pre-render MonoGame scenes to static PNGs + CSS effects:
box-shadow: inset), fire flicker (animation), subtle particle <canvas> overlaySceneCatalog logic)Turso doesn't support FTS5. Use Orama (10KB, client-side):
/ask route calls Ollama's OpenAI-compatible APIserwist SvelteKit plugin| C# Source | Port To | What |
|---|---|---|
BibleGame/BibleDatabase.cs (996 lines) |
lib/server/queries/*.ts |
All 30 database query methods → Drizzle |
BibleGame/Models/DisplayModels.cs |
TypeScript interfaces | Verse, GreekWord, StrongsEntry, etc. |
BibleGame/PopupBuilder.cs |
lib/utils/popup.ts |
Interlinear popup construction logic |
BibleGame/Loc.cs |
lib/i18n/en.ts + nl.ts |
~200 localization strings + book names |
BibleGame/Theme.cs |
lib/theme/colors.ts |
15 named colors → CSS custom properties |
BibleGame/TextUtils.cs |
lib/utils/text.ts |
SanitizeText, ExtractShortGloss, etc. |
BibleGame/NoteStore.cs |
Supabase tables + RLS | verse_notes, chapter_notes, note_links |
BibleGame/TranslationStore.cs |
Supabase table + RLS | word_selections |
BibleGame/UserData.cs |
Supabase user_settings | Reading position, preferences |
Goal: SvelteKit + Turso + Supabase auth + reader. Deployable.
pnpm, SvelteKit, Tailwind, Vercel adapter)bible.db dump, configure Drizzle schemaTheme.cs → CSS custom properties, convert m5x7 to WOFF2VerseText.svelte, VerseList.svelte, ChapterNav.svelte/read/[[book]]/[[chapter]] with server-side data loadingBookPicker modal, Jesus speech highlightingLoc.cs → i18n (EN/NL)Sidebar.svelte navigationDeliverable: Live URL — users can read any chapter, create an account. ✅
/search page with history, Jesus-only toggle, grouped results/notes)/bookmarks page)CommandPalette.svelte (Ctrl+K / Cmd+K, ~70 commands, all 66 books)Deliverable: Users can search, take notes, bookmark. Position syncs across devices. ✅
/pricing) with 3-tier feature comparisonTierGate.svelte wrapper componentlib/tier.ts, lib/server/user-tier.ts, user store)/api/webhooks/stripe) — body is TODO, not yet functionallib/server/stripe.ts stub — createCheckoutSession / handleWebhook throw "not configured yet"/parallel/[pericopeId] — multi-column responsive layout (EN/NL/Both toggle, tier-gated)/parallel)InterlinearPopup.svelte (Greek/Hebrew + Strong's, personal translation builder)CommentaryDrawer.svelte (Henry, Gill, Kanttekeningen — tier-gated)/themes), Parables browser (/parables), Jesus Teachings hub (/teachings)Remaining for full Phase 3 completion:
createCheckoutSession, implement webhook handler to update user tier in Supabase, add checkout button to pricing pageDeliverable: All 13 views ported. Stripe payments work. Pro tier functional. (Views done; Stripe ❌)
+error.svelte) — Custom error page with status code + error ID display.trim() on all inputs; Zod not used (acceptable for now)public, max-age=86400, s-maxage=604800 on commentaries, interlinear, cross-refs, OG images, translations; no-cache on search/teachings prerendered; /pricing and /themes list not yet prerenderedDeliverable: Production-ready API layer, fast queries, graceful error handling. ✅ (mostly)
colors.ts — 4 palettes: dark, light, sepia, high-contrast$state:root/settings — Button group toggles all 4 themesprefers-color-scheme auto-detect — Not implemented (manual selection only)Deliverable: Users can switch between dark/light/sepia/high-contrast themes. ✅
verse_texts table in schema — Proper join table for multiple translationstranslationId parameterDeliverable: Users can read in any supported translation. ✅ (search still EN-only)
/crossrefs/[book]/[chapter]/[verse] — Interactive force-directed graph, tier-gated, vote filter (1–20)word_selections table)Deliverable: All Pro + Premium content features work. ✅ (note export uncertain)
lib/server/ai.ts) — Streaming + non-streaming, configurable via OLLAMA_URL / OLLAMA_MODEL env vars (defaults: Qwen 3.5 4B)lib/server/rag.ts, 587 lines) — Reference parsing (60+ book aliases, EN+NL), keyword search, commentary retrieval, user notes context/ask chat page (Premium only) — Streaming responses, conversation sidebar, status phase markersmarkSavedToNotes() in chat store/api/ask, 60 req/60s on /api/search (IP-based, in-memory)Note: Conversation history is localStorage-based, not Supabase (no server-side persistence across devices).
Deliverable: Premium users can ask Bible questions, save AI answers to notes. ✅
/api/ and /auth/ routesmanifest.json with icons, standalone mode, theme color, categoriesDeliverable: Basic offline + installable PWA. ✅ (advanced offline/polish items pending)
/api/errors endpoint logs to console onlynavigation, explore, reading, settings, cross-refs, search, parablesrobots.txt presentRemaining for launch:
After each phase, verify:
pnpm dev runs locally without errorsKey tables (all with RLS — users can only access their own data):
profiles (extends auth.users)user_settings (reading position, preferences)bookmarks (book_id, chapter)verse_notes (book_id, chapter, verse, content)chapter_notes (book_id, chapter, content)note_links (bidirectional from/to verse)word_selections (personal translation word glosses)subscriptions (Stripe customer/subscription IDs, tier)ai_conversations + ai_messages (Premium chat history)