Sustenance
A small shared grocery list built with Rust, Axum, Maud, htmx, WebSockets, and SQLite.
Run locally
cargo run
Open http://127.0.0.1:3000. The application creates sustenance.db in the working directory on first start.
Configuration
| Variable | Default | Purpose |
|---|---|---|
DATABASE_PATH |
sustenance.db |
SQLite database path |
BIND_ADDRESS |
127.0.0.1:3000 |
Listen address |
PUBLIC_BASE_URL |
derived from BIND_ADDRESS |
Base URL used in invitation links |
COOKIE_SECURE |
false |
Add the Secure attribute to session cookies |
REGISTRATION_MODE |
invite_only |
Use open for local development; otherwise registration requires a valid list invitation after the first account |
SEED_CONFIG |
seed.json |
Optional JSON file with a default user to create when the database is first initialized |
RUST_LOG |
sustenance=debug,tower_http=info |
Log filter |
Seeding a default user
If a JSON config file exists at the path given by SEED_CONFIG (default seed.json),
Sustenance creates the configured user on startup when the database has no users yet.
The file is optional — if it is missing or invalid, seeding is silently skipped.
{
"user": {
"email": "you@example.com",
"display_name": "You",
"password": "a-strong-password"
}
}
Current features
- Email/password accounts with Argon2 password hashes
- Cookie-backed sessions and CSRF tokens for list mutations
- Shared lists with one-time, seven-day invitation links
- Invite-only registration by default after the first account
- Add, edit, check, and delete grocery items
- Global categories with common defaults seeded at startup and custom category creation
- Items grouped by category and assigned from the add/edit forms
- Meals with ingredients, markdown descriptions, and one-click "add meal to list"
- Server-authoritative last-write-wins updates
- Per-list WebSocket updates with server-rendered htmx fragments
- In-memory presence for members currently viewing a list
- Responsive layout for phone, tablet, and desktop
The htmx scripts are currently loaded from unpkg. They can be vendored into static/ before production deployment.
Verification
cargo fmt --all -- --check
cargo check
cargo test
End-to-end tests (Playwright)
The e2e tests live in e2e/ and use Playwright with a real browser. Each test
starts its own server against a fresh, throwaway database on a unique port, so
tests are fully isolated from each other and from your real sustenance.db.
# one-time setup
cd e2e
npm install
npx playwright install chromium
# run the tests (builds the server automatically via globalSetup)
cd e2e
npx playwright test
The Playwright globalSetup runs cargo build before the suite, and each test
launches its own server against a fresh database, so no manual build or server
start is required.