···25252626also added loading indicator for "related to" results in frontend.
27272828+### recent work (2026-01-06)
2929+3030+- merged PR1: multi-platform schema (platform + source_collection columns)
3131+- added `loading.js` - portable loading state handler for dashboards
3232+ - skeleton shimmer while loading
3333+ - "waking up" toast after 2s threshold (fly.io cold start handling)
3434+ - designed to be copied to other projects
3535+- fixed pluralization ("1 result" vs "2 results")
3636+2837## what we know
29383039### standard.site lexicons
···195204- [ ] should we dedupe platform-specific vs standard records?
196205- [ ] embeddings: regenerate for all, or use same model?
197206207207+## implementation plan (PRs)
208208+209209+breaking work into reviewable chunks:
210210+211211+### PR1: database schema for multi-platform ✅ MERGED
212212+- add `platform TEXT` column to documents (default 'leaflet')
213213+- add `source_collection TEXT` column (default 'pub.leaflet.document')
214214+- backfill existing ~3500 records
215215+- no behavior change, just schema prep
216216+- https://github.com/zzstoatzz/leaflet-search/pull/1
217217+218218+### PR2: generalized content extraction
219219+- new `extractor.zig` module with platform-agnostic interface
220220+- `textContent` extraction for standard.site records
221221+- keep existing block parser for `pub.leaflet.*`
222222+- platform detection from `content.$type`
223223+224224+### PR3: TAP subscriber for site.standard.document
225225+- subscribe to `site.standard.document` + `site.standard.publication`
226226+- route to appropriate extractor
227227+- starts ingesting pckt.blog content
228228+229229+### PR4: API platform filter
230230+- add `?platform=` query param to `/search`
231231+- include `platform` field in results
232232+- frontend: show platform badge, optional filter
233233+234234+### PR5 (optional, separate track): witness cache
235235+- `witness_cache` table for raw records
236236+- replay tooling for backfills
237237+- independent of above work
238238+239239+## operational notes
240240+241241+- **cloudflare pages**: `leaflet-search` does NOT auto-deploy from git. manual deploy required:
242242+ ```bash
243243+ wrangler pages deploy site --project-name leaflet-search
244244+ ```
245245+- **fly.io backend**: deploy from backend directory:
246246+ ```bash
247247+ cd backend && fly deploy
248248+ ```
249249+- **git remotes**: push to both `origin` (tangled.sh) and `github` (for MCP + PRs)
250250+198251## next steps
1992522002531. ~~verify leaflet's site.standard.document structure~~ (done - they don't have any)
2012542. ~~find and examine offprint records~~ (done - no public content yet)
202202-3. decide on hybrid vs wait approach
203203-4. consider witness cache architecture (see below)
204204-5. design database migration
205205-6. implement generalized tap subscriber
206206-7. test with multi-platform data
255255+3. ~~PR1: database schema~~ (merged)
256256+4. PR2: generalized content extraction
257257+5. PR3: TAP subscriber
258258+6. PR4: API platform filter
259259+7. consider witness cache architecture (see below)
207260208261---
209262