- JavaScript 85%
- CSS 10.4%
- Python 3.8%
- HTML 0.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
`./deploy.sh` (no arguments) bumps the minor version and ships the static files to the Mac Mini, where nginx serves them at https://rutilo.nl/scanbox/static/. See ~/dev/ops/deploy-runbook.md §Frontends for the mechanism. The CLAUDE.md section records the two things this project must keep satisfying now that it is served from a subpath rather than the domain root: asset paths stay relative, and the API base needs the /scanbox prefix. Both httpService.js and sw.js still hardcode a bare /api, which is noted there rather than changed in this ops-focused commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
| .claude | ||
| src | ||
| test | ||
| tools | ||
| vendor/pdfjs | ||
| .gitignore | ||
| API-CONTRACT.md | ||
| apple-touch-icon-source.svg | ||
| apple-touch-icon.png | ||
| CLAUDE.md | ||
| CONFORMANCE-HISTORY.md | ||
| CONFORMANCE.md | ||
| deploy.sh | ||
| favicon.svg | ||
| icon-192.png | ||
| icon-512.png | ||
| index.html | ||
| manifest.webmanifest | ||
| package.json | ||
| README.md | ||
| serve.py | ||
| SERVER-CONFORMANCE.md | ||
| SPEC.md | ||
| sw.js | ||
| TASKS.md | ||
ScanBox frontend
Client for ScanBox, an application giving access to a decades-long archive of scanned and received documents: finding them by date and label, browsing them visually, and reading them.
What it covers and why is in SPEC.md. This file is only about working with this repository.
Status
Early, and running. Searching, the label area, the results grid, the unparseable-documents view and the viewer work against the mock. The viewer shows a document's own content where the mock has real bytes behind a document — a multi-page document is stepped through page by page, using the same slide gesture that steps between documents — and falls back to the generated thumbnail for every other document. There is no backend — finding out what its endpoints should be is the point of building the frontend first.
Not built yet: locked searches (deferred) and overviews.
Running
python3 serve.py 8430
Then open http://localhost:8430. serve.py sends no-store, so a refresh always
picks up what is on disk — plain http.server caches ES modules hard enough to
survive a reload. Port 8430 rather than 8420 because the sister project CasaFluxFE
uses 8420.
npm test
Runs the logic tests under node --test. No browser and no network involved.
npm run snapshot
Regenerates the mock's data from the archive. Reads filenames only, and never writes to the archive.
Documents
| File | Job |
|---|---|
| SPEC.md | What the client does, and why each choice was made |
| CONFORMANCE.md | Client rules, numbered CF-, derived from SPEC.md |
| CONFORMANCE-HISTORY.md | Older revision notes for the above |
| API-CONTRACT.md | What goes over the wire — shared with the backend |
| SERVER-CONFORMANCE.md | What the backend must guarantee, numbered CFS- |
| CLAUDE.md | How to work on this repository |
SPEC.md and the conformance documents are implementation-agnostic on purpose: they should hold for a rewrite in another framework, or a native app. Anything that is true only of this web client belongs here.
Stack
Vanilla JavaScript, no build step, no dependencies at all so far. Libraries are
added only where they earn their place — PDF rendering being the one where that is
already clear. JSDoc annotations with tsc --checkJs --noEmit where type checking
is useful.
Logic with no DOM access — query parsing and evaluation, filename parsing, label
ranking and typo tolerance — lives in src/lib and is tested under node --test.
That is where the correctness risk is and none of it needs a browser.
| Directory | Holds |
|---|---|
src/lib |
Logic with no DOM access, and the data-service choice |
src/mock |
The mock service, its filename snapshot, and generated thumbnails |
src/ui |
The pill, search field, label area, results grid and viewer |
test |
node --test suites, named after the requirements they exercise |
tools |
makeSnapshot.js, which reads the archive |
The label pill is a custom element (<scanbox-pill>). A pill is exactly what
custom elements are good at, and the alternative was a framework that would have
had to earn its place against one small file.
The archive
The documents live in the Scans directory named in the global ~/.claude/CLAUDE.md,
and that directory has a CLAUDE.md of its own describing the naming convention,
the filing workflow and the folder map. It is the authority on the data; read it
before reasoning about what a document or a label is.
It is read-only from this repository. Nothing here writes to it. Mutation happens in a session aimed at the archive itself, or eventually through the ScanBox backend.
Reading it to ground a decision is wanted, though — the measurements in SPEC.md §What the data actually looks like came from there and contradicted the first draft of the design more than once. When the question is "how many labels are there really", count rather than guess:
find ~/Jottacloud/Scans -type f -not -path '*/bak/*' -exec basename {} \; | grep -E '^[0-9]{8}_' | sed -E 's/^[0-9]{8}_//; s/\.[^.]+$//' | tr '_' '\n' | sort | uniq -c | sort -rn
Backend
There is no backend yet. The client runs against a mock data service, and the mock is permanent — it stays after the backend arrives, for testing and for interface work that should not depend on a live archive. It also carries the scenarios that make the conformance rules checkable.
There is one data service with two implementations, mock and real HTTP, and nothing above that service knows which it is talking to. A component reaching for the mock directly would have to be changed twice: once to use the real service, and once more the next time somebody wanted to debug without one.
The backend will be Java, built on LabelDB — which is where the query syntax in API-CONTRACT.md §3 comes from, and where the per-label result counts that make the label sidebar work come from essentially for free.