Production-ready Rio web application template featuring session-based authentication, optional TOTP multi-factor security, FastAPI endpoints, and a reusable component library.
- Auth & security: login, password reset, role-based guards, MFA toggles, recovery codes, admin-only operations.
- API layer: FastAPI routers for profile data, shared validation in
app/app/validation.py, and SQLite persistence helpers. Protected external HTTP clients are not supported until a credential model is designed for a concrete consumer. - UI experience: Rio pages for public marketing routes and protected app area, shared layout elements, and Plotly chart support.
- Built-in primary currency system with configurable naming, precision, admin tooling, and ledger history.
- Developer ergonomics: Example scripts, bundled Rio documentation, and deployment playbooks for quick onboarding.
There are two ways to use this boilerplate:
git clone git@github.com:azidancorp/RioBoilerplate.git my-project
cd my-project
rm -rf .git && git init # Start fresh git historyIf you already have a git project and want to pull in this boilerplate while keeping the ability to get future updates:
# From your existing project directory
git remote add boilerplate git@github.com:azidancorp/RioBoilerplate.git
git fetch boilerplate
git merge boilerplate/main --allow-unrelated-histories -m "Merge RioBoilerplate template"This merges the boilerplate into your project. Later, to pull updates:
git fetch boilerplate
git merge boilerplate/mainFor detailed merge instructions and conflict resolution, see UPSTREAM_MERGE_GUIDE.md.
- Set up the boilerplate using Option A or B above.
- Create and activate a virtual environment:
python -m venv venvthensource venv/bin/activate(orvenv\Scripts\activateon Windows). - Install the hashed development lock:
python -m pip install --require-hashes -r requirements-dev.txt. - Copy
.env.exampleto.envand set any provider/session secrets your deployment uses. - From the repository root, initialize the first verified root account:
./bootstrap.sh. - Start the development server:
./dev.sh(or./dev.sh 8888to pick a port). - The app stores its local SQLite database at
app/app/data/app.db. This file is ignored by git and should remain a local runtime artifact.
Access the dev server at http://localhost:8181. Use ./dev.sh 8181 --release to mirror production settings. Replace 8181 with the port you actually chose when checking a different local run.
The values tracked in app/app/config.py describe production — a canonical HTTPS APP_URL, Secure/__Host- cookies, real email delivery, and enforced email verification. That way a missing or unread configuration fails closed with a broken localhost login instead of failing open with insecure cookies on a public site.
./dev.sh creates app/app/config_local.py (git-ignored) from app/app/config_local.example.py on first run, which overrides those values for localhost. Edit that file freely; dev.sh never rewrites it. If you start the server without it — plain cd app && rio run on a fresh clone — login appears to succeed but a red banner reports that the sign-in state could not be saved, because cookie writes are pinned to the production origin.
Overrides are ignored under pytest, so tests and CI always run against the tracked production configuration.
Public password signup and OAuth registration cannot initialize an empty database. With no arguments, bootstrap_root prompts for email and password. You can also pass values directly, for example python -m app.scripts.bootstrap_root --email owner@example.com --password '<strong-password>'. --username owner is optional; if you provide --username without --email, that username becomes the root login identifier. The command creates one verified root user only when the database is empty.
Warning: not production-ready on Railway yet. As shipped,
railway.tomldeploys with no volume attached, and Railway's container filesystem is ephemeral — the SQLite database is erased on every deploy and restart. Do not put real users on a Railway deployment until the runtime-data relocation described below is complete and a volume is mounted. The supported production path today is the VPS guide inDEPLOYMENT_INSTRUCTIONS.md; the outstanding Railway work and the root-bootstrap procedure are tracked indocs/railway-readiness.md.
railway.toml runs strict prestart checks before starting the public server. On a fresh database, the deployment exits with a bootstrap error rather than exposing an unclaimed root slot. It also refuses to start until secure cookies, a canonical HTTPS APP_URL, and an external resend or verified-STARTTLS smtp email method are configured. These non-secret values are code-configured, so set, test, and commit them in app/app/config.py before deploying; provider secrets remain in the environment. These fail-closed results are expected.
Do not expose a Railway domain until the initial root has been created against the same persistent database the service will use. railway run and railway shell execute locally with Railway variables and do not modify the deployed SQLite volume.
The current app/app/data/ directory mixes mutable runtime state with tracked sample data, so it does not yet have a safe Railway volume mount target. Complete the runtime-data relocation tracked in docs/railway-readiness.md before treating this SQLite configuration as Railway-ready; mounting a volume over the whole directory would hide tracked application files.
./dev.sh– hot-reloading dev server with the local configuration override in place../dev.sh 8181 --release– release-mode smoke test.curl -fsS http://127.0.0.1:8181/api/health– machine-readable health check for the running app and local SQLite schema.
Runtime dependencies are declared in requirements.in and compiled with hashes
into requirements.txt. Development and supply-chain tools use the corresponding
requirements-dev.in and requirements-dev.txt files. After changing an input,
regenerate both locks with the pinned pip-compile from the development lock;
never hand-edit the generated files.
.envis for secrets only, such asSESSION_SECRET_KEYor provider credentials.- Non-secret behavior stays code-configured in
app/app/config.py, whose tracked values describe production. Edit that file directly for app-specific defaults such as email validation, username login, password policy, and currency naming/precision. - Machine-local development values belong in the git-ignored
app/app/config_local.py, never in a commit. See “Local configuration” above. EMAIL_METHOD="outbox"is for local development and is set by the local override file. Production must selectresendor securesmtp; delivery failures never fall back to local files.- Email validation and username-login behavior are documented in
docs/configuration/email-validation.md. - Root initialization is intentionally not configurable: public registration never assigns a privileged role.
- The runtime SQLite database file
app/app/data/app.dbis created locally on first run and is ignored by git. - Before going to production, replace the placeholder branding in
app/app/assets/(favicon.ico,logo.png,og_image.png) with your own. The source script atapp/assets_src/build_brand_assets.pyshows how they were generated and can be adapted; run it from the outerapp/directory withpython assets_src/build_brand_assets.py.
- SQLite schema stores a single minor-unit balance per user plus an audited
user_currency_ledger. - Admin UI (
/app/admin) now surfaces balances, allows grants/deductions, and shows success/error feedback. - FastAPI endpoints (
/api/currency/*) expose balance, ledger, and privileged adjustment APIs. - CLI helper
python app/app/scripts/currency_admin.pysupportslist,ledger,adjust, andsetoperations from the terminal.
- Protected profile operations and
/api/currency/balance,/api/currency/ledger,/api/currency/adjust, and/api/currency/setrequireAuthorization: Bearer <session token>./api/health,/api/test,/api/contact, and/api/currency/configare public. - The bearer requirement is declared in OpenAPI as
SessionBearer. Interactive Swagger UI lives at/docs; reference documentation lives at/redoc. The schema describes how to send an existing credential but does not provide or issue one. - The stock Rio UI does not depend on protected REST operations over HTTP.
app/app/pages/app_page/currency_playground.pyinvokes currency route handlers directly as a manual QA exception, not as the general UI/service sharing pattern. - There is intentionally no supported external token issuance or browser-cookie extraction flow. Production sessions are created through the web login/OAuth paths; tests create sessions directly with
Persistence.create_session()only as setup. - Before adding a browser, mobile, CLI, or integration client, read
docs/api-client-authentication.mdand design a credential lifecycle for that concrete consumer.
RioBoilerplate/
├── app/
│ ├── rio.toml # Rio app configuration
│ ├── JSPages/ # Prototype HTML/JS demos
│ └── app/
│ ├── __init__.py # App bootstrap + FastAPI bridge
│ ├── api/ # FastAPI routers (profiles, examples)
│ ├── assets/ # Branding assets (favicon, logo, og_image) — replace before production
│ ├── components/ # Reusable Rio UI widgets
│ ├── data/ # Runtime SQLite DB (local/ignored) and sample data
│ ├── pages/ # Public pages
│ │ └── app_page/ # Protected app pages
│ ├── scripts/ # Utilities and MFA helper scripts
│ ├── permissions.py # Role checks and guard helpers
│ ├── persistence.py # Database access layer
│ └── validation.py # Input validation & Pydantic models
├── RioDocumentation/ # Bundled Rio reference material
├── DEPLOYMENT_INSTRUCTIONS.md # Production rollout guide
├── requirements.in # Direct runtime dependencies
├── requirements.txt # Hashed runtime lock
├── requirements-dev.in # Direct development/tooling dependencies
├── requirements-dev.txt # Hashed development lock
└── README.md
Focus release verification on:
- Registration, login, and role-based routing.
- Enabling/disabling MFA and using recovery codes.
- Profile update via the UI and profile CRUD via
/api/profiles. - Error handling across contact flows and API responses.
- Currency adjustments: verify admin operations, ledger history, and
/api/currency/*behaviour (positive & negative paths). - Release health check:
curl -fsS http://127.0.0.1:8181/api/healthagainst the port used for that run.
AGENTS.md– contributor workflow and coding standards.CLAUDE.md– extended architecture and assistant notes.DEPLOYMENT_INSTRUCTIONS.md– step-by-step deployment guidance.RioDocumentation/– offline Rio framework reference.
Distributed under the terms of the included LICENSE.