An offline-first, hierarchical list-keeping PWA. Frontend is Rust + Yew compiled to WASM via Trunk; backend is Actix Web + Postgres (via sqlx) serving the built assets and a sync API.
shared/— domain types (Item,Membership, sync DTOs) used by bothfrontendandbackend, so the wire format can't drift.frontend/— Yew app (trunk build). All reads/writes go through a locallocalStorage-backed store (src/store.rs) — the app works fully offline. A background loop (src/sync.rs) pushes local changes and pulls remote ones every 30s (and on reconnect), using last-write-wins onupdated_at.backend/— Actix Web server exposingPOST /api/sync(push+pull in one round trip) and/api/health, and servingfrontend/dist. Postgres schema/migrations live inbackend/migrations/.
Everything is one items table plus one memberships join table:
- an item can be a plain task, a note (
is_note, not completable), or a list — any item can have children - a membership row (
item_id,parent_id) is how an item appears inside another item's list;parent_id = NULLmeans "top-level list" - an item can have multiple membership rows (different
parent_id) to appear in more than one list at once (tags) position(per membership) gives each list its own custom order for that itemvisible(per membership) lets an item be hidden from one list while staying visible in another
updated_at/deleted_at on both tables double as the sync log — no separate op-log needed.
Recurring tasks, time-gated visibility, and a calendar view are intentionally not implemented yet (see tasks.md); the schema has room to add them later as an additive migration.
rustup target add wasm32-unknown-unknown
cargo install trunk sqlx-cli --no-default-features --features postgres,rustlsA local Postgres server, with a role/database for the app:
psql -d postgres -c "CREATE ROLE lister WITH LOGIN PASSWORD 'change-me';"
psql -d postgres -c "CREATE DATABASE lister OWNER lister;"Copy backend/.env.example to backend/.env (or export DATABASE_URL yourself) — defaults to postgres://lister:change-me@localhost/lister.
Run the frontend with hot reload:
cd frontend
trunk serveMigrations run automatically when the backend starts (sqlx::migrate!()), or run them manually:
cd backend
sqlx migrate run./run.shThis builds the frontend release bundle and starts the backend on port 8400. Then open http://127.0.0.1:8400. The app is installable as a PWA; the static shell works offline via the service worker, and list data works offline via the local store + background sync described above.
GET /api/lists?path=Home/Groceries returns the items of the list at that path (list names from a
top-level list down, case-insensitive) with Authorization: Bearer <token>. Create a token under
Admin → API tokens (shown once, with a Copy button; revoke it there too), or on the server with
cd backend && cargo run -- mint-token you@example.com "home-monitor". Tokens only open this read
endpoint, never sync.