A small app for personal or family use to keep track of product purchases: rate and review what you buy, where you bought it, and what you paid.
- Backend: Rust (REST API + CLI), SQLite
- Frontend: Svelte
- Track purchases — Record products you buy.
- Rate and review — Give products a rating and write a review.
- Where and how much — Store the place (store or location) where you bought each product and the price you paid.
backend/— Rust API and CLIfrontend/— Svelte appdocs/— Specification and API docs
- Rust (stable, 1.85+)
- Bun (latest)
- Node.js 24 LTS
The backend is configured via environment variables. In the backend
directory, copy the example file to .env and edit the values:
cd backend
cp .env.example .envEdit .env to set at least JWT_SECRET (required). Run the backend from
backend/ so it finds .env. In production, set the variables in the
environment instead of using a file.
cd backend
cargo build --releaseThe binary will be at backend/target/release/pocketratings.
cd frontend
bun install
bun run buildImportant: The backend server must be started before starting the frontend server, as the frontend depends on the backend API.
Start the backend server first:
cd backend
cargo build
cargo clippy --all-targets -- -W clippy::pedantic -W clippy::nursery -W clippy::cargo -D warnings
cargo test
# Start the server
cargo run -- server startThe backend API will be available at http://127.0.0.1:3099 (or the
address configured in your .env file).
Once the backend server is running, start the frontend dev server:
cd frontend
bun install
bun run devThe dev server will start at http://localhost:3000.
cd backend && cargo clippy --all-targets --release -- -W clippy::pedantic -W clippy::nursery -W clippy::cargo -D warnings
cd frontend && bun run lintRun tests for both backend and frontend:
cd backend && cargo test --release
cd frontend && bun run testFrom the repo root, run ./scripts/pre-push.sh to run backend (format,
clippy, test, coverage) and frontend (lint, test) checks. To install as
a git hook so it runs before every push:
ln -sf ../../scripts/pre-push.sh .git/hooks/pre-pushBackend coverage (run by the pre-push script) requires
cargo install cargo-llvm-cov.
You can run the full stack (Caddy reverse proxy, backend API, static
frontend) with Docker or Podman Compose. The proxy routes /api/v1/ to
the backend and everything else to the frontend; one entry point, no CORS.
Prerequisites: Docker with Compose, or Podman with Compose (e.g.
podman-compose).
-
Copy the root env example and set
JWT_SECRET:cp .env.example .env # Edit .env and set JWT_SECRET to a long random string. -
From the repo root, start the stack:
docker compose up -d # or: podman-compose -f compose.yaml up -d -
Open the app at http://localhost (or https://yourdomain.com if you configured the Caddyfile with a domain for Let's Encrypt).
For production HTTPS, edit the Caddyfile at the repo root: replace
http://localhost with your domain (e.g. https://pocketratings.example.com).
Caddy will obtain and renew a certificate automatically.
When the stack is running, the database lives inside the backend container. Run CLI commands in that container so they use the same database:
docker compose exec backend /app/pocketratings <command> [options]
# or: podman-compose -f compose.yaml exec -T backend /app/pocketratings <command> [options]Examples (registration is CLI-only in v1):
docker compose exec backend /app/pocketratings user register \
--name "Jane" --email jane@example.com --password secret
docker compose exec backend /app/pocketratings user list
docker compose exec backend /app/pocketratings user set-password \
--email jane@example.com --password newsecret
docker compose exec backend /app/pocketratings category listTo run the CLI against a local database instead (e.g. from the repo
with cargo run), use the backend's own .env in backend/ and run from
there; see Configuration and Development above.
The database is stored in a named volume pocketratings_db, mounted at
/data in the backend container. The database file is
/data/pocketratings.db.
Back up the database
From the repo root, with the stack running:
Recommended: hot backup without stopping the server
docker compose exec backend /app/pocketratings database backup
# or: podman-compose -f compose.yaml exec -T backend /app/pocketratings database backupThis writes a snapshot to /data/pocketratings.db.backup inside the
container. Copy it out (replace CONTAINER_ID with the backend container
ID or name):
docker cp CONTAINER_ID:/data/pocketratings.db.backup backup-$(date +%Y%m%d-%H%M%S).db
# or: podman cp CONTAINER_ID:/data/pocketratings.db.backup backup-$(date +%Y%m%d-%H%M%S).dbAlternative: raw copy (simpler but not a guaranteed consistent snapshot if the server is writing):
docker compose exec backend cat /data/pocketratings.db \
> backup-$(date +%Y%m%d-%H%M%S).db
# or: podman-compose -f compose.yaml exec -T backend cat /data/pocketratings.db \
# > backup-$(date +%Y%m%d-%H%M%S).dbRestore the database
-
Stop the backend:
docker compose stop backend # or: podman-compose -f compose.yaml stop backend -
Replace the database in the volume (use the backup file path you have):
docker run --rm \ -v pocketratings_pocketratings_db:/data -v "$(pwd)":/backup \ alpine sh -c "cp /backup/backup-YYYYMMDD-HHMMSS.db /data/pocketratings.db \ && chown 1000:1000 /data/pocketratings.db"
For Podman use podman run. Replace backup-YYYYMMDD-HHMMSS.db with
your backup filename. The volume name is pocketratings_pocketratings_db.
- Start the backend again:
docker compose start backend # or: podman-compose -f compose.yaml start backend
GPL-3.0 — copyleft; derivatives and forks must remain open source. See LICENSE.