a love letter to tangled (android, iOS, and a search API)
at main 128 lines 3.2 kB view raw view rendered
1# Deployment Walkthrough 2 3Twisted now deploys as one VPS Compose stack defined by 4`docker-compose.prod.yaml`. Coolify can still host that stack, but the Compose 5file is the source of truth. 6 7## Services 8 9- `postgres`: primary database on `pgvector/pgvector:pg17` 10- `migrate`: one-shot schema bootstrap via `twister migrate` 11- `api`: public HTTP service 12- `indexer`: private Tap consumer 13- `tap`: private Indigo Tap service 14- `llama-embeddings`: private llama.cpp server for future embedding work 15 16## Prerequisites 17 18- one VPS or Coolify host with Docker Compose 19- this repo available to the host 20- explicit `INDEXED_COLLECTIONS` and `READ_THROUGH_COLLECTIONS` 21- one shared `TAP_AUTH_PASSWORD` 22- a production `POSTGRES_PASSWORD` 23 24Use explicit search collections. Do not use `sh.tangled.*` in production. 25 26## Environment 27 28Required: 29 30- `POSTGRES_PASSWORD` 31- `TAP_AUTH_PASSWORD` 32- `INDEXED_COLLECTIONS` 33 34Common overrides: 35 36- `POSTGRES_USER` default `twisted` 37- `POSTGRES_DB` default `twisted` 38- `LOG_LEVEL=info` 39- `LOG_FORMAT=json` 40- `READ_THROUGH_MODE=missing` 41- `READ_THROUGH_COLLECTIONS=<explicit CSV>` 42- `READ_THROUGH_MAX_ATTEMPTS=5` 43- `HTTP_BIND_ADDR=:8080` 44- `INDEXER_HEALTH_ADDR=:9090` 45- `LLAMA_MODEL_REPO=nomic-ai/nomic-embed-text-v1.5-GGUF` 46- `LLAMA_MODEL_FILE=nomic-embed-text-v1.5.Q8_0.gguf` 47 48`llama-embeddings` is private and not part of search yet. It only keeps the 49model warm and cached for later adapter work. 50 51## Bootstrap 52 53From the repo root: 54 55```sh 56just vps-up 57``` 58 59That sequence: 60 611. starts PostgreSQL and Tap 622. runs `migrate` 633. starts `api`, `indexer`, and `llama-embeddings` 64 65## Clean Reset 66 67For a fresh VM or full reset: 68 69```sh 70just vps-reset 71``` 72 73This removes named volumes, recreates PostgreSQL, reapplies migrations, and 74starts the full stack from zero. 75 76## Coolify Notes 77 78If you run this through Coolify: 79 801. create one Docker Compose application 812. point it at `/docker-compose.prod.yaml` 823. set the env vars above in Coolify 834. expose only the `api` service through Traefik 84 85Do not add a separate PostgreSQL resource for this stack. 86 87## Checks 88 89- `api`: `GET /readyz` returns `200` 90- `indexer`: `GET /health` returns `200` 91- `indexer` can reach `ws://tap:2480/channel` 92- `llama-embeddings` serves embeddings on its internal port 93 94Then rebuild the serving dataset: 95 96```sh 97docker compose -f docker-compose.prod.yaml exec indexer twister backfill 98docker compose -f docker-compose.prod.yaml exec indexer twister enrich 99docker compose -f docker-compose.prod.yaml exec indexer twister reindex 100``` 101 102Do not import old Turso data as the default migration path. 103 104## App Target 105 106For local app builds: 107 108```sh 109VITE_TWISTER_API_BASE_URL=https://<your-api-domain> 110``` 111 112## Rollback 113 114- PostgreSQL restore is the rollback primitive 115- keep `--local` only as a temporary development fallback 116 117## Post-Deploy Checklist 118 119After a fresh deploy or indexer recovery: 120 1211. confirm `migrate` exited successfully 1222. confirm `api` returns `200` from `/readyz` 1233. confirm `indexer` returns `200` from `/health` 1244. in the `indexer` container run the following 125 1. run `twister backfill` 126 2. run `twister enrich` 127 3. run `twister reindex` 1285. watch `indexer` logs and confirm the Tap cursor keeps moving forward