A public data workbench: one console over several data collections,
each read through its own adapter, with search, filters, comparison and
exports that carry their source and collection date. It is the first product
built on the SaaS Maker UI library (sass-maker/ui-library, Console template).
Plan and decisions: Significant-Hobbies/ph-catalog#14. Collectors stay in their own repos; techdata only reads until parity is proven.
| Collection | Source | Read via | Freshness |
|---|---|---|---|
| Nomad Atlas places | Nomads.com, via Significant-Hobbies/nomad-data-adventure |
Bundled public/data/nomad/cities.json (byte-identical, sha256-checked) and Atlas's model.js copied unchanged |
Snapshot collected 2026-09-07, published 2026-09-13 (517cbeb) |
| High Signal Podcasts | Significant-Hobbies/on-record |
Public API api.podcasts.highsignal.app/api (read-only) |
API read-time provenance; collection cadence is separate (below) |
| Reddit Insights | Reddit, via High-Signal-App/research-subreddit |
Public Snapshot API reddit-insights.highsignal.app/api/snapshots (GET only) |
Capture windows and revision on every snapshot; 24-hour serving leases |
| PH Catalog | Product Hunt public pages, via Significant-Hobbies/ph-catalog |
Browser DuckDB-WASM over private R2 Parquet via the Worker | ph-catalog catalog-state, published/exported 2026-10-10; 575,479 products, 93,897 with categories |
| Research Papers | High-Signal-App/research-papers |
Public GET JSON exports at papers.highsignal.app (CC-BY 4.0) |
Response Date/Last-Modified or read time; collection date not recorded |
This inventory is the portable documentation portion of #12, based on public checked-in source/docs reviewed on 2026-10-13. The owner recommendation is a recommendation, not finalized approval of a collector architecture. techdata currently reads through adapters; collector code and writes remain in the source repos. Repository ownership below means responsibility in checked-in code/docs, not a verified on-call assignment or proof that a job is enabled. Configured schedules, suggested cadences, serving leases and successful live refreshes are different kinds of evidence.
| Collection | Owning source repo | Evidenced refresh cadence/workflow | Export path and techdata handoff |
|---|---|---|---|
| Nomad Atlas | Significant-Hobbies/nomad-data-adventure | Completed saved-snapshot experiment; source README states no active collection or expansion roadmap. No recurring refresh is evidenced. | Source data/nomads_cities.json and public cities.json are byte-identical. techdata bundles public/data/nomad/cities.json and the unchanged source model.js; local hash/parity tests pin these copies. Current bundled collection date is 2026-09-07. |
| High Signal Podcasts | Significant-Hobbies/on-record | Checked-in cron-ingest.yml: discovery/transcripts daily at 06:00 UTC (11:30 IST), plus Sunday 07:00 UTC (12:30 IST) discovery/transcripts and claim extraction; manual dispatch also exists. These are configured triggers, not verified active runs. |
Python ingest writes through the source Worker publication gate; D1 holds records and R2 holds raw material. techdata reads the public api.podcasts.highsignal.app/api/{stats,episodes,people,claims} routes, not raw storage or a database dump. Published API data needs no source SSR rebuild. |
| Reddit Insights | High-Signal-App/research-subreddit | Historical ingest/analyze/UI pipeline is documented as manual. The daily Worker is explicitly an undeployed scaffold, despite its configured 02:17 UTC (07:47 IST) cron. Current forward-collector activation/cutover and actual publication/lease-renewal cadence are unknown from the reviewed evidence. | Daily-v2 archive import verifies source packs and writes minimized gzip derivatives in artifacts/daily-snapshots/; publication writes reddit-insights/exports/v1/index.json and catalogued derivatives to private storage. techdata reads public /api/snapshots/catalog and /api/snapshots/:date/:subreddit?v= at reddit-insights.highsignal.app, never raw archives. A 24-hour serving lease is an expiry rule, not proof of daily collection. |
| Research Papers | High-Signal-App/research-papers | Operations docs suggest daily arXiv/OpenReview, weekly citation graph, and daily overlay/export jobs via host launchd. Installed jobs, host timezone, latest successful run and current cadence are unverified. |
papers export-ch regenerates web/public/data/*.json from ClickHouse; docs describe papers warm-update --build-web and a subsequent static rebuild/publication. techdata reads public /data/{top_papers,hot,sleepers,review_top_papers,top_cited_works,top_authors,summary}.json, /paths.json and supported /paper/:arxiv_id.md routes at papers.highsignal.app, not operator ClickHouse/API state. |
| PH Catalog | Significant-Hobbies/ph-catalog | Checked-in daily.yml: daily 21:47 UTC (03:17 IST next day), self-hosted macOS/ARM64 runner, bounded daily --limit 500 --workers 2 --rps 0.25, verification and release export. Enabled scheduler, runner health and successful private export are unverified. |
Source generates producthunt-full.parquet (seven-field product table) and ph-catalog-full.tar.zst (portable catalogue/provenance archive), uploaded to mutable private catalog-state release. techdata's allowlisted R2 read path is /api/files/ph/producthunt-full.parquet; public/data/ph/summary.json is a derived first-paint summary. A source daily release does not automatically update either techdata copy. |
The links below pin the reviewed source revisions; they are source evidence, not new production receipts or instructions to run the collectors.
- Nomad: README at
32ad9ffstates the completed/snapshot-only status. techdata snapshot metadata retains the original collection date/revision. A future recollection or copy refresh needs a separate decision; this inventory does not schedule one. - Podcasts: workflow at
752b16e, ingest runbook and README. The runbook's daily--focus recsdescription disagrees with the workflow's weekly--focus all --max-segments 40extraction step; the table reports the checked-in workflow. README also labels the project inactive. Neither cron syntax nor an HTTP read timestamp establishes active ingestion or publication. - Reddit: README at
2c3abee, collector activation gate, scaffold cron and ownership/handoff contract. The docs assign canonical collector/archive responsibility to Reddit Insights and describe transition from a High Signal-hosted archive. They do not establish completed cutover here. The documented publisher renews leases only after an authoritative manifest reread; private archive/redaction/renewal receipts remain an operator gate. No duplicate collector activation is implied. - Papers: suggested jobs at
ef940e9, data/export map and refresh quality manifest. Suggested host times are 03:00 arXiv, 04:00 OpenReview, 05:00 weekly graph, 06:00 overlay/export; timezone/installation are not evidenced. Actual watermarks, output counts and failures live in the gitignored operator refresh manifest, which was not read. techdata's separatescripts/papers-citations.mjsproducespublic/data/papers/citations.jsonfrom public paper lists/OpenAlex; no recurring schedule is checked in for that supplemental snapshot, and none is added here. - PH: daily workflow at
13d3167, README and portable handoff docs. The immutablecatalog-handoff-v1archive is a separate documented boundary from the mutablecatalog-staterelease; private assets/checksum receipts were not fetched. A 03:15 host-local launchd template also exists, but installation and coexistence with Actions are unknown. It is not evidence of a second active scheduler. techdata summary generation and approved R2 replacement remain separate maintenance steps described below.
Open gates: the keep-versus-relocate architecture decision in #12 remains with the owner, as does any source-site retirement decision in #13. Current operator/on-call assignments, enabled schedules, private manifests/releases, credential readiness, last successful collection/publication and live export freshness remain unverified. A fetched date records a read, not collector success; missing upstream collection dates stay missing. This documentation phase adds no freshness enforcement, collector relocation, job activation, schedule/resource/ configuration change, credential provisioning or retirement approval.
Inventory of nomad.significanthobbies.com (app.js, model.js, index.html
at 3ab6a63) and where each lives in techdata (/nomad/).
| Atlas feature | techdata |
|---|---|
| Search name/country, accent-insensitive | Filter search (same fold) and ⌘K |
| Region and country filters | Facets with counts (multi-select) |
| Cost profiles: nomad, expat, local, family | Profile toggle; drives cost column, cost filter, median, cards |
| Max monthly cost slider | cost range on the selected profile |
| Internet, safety minimums; remote-work-visa checkbox | Ranges and a visa facet |
| Lifestyle & inclusion: walkability, healthcare, English, female, LGBTQ+, nightlife, cleanliness | Ranges under "more filters" |
| Weather snapshot: min/max °C, max AQI | temp and aqi ranges under "more filters" |
| Quick filters: all, under $1,500, well connected (50+), walkable (4+), remote work visa | Same five presets |
| Card and table views | Both (view=cards; phones default to cards) |
| 8 sort orders (overall, lowest cost, internet, safety, walkability, healthcare, nightlife, lowest AQI) | Sort menu plus sortable columns; missing values last, ties by name |
| Pagination ("explore more") | Pages of 50 (table) / 48 (cards) |
| Shareable filter URLs | Every filter, profile, sort, view, open place and shortlist is in the URL; old Atlas links are translated on load |
| Result insights: count, median cost, median internet, countries | Same, above the table |
| Active filter chips, reset, empty state | Library ActiveFilters, clear all, empty state |
| City details: four profile costs, every other metric, source link | Record detail panel (sheet on phones) with provenance |
| Unusual-estimate flag (< $100 or > $30,000) | Kept as published, flagged in table, cards, detail and compare |
| Compare up to 3 places across 22 metrics, shortlist bar | Shortlist bar and /nomad/compare/?places=… (add/remove there too) |
| Original JSON download | "original json" (byte-identical file) |
| Filtered JSON / CSV export with every source field | Export menu: all 27 source fields, JSON wraps source, collected-at, profile and filters |
| About the data notes | /nomad/notes/ with dataset counts and checksum |
| Space novelty entries excluded (1,383 → 1,374) | Same |
Parity is tested: tests/nomad.test.ts runs 19 Atlas filter/sort
combinations and all presets through Atlas's own selectCities and through
techdata, and requires identical slugs in identical order.
Left out on purpose (public-site chrome, not data features): hero art, newsletter capture, project strip and Ask-AI footer.
App Health browser analytics runs only on https://data.highsignal.app and is
skipped for fleet_qa=1, local development and preview origins. It records
page views and active sessions using a first-party browser ID that can persist
for up to 90 days; search text is excluded. Bot filtering is enabled, but manual
QA and other automation may still be counted. No core action or account identity
is inferred from page views.
- Claims (
/podcasts/claims/): full-text search with claim type, speaker and said-on date filters (newest 50, as the API returns); claim detail with the verbatim quote, verified-speaker attribution, timestamp deep link (caption transcripts only), transcript window around the quote, evidence, mentions, episode source and public claim page. - Episodes (
/podcasts/): server-paged list with show filter and search; detail lists the episode's claims with timestamps. - People (
/podcasts/people/): verified speakers, server-paged; detail with their newest claims and a link to search all of them. - Unverified speakers are labelled, never named or listed as people (the API enforces this; tests check techdata never upgrades them).
- Subreddits (
/reddit/): communities from the live catalog, latest recorded post/retained-comment counts, coverage and available dates; facets with counts. - Threads (
/reddit/posts/): chosen community and collection date, searchable post table, real post-label facet, recorded score range, score/reply sorting. URL state includes the 12-character revision; thread details show body, source permalink, reported replies, retained comments and exact UTC collection window. - Posts and retained-comments CSV/JSON exports carry subreddit, date, full revision, captured-at and source on each row. JSON also keeps provenance, coverage, window, attribution and applied filters. Posts export the filtered view; comments export all retained comments in the selected snapshot.
- Author/profile fields are omitted. Labels use the API's
flair; no inferred topics. Coverage is always shown: retained comments are filtered and scores and reply totals are recorded values, never current Reddit values. - Not-archived, removed revision, expired and unavailable states remain distinct.
Snapshot reads use no-store and pinned
?v=requests; global search only searches community names plus bounded, already loaded latest snapshots still catalogued. REDDIT_INSIGHTS_API_BASEcan override the public origin (no configuration change required). No writes, archive access or collector changes.
/ph/: 575,479 products (93,897 with categories). The prerendered HTML contains the first page by name from the real export, with full-export facet counts. DuckDB-WASM starts after paint; the first two pages remain browsable during loading. Other URL filters/sorts/pages and product details wait for the engine. Browser-only DuckDB-WASM queries names/taglines/descriptions with case/accent-insensitive search, category and website facets with counts, sorting, URL state, paging and slug-selected detail.- CSV/JSON exports include all filtered rows and provenance; JSON carries source, collectedAt (not recorded), fetchedAt, release revision, export date and filters.
- The full Parquet export loads from
/api/files/ph/producthunt-full.parquetusing HTTP range reads; it is not downloaded into a browser buffer first. GET /api/ph/summaryand/api/collectionsexpose static full-export provenance; product queries stay in the browser.- Pinned DuckDB-WASM 1.32.0 modules and workers load lazily from
/api/files/duckdb/1.32.0/on the same origin. Capability selection downloads only one bundle: the smaller EH on supported browsers, otherwise MVP. - Full filtered exports are prepared on request, then downloaded through the export menu; they do not block the first interactive page.
- Only the DuckDB-WASM path is implemented; the DuckDB-WASM vs D1 benchmark is open.
The shared ⌘K index lazily merges client
searchPh()hits with server results. - No per-row server API, writes, votes or launch dates. Attribution: Product Hunt (public product pages), catalogue by ph-catalog. Per-record collection dates are absent; the release publication date is not used as a collection date.
Regenerate the small summary using the pinned WASM dependency (no additional production dependency). The script checks the full SHA-256 and both totals, uses the same default SQL sort as the browser, and enforces a 150 KiB gzip cap. DuckDB may download its matching Parquet extension on the first script run. Keep the downloaded Parquet outside the repository:
gh release download catalog-state --repo Significant-Hobbies/ph-catalog --pattern producthunt-full.parquet --dir /tmp/techdata-ph-export
node scripts/ph-summary.mjs /tmp/techdata-ph-export/producthunt-full.parquetpublic/data/ph/summary.json contains 100 display rows (descriptions are deferred
to the full engine), category/website counts, totals and release/source provenance.
Astro passes it to the server-rendered React island, so useful rows are in the
HTML before hydration. ph-query-ready is a browser performance mark emitted
after the requested full-engine page/detail and its counts/facets resolve; export
preparation is deliberately separate. Saved views, column visibility and filter
URLs use the existing state hooks.
- Papers (
/papers/): merged public top, hot, sleepers and OpenReview review lists, keyed by published arXiv/OpenReview ID, with list/category/year/ venue/decision/topic filters and facet counts, search, sorting, pagination, URL state, detail and filtered CSV/JSON exports. Differing list metrics remain in thepublishedfield; top-papers fields take precedence in the merged row. - Detail shows the published citation count, cites/year, in-corpus degree, PageRank/Katz, topics, keywords, reviews, arXiv/OpenReview links, public paper Markdown (top 200 only), and actual reading-path memberships.
- Reading paths (
/papers/paths/): readings in source order with authors, source links, the path's ownsourceNoteandtrustNote. A path reading need not be in the selected paper export. Authors on paper rows come only from published reading-path metadata, not author rankings. - Cited works (
/papers/cited/) and authors (/papers/authors/): public aggregate rankings, sortable/filterable tables, details and exports. - Corpus totals in
summary.jsondescribe the operator snapshot (478,991 papers and 8,981,698 paper edges), not the number of publicly browsable papers. Public paper counts are computed from the merged exports. Missing files are labelled explicitly; counts then cover only available files. - Citation links on paper details come from the separate OpenAlex (CC0) snapshot, matched by DOI or API-verified arXiv location. References and cited-by include only papers in the merged public collection; unmatched or conflicting identifiers are labelled. This is separate from the operator corpus metrics. Source and fetched date appear next to the links. The static JSON is fetched only when a paper detail opens, never for list pages.
Regenerate offline (or with the same command in a scheduler):
node scripts/papers-citations.mjsThe script reads all four public paper lists, batches up to 50 DOI filters,
uses mailto=techdata@users.noreply.github.com, makes at most eight requests
per second, and retries network/429/5xx failures with bounded backoff. It verifies
DOI/arXiv identifiers in returned OpenAlex locations, never titles. Failed reads
leave the existing file intact. Output ordering is deterministic for the same
inputs and timestamp; public/data/papers/citations.json has a 1.5 MB cap.
Home summaries and the first episode page are also read at build time, with their
actual fetch dates; episodes revalidate through the live API after hydration.
- Attribution: Research Papers (High Signal), CC-BY 4.0, via public JSON
exports. Every API envelope and export carries source and fetched-at;
collection date is null when unrecorded. Submitted dates, Markdown
last_updatedandpaths.generatedAtare not collection dates. Freshness uses response Last-Modified/Date where present, otherwise read time. RESEARCH_PAPERS_BASEoptionally overrides the default public site base. Resources load lazily and cache per adapter instance. No operator APIs, ClickHouse access, collection or source writes are used.- API:
/api/papers/papers(view filter params,sort=field:asc|desc,limit,offset),/api/papers/papers/:id,/api/papers/paths,/api/papers/paths/:id,/api/papers/cited-works,/api/papers/authors.
- Astro 7 + React islands, prerendered pages, on one Cloudflare Worker
(
@astrojs/cloudflare)./api/*is a Hono app (src/server/app.ts). - One adapter per collection under
src/adapters/; no shared record schema. The contract (types.ts) is summary, search hits and provenance; each adapter keeps its own record shape. GET /api/search?q=&limit=fans out to server adapters in parallel (5-second deadline each) and returns{hits, collections: [{id, ok, ms, count, error?}], provenance}. Source summaries need no extra upstream reads; record views carry dates/revisions. Optionalcollectionandkindfilters remain supported. Timeouts retain request-local partial hits when supported. Failures return other hits withno-store; successful reads use short-lived public caching.src/search/index.tsranks and caps hits; ⌘K shares one request per query and lazily merges browser-only PH hits into stable collection groups.GET /api/collections,/api/nomad/places(same query string as the view),/api/nomad/places/:slug, and/api/podcasts/{stats,episodes,episodes/:id,people,people/:slug,claims,claims/:id},/api/reddit/catalogand/api/reddit/snapshots/:date/:subreddit?v=.- UI:
ConsolePage,DataTable,FilterBar/useUrlFilters,SearchPalette,RecordDetail,ExportMenufrom@saas-maker/*v0.1.14 (git dependency).
Every explorer can save its collection URL, filters, sort and visible columns, or copy the same link for sharing. Saved views appear in a fixed-height sidebar list with rename/delete controls. Views and pins use schema-validated, versioned localStorage keys; unavailable storage falls back to session storage, then memory.
Select table rows or pin a record in its details to add it to /compare/ (up to
24 pins). Nomad's existing shortlist uses “pin selected to tray”; the original
/nomad/compare/?places=… view is unchanged. Claims offer a table alongside the
existing quote view. The palette includes a pinned group. Compare retains the
selected record's actual fields and source dates/revision/URL as a local snapshot;
different collections stay in separate groups and unverified speakers stay unnamed.
Needs Node 22+ and pnpm 10.33.2. sass-maker/ui-library is public.
pnpm install --frozen-lockfile
pnpm dev # astro dev (workerd) on http://localhost:4321
pnpm run check # typecheck, Biome lint, tests, build
pnpm run build && pnpm run preview # production build on workerd, port 4329Deploy is manual and owner-approved only (.github/workflows/deploy.yml,
workflow_dispatch). The Worker is public and requires no authentication.
The R2 bucket stays private: do not enable a public bucket endpoint.
The selected canonical host is https://data.highsignal.app. The manual
workflow pins PUBLIC_SITE_URL to that origin at build time; local builds can
set it explicitly. Astro's site setting gives each page a query-free canonical.
The Worker serves both the custom domain and the existing workers.dev host;
/robots.txt and /sitemap.xml advertise the configured canonical origin on
either host. Without PUBLIC_SITE_URL, local builds use the request origin for
those two dynamic crawl endpoints and omit page canonicals. Robots allows pages
and disallows /api/; JSON and file responses have no robots header.
Content duplicates the five live source sites: Nomad Atlas (Nomads.com), High Signal Podcasts, Reddit Insights, Product Hunt (catalogue by ph-catalog), and Research Papers (CC-BY 4.0). The owner deliberately chose indexable pages with techdata self-canonicals on 2026-10-10. Revisit this canonical/indexing choice when those sites retire.
wrangler.jsonc binds the existing techdata-data bucket as DATA.
GET/HEAD /api/files/* serves exactly the five objects listed below through
the public Worker; all other keys and directory/list requests return 404.
Reads stream with single-range support. Parquet uses public one-hour caching,
an ETag and conditional 304 responses; versioned DuckDB files use immutable
one-year public caching.
Objects uploaded on 2026-10-10 using wrangler r2 object put --remote:
ph/producthunt-full.parquet: full export from ph-catalog catalog-state, 79,066,044 bytes, SHA-256e1d25bc8c46fe0e92c68b51a107702d12c3da87b738cbfdfa8c7cd84424cd006.duckdb/1.32.0/{duckdb-eh.wasm,duckdb-mvp.wasm,duckdb-browser-eh.worker.js,duckdb-browser-mvp.worker.js}: copied from@duckdb/duckdb-wasm1.32.0dist.
Upload command shape (documentation only; uploads require owner approval):
wrangler r2 object put techdata-data/ph/producthunt-full.parquet --remote --file <export.parquet> --content-type application/octet-stream
wrangler r2 object put techdata-data/duckdb/1.32.0/duckdb-eh.wasm --remote --file <dist/duckdb-eh.wasm> --content-type application/wasm
wrangler r2 object put techdata-data/duckdb/1.32.0/duckdb-browser-eh.worker.js --remote --file <dist/duckdb-browser-eh.worker.js> --content-type application/javascriptThe MVP files use the same respective content types. The route preserves stored
Content-Type metadata and adds nosniff; keep upload metadata correct.
- Qualify the custom domain's HTTPS, indexing and collection links in issue #24.
- DuckDB-WASM vs D1 benchmark.
- Parity sign-off per collection, then decide the public sites' fate.