a love letter to tangled (android, iOS, and a search API)
at main 116 lines 3.1 kB view raw view rendered
1--- 2title: API Service Reference 3updated: 2026-03-26 4--- 5 6Twisted is a Go service that indexes Tangled content, serves search, and caches 7recent activity. It uses PostgreSQL for the primary runtime and retains a 8temporary local SQLite fallback behind `--local`. 9 10## Runtime Modes 11 12| Command | Purpose | 13| --- | --- | 14| `api` | HTTP API server | 15| `indexer` | Tap consumer and index writer | 16| `migrate` | apply embedded SQL migrations | 17| `backfill` | register repos with Tap | 18| `enrich` | fill missing repo names, handles, and web URLs | 19| `reindex` | re-upsert documents and finalize the search index | 20| `healthcheck` | one-shot config and process probe | 21 22## HTTP API 23 24- `GET /healthz` — liveness probe 25- `GET /readyz` — readiness probe, checks database reachability 26- `GET /search` — keyword search 27- `GET /documents/{id}` — fetch one indexed document 28- `GET /admin/status` — cursor and queue state when admin routes are enabled 29 30The API also serves the built-in search/docs site from `/` and `/docs*`. 31 32## Search 33 34Keyword search is implemented with PostgreSQL full-text search. 35 36- weighted fields: title, author handle, repo name, summary, body, tags 37- query parser: `websearch_to_tsquery('simple', ...)` 38- ranking: `ts_rank_cd` 39- snippets: `ts_headline` 40 41Response shape stays the same as the previous FTS5 API. Ranking and snippet 42details are allowed to differ from the SQLite-era implementation. 43 44## Database 45 46Primary backend: PostgreSQL. 47 48Main tables: 49 50- `documents` 51- `sync_state` 52- `identity_handles` 53- `record_state` 54- `indexing_jobs` 55- `indexing_audit` 56- `jetstream_events` 57 58`documents` stores a generated weighted `tsvector` column plus a GIN index for 59keyword search. 60 61No embedding tables are active yet. `llama-embeddings` is deployed only as 62infra groundwork for a later semantic-search milestone. 63 64## Configuration 65 66Primary env vars: 67 68- `DATABASE_URL` 69- `HTTP_BIND_ADDR` 70- `INDEXER_HEALTH_ADDR` 71- `TAP_URL` 72- `TAP_AUTH_PASSWORD` 73- `INDEXED_COLLECTIONS` 74- `READ_THROUGH_MODE` 75- `READ_THROUGH_COLLECTIONS` 76- `READ_THROUGH_MAX_ATTEMPTS` 77- `ENABLE_ADMIN_ENDPOINTS` 78- `ADMIN_AUTH_TOKEN` 79 80Default local database URL: 81 82```sh 83postgresql://localhost/${USER}_dev?sslmode=disable 84``` 85 86`--local` is deprecated and switches to the legacy SQLite fallback at 87`packages/api/twister-dev.db`. 88 89## Local Operation 90 91Start local Postgres with the repo compose file: 92 93```sh 94just db-up 95just api-build 96DATABASE_URL="postgresql://localhost/${USER}_dev?sslmode=disable" \ 97 ./packages/api/twister migrate 98just api-dev 99just api-run-indexer 100``` 101 102That dev compose file also runs Tap locally at `ws://localhost:2480/channel`. 103`api` and `indexer` no longer auto-apply schema changes on startup. 104 105Use `just api-dev sqlite` only when you need the temporary SQLite rollback path. 106 107## Deployment 108 109Production uses: 110 111- `docker-compose.prod.yaml` as the VPS stack source of truth 112- in-stack PostgreSQL on `pgvector/pgvector:pg17` 113- a one-shot `migrate` service before long-lived services start 114- private Tap and llama.cpp embedding services on the internal Compose network 115 116See `docs/reference/deployment-walkthrough.md` for the full production flow.