Prerequisites
- Ruby 3.4+ (see
.ruby-version) - SQLite3 development libraries
- Node.js (for Tailwind CSS build)
Installation
Clone the repository and install dependencies:Running the App
Procfile.dev:
- Puma web server on
http://localhost:3000 - Tailwind CSS watcher for live stylesheet compilation
Reset and Re-seed
To reset the database to a clean state with fresh seed data:
The seed database contains one organization (Sameiet Eiketoppen) with 10 meetings across all statuses, complete with agenda items, polls, and votes.
Key Commands
Email in Development
The app uses letter_opener in development. Magic link emails open automatically in your browser instead of being sent.Environment Variables
Secrets are managed via Doppler. After cloning the repo, link your local environment:bin/dev injects secrets automatically — no .env file needed.
Turnstile and Litestream are both fully ENV-gated: Turnstile needs both keys
before the widget renders or a token is verified, and Litestream needs
LITESTREAM_REPLICA_BUCKET. Local development and test runs are unaffected by
leaving them unset. See
Backup and Recovery for the Litestream
restore runbook.
For deployment configuration, see config/deploy.yml (production) and config/deploy.staging.yml (NAS staging).
Staging Deployment (NAS)
The staging environment runs on a UGreen NAS at100.65.168.27 via Tailscale. It uses Kamal 2 with Docker.
Prerequisites
- Tailscale — connected to the same tailnet as the NAS
- Doppler CLI — authenticated (
doppler login) - SSH key — your
~/.ssh/id_ed25519.pubmust be in~/.ssh/authorized_keyson the NAS (userhakon)
First-time setup
Deploying
.kamal/secrets.staging), builds the image, and deploys it. The app is accessible at http://100.65.168.27:8080/.
Useful commands
Architecture
- Rails env:
staging(dedicated environment — production-like with debug logging and Mailtrap email) - Config:
config/deploy.staging.yml(overridesconfig/deploy.yml) - Secrets:
.kamal/secrets.staging(fetches from Dopplerstgconfig) - Proxy: kamal-proxy on port 8080 (HTTP) and 8443 (HTTPS) — avoids conflict with NAS nginx on 80/443
- Storage: SQLite databases persist in
/volume1/docker/votering/on the NAS (bind mount to/rails/storage) - SSH user:
hakon(configured indeploy.staging.yml)
Staging uses
RAILS_ENV=staging, so db:seed works. After first-time setup, run kamal app exec --destination staging "bin/rails db:seed" to populate test data.