Ironsworn TTRPG character tracker. Manage characters, track progress, roll moves, consult oracles, and run expeditions — all in a web-based interface with real-time state persistence.
- This was a first foray into using Claude to do all the coding. It's an experiment not a social commentary.
- That being said, the AI generated images for foes are slop, I'd be open to working with a willing artist to make these much nicer.
- I am not a designer, suggestions for improving the UI are most welcome.
- I have probably misintrepreted or missed a rule here or there, bug reports are definitely welcome.
- Ironsworn and the Delve Expansion are incredible RPGs, I highly encourage you to support Shawn Tomkin and purchase his work.
A final note: The YRT expansion that is referred to is a side project I'm working on set in a post-apocalyptic world where technology is indistinguishable from magic. I'm not ready to release anything yet but you can see some of the the workings in the Conclave spells, the use of mana, and some Oracles.
| Layer | Technology |
|---|---|
| Frontend | SvelteKit 2 + Svelte 5 (runes), adapter-node SSR |
| API | Fastify 5, TypeScript, Zod validation |
| Database | PostgreSQL 16 with Row-Level Security (Drizzle ORM) |
| Cache | Redis (Valkey) — rate limiting, maintenance mode |
| Auth | JWT RS256 (15-min access + 30-day rotating refresh tokens, auto-refresh in hooks) |
| Process | PM2 (cluster mode for API, fork for web) |
| Proxy | Nginx with TLS (Let's Encrypt), rate limiting |
ironledger/
apps/
api/ Fastify REST API (port 3000)
web/ SvelteKit frontend (port 5173 dev / 3001 prod)
packages/
shared/ Shared TypeScript types and game data
infra/
nginx/ Production Nginx config
scripts/ Server setup, deploy, backup scripts
docker/ Dev database containers
docs/ Feature documentation
- Node.js 22+
- PostgreSQL 16+ (or Docker)
- Redis 7+ (or Docker)
# 1. Clone and install
git clone <repo-url> && cd ironledger
npm install
# 2. Start database services (Docker)
docker compose up -d
# Or use: ./infra/scripts/dev-db.sh up
# 3. Create .env from template
cp .env.example .env
# Edit .env — generate JWT keys with:
# openssl genrsa -out private.pem 2048
# openssl rsa -in private.pem -pubout -out public.pem
# 4. Run database migrations
npm run migrate
# 5. Seed development data (optional)
npm run seed --workspace=apps/api
# 6. Start dev servers (two terminals)
npm run dev # API on :3000
npm run dev:web # Web on :5173| Account | Password | |
|---|---|---|
| Admin | [email protected] |
adminpassword123! |
| User | [email protected] |
devpassword123! |
- Create and manage Ironsworn characters
- Full character sheet with stats, tracks, assets, and vows
- Auto-save with 1500ms debounce
- Complete Ironsworn move reference with picker grid
- Action, progress, and spell rolls with 3D animated dice
- Live roll formula display (e.g.,
d6 + iron[3] + adds[+1] vs d10 & d10) between spinners and roll button - Data-driven progress routing: each progress move reads from the correct track (foe, journey, site, bonds, failures) via
progressSourcefield - Move precondition checking (disables moves with unmet requirements)
- Burn momentum to upgrade roll outcomes
- Clickable move cross-references in outcome text
- Strong Hit / Weak Hit / Miss outcomes shown in move detail view
- Oracle table consultation with random rolls
- Linked oracle chains
- "Roll Twice" results auto-combine two independent re-rolls into one result
- Full foe catalogue from Ironsworn core, Delve supplement, and YRT homebrew
- Per-character encounter tracking with progress tracks
- Ranks 1–5 (Troublesome → Epic) with progress mechanics
- Escalating Harm (YRT): foe harm starts at 1 and increases on each Miss; capped at effective rank
- Escalating Defense (YRT): foe projects a mana shield that absorbs strikes; defense erodes on each Miss and blocks progress marks while active; cap = progress-per-hit for that rank
- Journey and Delve Site expedition types
- Progress tracks with waypoint/room mechanics
- Delve tables for site exploration
- Track settlements and the people who inhabit them
- Oracle-powered random generation for community names, locations (inland/coastal), and NPC names (Ironlander, Elf, Giants, Varou, Trolls variants)
- Free-form notes, region, trouble, and relationship fields per entry
- 3-column responsive grid layout
- Responsive layout down to 360px; tested on Surface Duo (540px breakpoint for icon-only tabs)
- Horizontal swipe-to-switch-tab on the home page (direction and distance thresholds filter out vertical scrolls and taps); opt out per-element with
data-no-swipe-tabs - On Adventure, a drag-to-resize split panel replaces the desktop side-by-side layout: GCB on top, session log below, both scroll independently, split persists to localStorage
- Picker dialogs (Foes, Moves, Oracles) size to
min(85dvh, 720px)so they don't collapse behind mobile browser chrome - Collapsible glass search pill on Expeditions and Communities to reclaim toolbar space on narrow screens
- Body scroll lock when modal pickers or the Adventure split panel are active
- Persistent session log with interactive links
- Resource changes, moves, oracles, progress, initiative, debilities, menace links
- State-modifying links with strikethrough after click
- Auto-appended "Momentum: Burn Available" log entry when burn is possible on action roll results
- Cascade rules auto-append log entries on resource floor events:
- Overflow: health/spirit drops below 0 → excess converts to momentum loss
- Floor: supply hits 0 → "Supply: Exhausted" with Unprepared debility link; momentum hits −6 → note appended
- Floor overflow: resource already at minimum → "Face a Setback", "Face Death", "Face Desolation", or "Out of Supply" entries with per-point clickable exchange links
- Export includes timestamps for each entry
- Per-character initiative badges (sword/shield icons) on GCB and character sheet
- Automatically clears when foe is deselected
Integrated into the home page as a dedicated Admin tab (screwdriver-wrench icon, only visible to admin-role users).
- Users tab — sortable user table with pagination, role management (promote/demote/suspend), user delete
- Logs tab — live PM2 server log viewer (API/web stdout & stderr), filter, expandable JSON rows
- Maintenance tab — enable/disable maintenance mode with countdown, message, session revocation
- Registration tab — lock/unlock new account creation with a custom message
- Redis-backed system maintenance state shared across instances
- Global countdown banner for all users (polls every 10s)
- Blocks non-admin logins during maintenance
- Revokes all refresh tokens to force logoff
- Admin bypass for login during maintenance
- Full audit logging of maintenance events
- Admin can disable new user registration without triggering full maintenance mode
- Locked state shows a custom message on the
/registerpage with a link to sign in - Backed by Redis — survives server restarts
| Command | Description |
|---|---|
npm run dev |
Start API dev server |
npm run dev:web |
Start web dev server |
npm run build |
Build both API and web |
npm run test |
Run API test suite (vitest) |
npm run migrate |
Run database migrations |
npm run check:web |
TypeScript check for web |
See docs/deployment.md for complete IONOS VPS deployment instructions including:
- One-time server provisioning
- Pushbutton CI/CD via GitHub Actions
- Manual deploy script with rollback
- Database backup strategy
- Horizontal scaling guide
- Maintenance mode workflow
Feature docs are in the docs/ directory:
| Doc | Description |
|---|---|
| admin.md | Admin panel — users, logs, maintenance, registration lock |
| architecture_decisions.md | Architecture and design decisions |
| character-sheet.md | Character sheet component |
| communities.md | Communities & NPCs — data model, oracle generation |
| DATA_FORMAT.md | Catalogue data format spec (moves, assets, oracles, foes) |
| deployment.md | IONOS VPS deployment guide |
| DICE_ROLLING.md | Dice rolling implementation |
| expansion-toggles.md | Delve / YRT expansion toggle system |
| expeditions.md | Expeditions system |
| foes.md | Foes and encounters |
| global-context-bar.md | GlobalContextBar tile layout |
| log.md | Session log with interactive links |
| mobile.md | Mobile layout, swipe gestures, and viewport behaviour |
| moves.md | Moves system and dice rolling |
| notes.md | Notes dialog |
| oracles.md | Oracle tables |
| ui-components.md | Shared UI design specs (cards, pills, tooltips, side labels) |
| YRT/DATA_FORMAT_YRT.md | YRT homebrew data format extensions |
- Ironsworn and Ironsworn: Delve by Shawn Tomkin — licensed under CC BY-NC-SA 4.0. Game data sourced from Datasworn by rsek.
- game-icons.net — game-themed SVG icons (CC BY 3.0)
- Font Awesome — UI icons (Free tier, CC BY 4.0)
- SSH key-only auth, UFW firewall, fail2ban
- HTTPS with HSTS, CSP, X-Frame-Options (Helmet + Nginx)
- Rate limiting at Nginx and API layers (Redis-backed)
- PostgreSQL Row-Level Security
- Argon2id password hashing (OWASP 2024)
- HaveIBeenPwned password checking
- hCaptcha on registration
- JWT RS256 with refresh token rotation and theft detection
- 64KB request body limit
