Limit request bodies to 1 MiB (413 JSON), wire aria-describedby on the login form, add Retry and cancellation to the book form load, disable Add entry while a note POST is in flight, and poll pg_isready in README. Claude-Session: https://claude.ai/code/session_01M9MLit5Ko3X4s7rzC5Kv7X
59 lines
2.8 KiB
Markdown
59 lines
2.8 KiB
Markdown
# My Library: Personal Book Collection Tracker
|
|
|
|
Flask + React + PostgreSQL. Users catalog their books, track reading progress, keep a reading journal per
|
|
book, and search/filter their library. Each user sees only their own data.
|
|
|
|
## Run (CoderPad)
|
|
|
|
The pad starts Flask (`backend/app.py`, port 5000) and Vite automatically. The schema is created on startup.
|
|
Optionally set `PASSWORD_PEPPER` (≥ 32 chars). Without it, a development pepper is generated into
|
|
`backend/.pepper` and a warning is logged.
|
|
|
|
## Run (local)
|
|
|
|
```bash
|
|
mise trust && mise install # Python 3.14, Node 24
|
|
docker compose up -d db # postgres:16 on 127.0.0.1:5432
|
|
until docker compose exec -T db pg_isready -U postgres; do sleep 1; done
|
|
mise exec -- python -m venv .venv && .venv/bin/pip install -r backend/requirements.txt
|
|
mise exec -- npm install
|
|
.venv/bin/python backend/app.py # API on :5000
|
|
mise exec -- npm run dev # UI; /api is proxied to Flask
|
|
```
|
|
|
|
## Test
|
|
|
|
```bash
|
|
.venv/bin/python -W error -m unittest discover -s backend/tests -t backend -v # real Postgres (books_test); run from repo root
|
|
mise exec -- npm test && mise exec -- npm run typecheck
|
|
```
|
|
|
|
## Design
|
|
|
|
- **Feature slices.** One Flask Blueprint per feature: `auth.py`, `books.py` and `notes.py` each hold their
|
|
routes, validation and SQL. `db.py` holds the pool and transactions; `validation.py` holds the shared input rules.
|
|
- **Isolation in SQL.** Every query filters on the session's user (`AND user_id = %s`, or joins to `books`
|
|
for notes). Another user's book and a missing book return the same 404.
|
|
- **Passwords.** Peppered PBKDF2-HMAC-SHA256 (FIPS-approved, stdlib only). See [ADR-0001](docs/adr/0001-password-hashing-pbkdf2.md).
|
|
- **Sessions.** Opaque tokens hashed at rest; 30-minute idle and 12-hour absolute expiry; real logout; CSRF
|
|
handled by SameSite plus a JSON-only rule. See [ADR-0002](docs/adr/0002-server-side-sessions.md).
|
|
- **Data rules in two places.** The API returns specific 400s, and Postgres CHECK and FK constraints
|
|
backstop them.
|
|
- **Frontend.** React Router (search and filter state lives in the URL), a small auth context, Tailwind.
|
|
No state library.
|
|
|
|
Full spec: [docs/superpowers/specs/2026-10-02-book-tracker-design.md](docs/superpowers/specs/2026-10-02-book-tracker-design.md)
|
|
|
|
## Known trade-offs
|
|
|
|
| Not included | Add when |
|
|
|---|---|
|
|
| Pagination | libraries exceed a few hundred books |
|
|
| Trigram/full-text index | ILIKE search slows (thousands of books) |
|
|
| Login rate limiting | before production |
|
|
| Migrations tool | schema changes after first deploy |
|
|
| Pepper rotation | before production key management |
|
|
|
|
A request that fails with 4xx rolls back its transaction, including the session idle-window slide, so failed
|
|
requests don't extend the 30-minute idle timeout.
|