Skip to main content

Prerequisites

  • Ruby 3.4+ (see .ruby-version)
  • SQLite3 development libraries
  • Node.js (for Tailwind CSS build)

Installation

Clone the repository and install dependencies:
Set up the database:
This creates the SQLite database, runs all migrations, and seeds initial data.

Running the App

This starts two processes via 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:
This drops the database, re-runs all migrations, and re-loads all seed data. After resetting, you can log in as: 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:
Once linked, 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 at 100.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.pub must be in ~/.ssh/authorized_keys on the NAS (user hakon)

First-time setup

This installs kamal-proxy on the NAS, builds the Docker image locally, pushes it to the local registry, and starts the app container. After setup, prepare the database:

Deploying

Kamal reads secrets from Doppler (via .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 (overrides config/deploy.yml)
  • Secrets: .kamal/secrets.staging (fetches from Doppler stg config)
  • 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 in deploy.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.

Logging in on staging

Staging uses the Mailtrap API in sandbox mode — emails are not delivered to real recipients. Instead, they appear in the Mailtrap sandbox inbox. Check the sandbox inbox to find magic link emails. If you need to log in without checking Mailtrap, generate a magic link URL directly from the Rails console:
Then in the console:
Open the resulting URL in your browser to log in. The token expires in 10 minutes.
Last modified on October 21, 2026