Shelf — project memory for Claude¶
Shelf is a small reading-list REST API with a tiny web page. Node 20+, ES modules, zero runtime dependencies.
Commands¶
npm test— runs the whole suite (node:test). Run it after every change.npm start— API on :3000; configuration comes from environment variables (see.env.example)npm run mcp— stdio MCP server exposing the store as toolsnode e2e/smoke.e2e.mjs— browser end-to-end test (needs Playwright; not part ofnpm test)
Layout¶
src/config.js— the ONLY place that readsprocess.env; validates and fails fastsrc/validate.js— all input validation; return{ ok, value | errors }, never throw. Shared with the browsersrc/store.js— the only code that touches data; no HTTP knowledge; delete is a soft deletesrc/auth.js— API keys ->{ owner, role }; roles arememberandadminsrc/security.js— escapeHtml, card rendering, CSP headers, RateLimitersrc/jobs.js— in-process job queue (retry with backoff, dead-letter list)src/ai.js— AI helpers; the model call is injected as a function so tests never hit the networksrc/mailer.js— outbound mail interface, inbound webhook signature + parsingsrc/app.js— routing + HTTP mapping only; no business rules hereweb/— static client;ui.jsis pure functions (unit-testable),app.jstouches the DOMtest/— one test file per area; API tests start the server on port 0project/— scope, requirements, MVP, tech-stack decisions, plan
Conventions¶
- Status codes: 201 create, 204 delete, 400 malformed JSON, 401 no/unknown key, 403 wrong role, 404 missing OR not yours, 422 validation, 429 rate limited, 501 AI not configured
- Never return 403 for another user's book: return 404 so ids do not leak
- Validation errors are arrays of short human-readable strings
- Every dynamic value that becomes HTML goes through
escapeHtml - Business rules live in
validate.jsorstore.js, never inapp.js - New behaviour needs a test first; do not change existing tests to make them pass
- AI output is untrusted: validate it and fall back to a safe default; never fail the user's request because the AI failed
Subagents¶
reviewer— read-only review of the current diff against these conventionssecurity-auditor— fresh-eyes security audit (read-only)e2e-writer— writes and runs browser tests; use it for any E2E work
Do not¶
- Add dependencies without asking
- Edit
data.json(runtime data, git-ignored) - Commit
.envor anything that looks like a real key