common/ had become the backend's library: 30 of its 41 modules were
imported by nothing in the frontend, so the name no longer said what
belonged there. It now holds only what the frontend or the build imports
too; backend-only code moved to server/, flat except for datasets/ (the
dataset engine and its readers). The *-db/ dataset directories stay in
common/: self-hosting docs and Docker volumes mount those paths.
frontend/utils/ keeps its app-wide modules at the root and gains ip/
(IP / ASN shaping and validation), report/ (the report pipeline) and
features/ (the pure layer of a single feature). Paths only — no logic
changes. The Dockerfile copies server/, and the AGENTS.md files say where
a new module goes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cut changelog-style narration from comments ("previously…", "replaced in v7",
"…fixes that", the shields.io backstory) so they explain the current code, not
how it got here. Codify this in AGENTS.md's Comments section.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shields.io's stars badge kept failing on GitHub token-pool exhaustion
("Unable to select the next GitHub token from pool"). Serve the count
from our own backend instead and render the badge ourselves.
- api/github-stars.js: fetch stargazers_count unauthenticated (no token),
edge-cached for a day in backend-server.js. Behind Cloudflare the origin
hits GitHub at most once per cache window, well under the 60 req/hour
unauthenticated limit; error responses stay no-store so failures aren't
cached.
- Nav.vue: replace the shields.io <img> with our own GitHub badge on
desktop and add the count to the mobile drawer's "Star on GitHub" row,
both fed by /api/github-stars (fetched on mount). Count is hidden until
it lands / on error, so the link never depends on the fetch.
- format-star-count.js: pure compact formatter (1234 -> 1.2k) with tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>