86 lines
2.9 KiB
Markdown
86 lines
2.9 KiB
Markdown
# Sustenance
|
|
|
|
A small shared grocery list built with Rust, Axum, Maud, htmx, WebSockets, and SQLite.
|
|
|
|
## Run locally
|
|
|
|
```sh
|
|
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.
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```sh
|
|
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`.
|
|
|
|
```sh
|
|
# 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.
|