Both follow the diigo-cache pattern (webapp holds the credential, read-only and minted narrow at the source; the cache serves a public page). Zotero's versioned sync answers diigo's stale-head problem; Mastodon's doesn't announce edits/deletes, so its tree carries that as a design question. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
5.2 KiB
zotero-cache goal tree
The same conventions as the diigo goal tree: each
- [ ] is a goal, its indented children must pass first, working notes
sit under each goal. This tree is goal 7 of that one, carried out.
-
The awesome-ocap bibliography is generated from Zotero (bib sync #195): madmode (and a GitHub action, later) read a cache of my Zotero library; the Zotero API key stays inside webapp, so neither reader holds a credential
-
0. Decide the shape (user's call before code): - [ ] 0-i. New worker
zotero-cache/besidediigo-cache/, or generalize diigo-cache? Recommendation: a new worker, and extract shared pieces (fill job, webkey page, page cache) only once both work — two examples before an abstraction. - [ ] 0-ii. Does it need a credential at all? The library is public on zotero.org; the public API (/users/<userID>/items, no key) may be enough for the bibliography. A key adds unpublished items, notes, and attachment metadata. If public is enough, webapp still earns its place as the rate-limited client, minted with no secret header. - [ ] 0-iii. Which collections make up awesome-ocap? (A Zotero collection per README section is the natural mapping.) -
1. Credential discipline: a read-only key minted at zotero.org → Settings → Security → API keys ("allow library access" only; no write, no notes unless 0-ii says so) — attenuation at the source. Send it as
Authorization: Bearer, notZotero-API-Key: webapp's mint form blanksauthorizationas a secret header and would echo an unknown one. Key → webapp DO storage only; ids → password manager. -
2. The cache (
zotero-cache/, the 1c pattern from diigo): - [ ] 2-i. Mint and wire:/_connect→/_mint→/_wire, the base URLhttps://api.zotero.org/users/<userID>/(GET /keys/currentwith the key returns the userID). - [ ] 2-ii. Storage: items keyed by Zoterokey, each with itsversion; one library version per cache. Durable state from day one: aSCHEMA_V1step, so later shapes migrate. - [ ] 2-iii. Fill:GET items?format=json&include=data,csljsonpaged bystart/limit(100 max) toTotal-Results; honorBackoffandRetry-After(webapp'smsPerCallis the floor, not the whole story). - [ ] 2-iv. Tests:pnpm lint && pnpm test, the real worker against a fake Zotero (fake-webapp style), including aBackoffresponse. - [ ] 2-v. Complete: a filled cache matches a Zotero export (File → Export Library → CSL JSON), the analogue of diigo'sscripts/compare-export.ts. -
3. Freshness is cheap here (diigo's 1f, solved by the API): Zotero versions every write. Refresh =
items?since=<library version>(only what changed,Last-Modified-Versionheader gives the new version) plusdeleted?since=<version>for removals. A test: an item edited and one deleted in the fake both show after a refresh. A cron alarm in the cache DO can drive it. -
4. Read surfaces: - [ ] 4-i. Public page
/public/<name>with?collection=, as HTML and JSON; JSON shape pinned by a test (the contract with readers). - [ ] 4-ii. CSL JSON and BibTeX out, from cached data (Zotero's ownformat=bibtexis a fetch; the cache should serve what it has). -
5. awesome-ocap README generated: a script (or madmode page) renders the collections to the README's markdown; diff against the hand-maintained README, the way 1c-vi diffed the diigo export. Prerequisite from #195: the current README's entries imported into Zotero (BibTeX / CSL JSON import).
-
6. Deployed: after diigo's goal 5 (webapp already deployed); rate-limit
/public/*; mint against prod; fill. -
7. Stretch (#195): a GitHub action regenerates the README from the public cache — public data, so no secret in the action.
-
How to run
TBD with goal 2; it should mirror the diigo how-to-run.
Working rules
capsite AGENTS.md: dev servers are the user's job; durable state, loud about breaking changes; secrets discipline; generated config types.
Pointers
- bib sync #195 — the goal, and the import half (README → Zotero)
- Zotero Web API v3 basics
and syncing —
versions,
since=, deletions,Backoff - awesome-ocap — the README to generate
- webapp/README.md — the mint form and its secret header list