7.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Bibdle is a daily Bible verse guessing game built with SvelteKit 5. Players read a verse and try to guess which book of the Bible it comes from. The game provides feedback hints (Testament match, Section match, Adjacent book, etc.) similar to Wordle-style games. Progress is stored locally in the browser and a new verse is generated daily.
You are able to use the Svelte MCP server, where you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:
(Make sure you use the Svelte agent to execute these commands)
Available MCP Tools:
1. list-sections
Use this FIRST to discover all available documentation sections. Returns a structured list with titles, use_cases, and paths. When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start of the chat to find relevant sections.
2. get-documentation
Retrieves full documentation content for specific sections. Accepts single or multiple sections. After calling the list-sections tool, you MUST analyze the returned documentation sections (especially the use_cases field) and then use the get-documentation tool to fetch ALL documentation sections that are relevant for the user's task.
3. svelte-autofixer
Analyzes Svelte code and returns issues and suggestions. You MUST use this tool whenever writing Svelte code before sending it to the user. Keep calling it until no issues or suggestions are returned.
Tech Stack
- Framework: SvelteKit 5 with Svelte 5 (uses runes:
$state,$derived,$effect,$props) - Styling: Tailwind CSS 4
- Database: SQLite with Drizzle ORM
- Auth: Session-based authentication using Bun's built-in cryptographically secure functions
- Deployment: Node.js adapter for production builds
- ML:
@xenova/transformersfor verse embeddings (initialized in server hook) (currently disabled, was a test for a cancelled project)
Development Commands
# Start development server
bun run dev
# Type checking
bun run check
bun run check:watch
# Run tests
bun test
bun test --watch
bun test tests/timezone-handling.test.ts # Run a single test file
# Build for production
bun run build
# Preview production build
bun run preview
# Database operations
bun run db:push # Push schema changes directly (avoid in prod)
bun run db:generate # Generate migrations
bun run db:migrate # Run migrations
bun run db:studio # Open Drizzle Studio GUI
Critical: Date/Time Handling
Bibdle is played by users across many timezones worldwide. The verse shown to a player must always be the verse for the calendar date at their location — not the server's timezone, not UTC. A user in Tokyo on Wednesday must see Wednesday's verse, even if the server (or a user in New York) is still on Tuesday.
NEVER use server time or UTC time for user-facing date calculations.
- Get today's date client-side:
new Date().toLocaleDateString("en-CA")→YYYY-MM-DD - Pass the date to the server as a query param or POST body (
localDate) - Server-side date arithmetic must use UTC methods on the client-provided date string:
new Date(dateStr + 'T00:00:00Z')+setUTCDate/getUTCDate src/routes/+page.tshasssr = falseso the load runs client-side with the true local date- Never set the user-facing URL to include their date as a parameter. It should always be passed to an API route behind the scenes if needed.
Streak Calculation
A streak counts consecutive calendar days (in the user's local timezone) on which the user completed the puzzle. The rules:
- The client passes its local date (
localDate) to the streak API. The server never uses its own clock. - A streak is active if the user has completed today's puzzle or yesterday's puzzle (they still have time to play today).
- Walk backwards from
localDatethrough thedailyCompletionsrecords, counting each day that has a completion. Stop as soon as a day is missing. - A streak of 1 (completed only today or only yesterday, with no prior consecutive days) is not displayed — the minimum shown streak is 2.
- "Yesterday" and all date arithmetic on the server must use UTC methods on the client-provided date string to avoid timezone drift:
new Date(localDate + 'T00:00:00Z'), thensetUTCDate/getUTCDate.
Architecture
Database Schema (src/lib/server/db/schema.ts)
- user:
id,firstName,lastName,email(unique),passwordHash,appleId(unique),isPrivate - session:
id(SHA-256 hash of token),userId(FK),expiresAt - daily_verses: Cached daily verses with book ID, verse text, reference, and date
- dailyCompletions: Game results per user/date with guess count, grade, book; unique on
(userId, date)
Sessions expire after 30 days and auto-renew when < 15 days remain.
Bible Data (src/lib/types/bible.ts)
The bibleBooks array contains all 66 Bible books with metadata:
- Testament (old/new), Section (Law, History, Wisdom, Prophets, Gospels, Epistles, Apocalyptic)
- Order (1-66, used for adjacency detection)
Daily Verse System (src/routes/+page.server.ts)
getTodayVerse() checks the database for today's date, fetches a verse if missing, caches permanently, and returns verse with book metadata.
Game Logic (src/routes/+page.svelte)
State Management:
guessesarray stored in localStorage keyed by date:bibdle-guesses-${date}- Each guess tracks: book, testamentMatch, sectionMatch, adjacent
isWonderived from whether any guess matches the correct book
Hint System, for share grid:
- ✅ Exact match | 🟩 Section match | 🟧 Testament match | ‼️ Adjacent book | 🟥 No match
Authentication System (src/lib/server/auth.ts)
- Token generation: base64-encoded random bytes; stored as SHA-256 hash in DB
- Cookie name:
auth-session - Anonymous users: identified by a client-generated ID; stats migrate on sign-up via
migrateAnonymousStats() - Apple Sign-In supported via
appleIdfield
Stats & Streak (src/routes/stats/)
- Stats page requires auth; returns
requiresAuth: trueif unauthenticated - Streak calculated client-side by calling
GET /api/streak?userId=X&localDate=Y - Streak walk-back: counts consecutive days backwards from
localDatethrough completed dates - Minimum displayed streak is 2 (single-day streaks suppressed)
API Endpoints
POST /api/daily-verse— Fetch verse for a specific datePOST /api/submit-completion— Submit game result with statsGET /api/streak?userId=X&localDate=Y— Current streak for userGET /api/streak-percentile— Streak percentile ranking
Key Files
src/routes/+page.svelte— Main game UI and client-side logicsrc/routes/+page.server.ts/+page.ts— Server load (verse) + client load (ssr: false)src/routes/stats/+page.svelte/+page.server.ts— Stats UI and server calculationssrc/lib/server/auth.ts— Session management, password hashing, anonymous migrationsrc/lib/server/bible-api.ts— Random verse fetching from local XML Biblesrc/lib/server/bible.ts— Bible book utility functionssrc/lib/types/bible.ts— Bible books data and TypeScript typessrc/lib/server/db/schema.ts— Drizzle ORM schemasrc/hooks.server.ts— Session validation hook; initializes ML embeddingstests/— Bun test suites (timezone, game, bible, stats, share, auth migration)
Environment Variables
Required in .env:
DATABASE_URL— Path to SQLite database file (e.g.,./local.db)
Deployment
Uses @sveltejs/adapter-node. See bibdle.service systemd configuration.
A Note
The main developer of this project is still learning a lot about developing full-stack applications. If they ask you to do something, make sure they understand how it will be implemented before proceeding.