Blocking:
- Stock adjustments read-modified-wrote outside a transaction, so concurrent
changes silently overwrote each other. Verified: 50 concurrent -1 requests
moved a quantity of 100 to 99 rather than 50, while all 51 history rows were
written, leaving the ledger disagreeing with the stock. Both adjust and patch
now take SQLite's write lock up front.
- Session tokens joined payload and HMAC with "." and split on the last
occurrence. A raw digest can contain that byte, so ~12% of issued tokens
failed their own validator (measured 121/1000). The digest is fixed width;
slice by length instead.
- starlette 0.41.3 and python-multipart 0.0.20 carried 15 advisories between
them, including a FileResponse Range-header DoS reachable through the public
static assets. Pinned starlette explicitly; python-multipart was unused.
Also:
- PATCH quantity now writes history, and a floored adjustment logs the delta it
applied rather than the one requested, so the log sums to the stock.
- Renaming or deleting a category or location rebuilds the search index for
every part beneath it; full paths are indexed, so "Workshop" finds Bin A3.
- Blank names, negative quantities and explicit nulls on NOT NULL columns are
422s instead of silent writes or 500s; taxonomy routes 404 on missing ids,
409 on duplicates, and reject indirect parent cycles.
- Security headers, HSTS behind X-Forwarded-Proto, Secure cookie via the
forwarded scheme, content-hashed asset URLs so Cloudflare cannot serve stale
frontend code, and a global failed-login throttle.
- README documents a WAL-safe backup; cp of parts.db alone could lose commits.
Checks go from 68 to 134, including a suite that runs against a real server
because lost updates only appear when requests genuinely overlap.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
FastAPI + SQLite behind a single-page frontend, deployed as a container on
mainserver behind Caddy.
One flexible parts table plus key/value specs so components, filament,
fasteners and tooling share a schema. Categories and locations are nestable
trees whose filters and sidebar counts both roll up through descendants.
Category spec templates pre-fill the properties worth recording for each kind
of part, which is what makes manual entry tolerable. Every quantity change is
logged. Search is FTS5 with prefix matching across names, MPNs, spec values,
tags, category and location.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>