···11# CLAUDE.md
2233-This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
33+This file provides guidance to Claude Code (claude.ai/code) when working with
44+code in this repository.
4556## What This Is
6777-OpenPDS is a directory of AT Protocol PDS servers with open registration. It runs on Val Town as a serverless app with two entry points: an HTTP server and a daily cron job. Data comes from [mary-ext/atproto-scraping](https://github.com/mary-ext/atproto-scraping) and gets enriched with health, geo-IP, version, and trust metadata.
88+OpenPDS is a directory of AT Protocol PDS servers with open registration. It
99+runs on Val Town as a serverless app with two entry points: an HTTP server and a
1010+daily cron job. Data comes from
1111+[mary-ext/atproto-scraping](https://github.com/mary-ext/atproto-scraping) and
1212+gets enriched with health, geo-IP, version, and trust metadata.
813914## Commands
1015···1621deno task deploy # fmt + lint + check + test + vt push (full deploy pipeline)
1722```
18231919-Do **not** use `vt push` directly — always use `deno task deploy` which runs quality checks first.
2424+Do **not** use `vt push` directly — always use `deno task deploy` which runs
2525+quality checks first.
20262127## Architecture
22282323-**Runtime:** Deno on Val Town. **Framework:** Hono. **Database:** Val Town SQLite. **Imports:** via `esm.sh` (not npm/node_modules).
2929+**Runtime:** Deno on Val Town. **Framework:** Hono. **Database:** Val Town
3030+SQLite. **Imports:** via `esm.sh` (not npm/node_modules).
24312532### Entry Points
26332727-- `backend/index.http.ts` — HTTP trigger. Hono app serving HTML directory (`/`) and JSON API (`/api/servers`). Runs migrations on first request.
2828-- `cron/refresh.cron.ts` — Cron trigger. Daily refresh: fetch PDS list → sync to DB → fetch latest version → enrich batch of servers.
3434+- `backend/index.http.ts` — HTTP trigger. Hono app serving HTML directory (`/`)
3535+ and JSON API (`/api/servers`). Runs migrations on first request.
3636+- `cron/refresh.cron.ts` — Cron trigger. Daily refresh: fetch PDS list → sync to
3737+ DB → fetch latest version → enrich batch of servers.
29383039### Data Flow (Cron)
314032411. `pds-fetcher.ts` downloads state.json (~2900 PDSes)
33422. Each PDS upserted to SQLite with open/closed status
34433. `version-checker.ts` gets latest PDS version from GitHub API
3535-4. `pds-enricher.ts` enriches a batch (configurable, default 20): DNS resolve → health check → describeServer → listRepos user count → geo-IP batch lookup
4444+4. `pds-enricher.ts` enriches a batch (configurable, default 20): DNS resolve →
4545+ health check → describeServer → listRepos user count → geo-IP batch lookup
36465. Results written back to DB via `updateEnrichment()`
37473848### Module Layout
39494040-- `backend/database/` — `migrations.ts` (schema), `queries.ts` (all SQL operations, row-to-object mapping)
4141-- `backend/routes/` — `pages.ts` (server-rendered HTML), `api.ts` (JSON endpoint)
4242-- `backend/services/` — Pure async functions: `pds-fetcher`, `pds-enricher`, `geo-resolver`, `version-checker`
4343-- `shared/` — `types.ts` (all TypeScript interfaces), `constants.ts` (config values, country flag helper)
5050+- `backend/database/` — `migrations.ts` (schema), `queries.ts` (all SQL
5151+ operations, row-to-object mapping)
5252+- `backend/routes/` — `pages.ts` (server-rendered HTML), `api.ts` (JSON
5353+ endpoint)
5454+- `backend/services/` — Pure async functions: `pds-fetcher`, `pds-enricher`,
5555+ `geo-resolver`, `version-checker`
5656+- `shared/` — `types.ts` (all TypeScript interfaces), `constants.ts` (config
5757+ values, country flag helper)
4458- `cron/` — Scheduled job orchestration
45594660### Trust Score
47614848-5 boolean signals, each worth 20%: contact email, ToS, privacy policy, active users (>5), latest PDS version. Calculated in SQL via CASE expressions.
6262+5 boolean signals, each worth 20%: contact email, ToS, privacy policy, active
6363+users (>5), latest PDS version. Calculated in SQL via CASE expressions.
49645065## Val Town Specifics
51665252-- Exports use Val Town conventions: HTTP files export `app.fetch`, cron files export a default async function
6767+- Exports use Val Town conventions: HTTP files export `app.fetch`, cron files
6868+ export a default async function
5369- SQLite accessed via `https://esm.town/v/stevekrouse/sqlite`
5454-- Schema changes: create new table names (append `_2`, `_3`) rather than ALTER TABLE
7070+- Schema changes: create new table names (append `_2`, `_3`) rather than ALTER
7171+ TABLE
5572- No `Deno` namespace in `shared/` code (must work in browser context too)
5673- Secrets via `Deno.env.get()`, never hardcoded
57745875## Conventions
59766060-- Database columns: `snake_case`. TypeScript code: `camelCase`. `rowToServer()` maps between them.
6161-- Per-request timeouts via `AbortSignal.timeout()` (5s for PDS endpoints, 10s for geo batch)
7777+- Database columns: `snake_case`. TypeScript code: `camelCase`. `rowToServer()`
7878+ maps between them.
7979+- Per-request timeouts via `AbortSignal.timeout()` (5s for PDS endpoints, 10s
8080+ for geo batch)
6281- Batch operations use `Promise.allSettled()` for partial-failure resilience
6382- HTML output uses custom `esc()` function for XSS prevention