Only "Download backup" recorded the date, so downloading from the account left Home saying "You haven't downloaded a backup yet". Both now record it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Bible Study App
A self-hosted Bible study tool with notes, projects, and user accounts.
Requirements
- Node.js v18 or higher — nodejs.org
- npm (bundled with Node.js)
- GCC / make (only needed for production/server installs — required to build the
better-sqlite3native module)
Quick Start
git clone https://github.com/nmemmert/study-bible-project.git
cd study-bible-project
bash setup.sh
setup.sh installs dependencies, builds the optimized frontend, and runs one
production server (frontend + API) on http://localhost:5173. Set APP_PORT
to use a different port. If the build fails, the previously running server is
left untouched. bash restart.sh pulls the latest code and does the same.
Stop / logs:
kill $(cat .api.pid)
tail -f .api.log
Development mode (hot reload)
bash setup.sh --dev
Starts the API on http://localhost:3001 and the Vite dev server on http://localhost:5173. Dev mode is much slower, so don't use it for real users.
Optional keys (set in .env or the environment)
| Variable | What it turns on |
|---|---|
SESSION_SECRET |
A long random string that signs login cookies. Optional: if unset in production, the server makes one and keeps it in DATA_DIR/.session-secret. |
ADMIN_EMAIL |
The one admin account. |
ESV_API_KEY, API_BIBLE_KEY |
ESV, NLT, CSB and NASB in the Reader. |
IQBIBLE_API_KEY |
IQ Bible: more commentaries, lexicons (BDB, LSJ, Abbott-Smith), places, topics, people, textual notes, Gospel parallels, daily verse and Spurgeon devotional, plan calendar export, more audio narrations, and background for podcast prompts. Hidden when unset. |
IQBIBLE_CACHE_HOURS |
Leave unset unless IQ Bible has given written permission to cache non-verse data; only verse/chapter text is cached by default (24h), as their terms require. |
BACKUP_KEEP, BACKUP_DISABLED=1 |
The server saves a snapshot of the whole database once a day to DATA_DIR/backups (default: keep 7). Restore with scripts/restore-data.sh. |
ALLOW_PRIVATE_NTFY=1 |
Lets reading reminders use an ntfy server on your own network (blocked by default). |
Production Install (Ubuntu / systemd)
Installs the app as a persistent systemd service under /opt/study-app.
# Install Node.js 20 (if not already installed)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
# Install build tools (required for better-sqlite3)
sudo apt-get install -y build-essential python3
# Clone and install
git clone https://github.com/nmemmert/study-bible-project.git
cd study-bible-project
sudo bash deploy/install.sh
The installer will:
- Install Node.js dependencies and build the frontend
- Create a
study-appsystem user - Register and start a systemd service
Useful commands after install:
systemctl status study-app # Check service status
journalctl -u study-app -f # Stream logs
systemctl restart study-app # Restart after an update
Open the firewall port (if needed):
sudo ufw allow 3001/tcp
sudo ufw reload
The app listens on port 3001 by default. Set the PORT environment variable in the systemd unit to change it.
Updating (Production)
cd /path/to/study-bible-project
git pull
sudo bash deploy/install.sh
The installer preserves the session secret across updates so logged-in users are not signed out.
Migrating to a New Machine
On the old machine — create a backup:
npm run backup
This creates study-app-backup_<timestamp>.zip in the project root.
On the new machine — restore after cloning and installing:
Development:
npm run restore study-app-backup_<timestamp>.zip
Production (after sudo bash deploy/install.sh completes):
sudo bash scripts/restore-data.sh study-app-backup_<timestamp>.zip --production
See scripts/backup-data.sh and scripts/restore-data.sh for details.
Project Structure
├── server/ # Express API + SQLite database
│ └── data/ # projects.db lives here (gitignored)
├── src/ # React frontend (Vite)
├── deploy/ # systemd service unit + install script
├── scripts/ # backup / restore helpers
└── setup.sh # Development quick-start
License
Private / personal use.
Development
npm run test:run # all unit and component tests
npm run test:e2e # real-browser tests (Playwright, in your installed Chrome)
npm run lint # ESLint (errors fail; warnings are advice)
The browser tests (e2e/) build the app, run it on port 3101 with an empty throwaway database (your real studies are never
touched), make an account, and click through the main flows: writing notes and the paste check, the daily five minutes and weekly
recall, comparing translations (Bible text is faked, so no internet is needed), and presenting on two screens. They use the
Chrome already on the computer, so there is no browser to download; install Chrome, or change channel in playwright.config.js
and run npx playwright install to use Playwright's own browser.
Who can sign up: the administrator (the ADMIN_EMAIL account) chooses Open, Invite only or Closed under Admin → Sign-ups, and makes single-use invite links there. The very first account can always be created.
Verse of the day push: with IQBIBLE_API_KEY set, each person can turn on a daily verse notification in Settings → Reading reminders (it goes to the same ntfy topic).
Forgotten passwords: the sign-in page's "Forgot your password?" sends a one-time code to the account's ntfy topic (the one used for reading reminders). Accounts without a topic still ask the administrator for a temporary password.