Architecture
Overview
FlowDice is a Ruby on Rails web application that ships as a PWA first, with Hotwire Native shells added in Phase 3. The dice engine is factored as a standalone Ruby module to enable reuse across the web UI, API, MCP Server, and Discord Bot.
Rails App
- Framework: Rails 8+ with Hotwire (Turbo Drive + Stimulus)
- Frontend: Mobile-first responsive HTML/CSS, Stimulus controllers for calculator interactivity
- Offline: Service worker caches all pages and assets for full offline PWA support
- Navigation: Standard Turbo Drive full-page navigation (not heavy Turbo Frames) — this is critical for Hotwire Native compatibility
- RNG: Cryptographically secure random number generation via
SecureRandom
Key Components
Dice Engine (standalone Ruby module)
The notation parser and evaluator. Takes a Notation Spec string, parses it into an AST, and evaluates it to produce results with individual die values. Factored as a standalone module/gem so it can be consumed by multiple interfaces.
FlowDice::Engine (core Ruby module)
├── Web UI (Rails controllers + Stimulus)
├── JSON API (for native apps)
├── MCP Server (tool definitions + handlers)
├── Discord Bot (via MCP client)
└── Future: CLI, etc.
Core responsibilities:
- Parse notation string into expression tree
- Evaluate expressions with secure random rolls
- Handle Keep Highest and Lowest, Crit Mechanics, Custom Face Values, Reroll Mechanic
- Resolve Flows conditionals and Named Parameters
- Generate Human-Readable Explanations from the AST
- Return structured results (total, individual dice, kept/dropped, crit applied)
Calculator UI
Stimulus controller managing the button-based input. Builds notation strings from button presses, validates input state (disabling invalid buttons), and displays live notation + explanation.
MCP Server
Exposes the dice engine as MCP tools for AI assistants, VTTs, bots, and other integrations. Thin wrapper over the same engine — see MCP Server for tool definitions.
Discord Bot
Lightweight Node.js interface using discord.js, connecting to the FlowDice instance via MCP Server. Provides slash commands (/roll), manages Discord interactions, and renders results as embeds with interactive parameter buttons.
Favorites System
Named, saved notation strings with optional Named Parameters. Single-tap to roll, long-press for parameter toggles. Stored locally for offline support; synced to cloud in Phase 3 with Characters.
Roll History
Chronological log of all rolls with notation, results, and individual die values. Tap to re-roll.
Data Model
| Model | Fields | Notes |
|---|---|---|
Roll | notation, result, individual_dice, rolled_at | Every roll executed |
Favorite | name, notation, last_result, position | User-saved rolls |
Character | name, system, stats, weapons, spells, class_features | Phase 3; synced to cloud |
Phase 1 stores everything client-side (localStorage/IndexedDB) for offline-first. Server-side persistence is a Phase 2 consideration if sync or accounts are added. Phase 3 requires server-side character storage for multi-device sync.
Interfaces
FlowDice engine has 7 interfaces:
- Web UI — Rails app + PWA
- PWA — offline-capable web app
- Hotwire Native iOS — Swift/Xcode shell (Phase 3)
- Hotwire Native Android — Kotlin/Android Studio shell (Phase 3)
- JSON API — for any client (native, web, third-party)
- MCP Server — for AI assistants, VTTs, integrations
- Discord Bot — slash commands via Discord Bot
- Future: Android Auto (Phase 3 stretch), CLI, etc.
All routes feed to the same FlowDice::Engine, so behavior is identical everywhere.
Platform Progression
- Phase 1: Rails app → browser (desktop + mobile) + PWA
- Phase 1 Stretch: MCP Server (basic
roll+parsetools) - Phase 2: Full MCP Server + Template Library + Discord Bot + JSON API
- Phase 3: Hotwire Native iOS shell + Android shell + Characters + cloud sync
- Stretch: Android Auto, CLI, etc.
Hotwire Native Readiness
Building the Rails app with these conventions ensures smooth native wrapping later:
- Mobile-first responsive CSS from day one
- URL-based navigation (not heavy Turbo Frames for primary flows)
turbo_native_app?helper available for conditional native UI- Clean URL structure maps to native navigation stacks
- Service worker enables offline support in both web and native contexts
See also: FlowDice, Notation Spec, Hotwire Native, MCP Server, Discord Bot