a love letter to tangled (android, iOS, and a search API)
1# Twisted
2
3Twisted is a monorepo for a Tangled mobile client and the supporting Tap-backed indexing API.
4
5## Projects
6
7- `apps/twisted`: Ionic Vue client for browsing Tangled repos, profiles, issues, PRs, and indexed search results
8- `packages/api`: Go service that consumes Tangled records through Tap, fills gaps in the public Tangled API, and serves search
9- `docs`: top-level specs and plans, split by project under `docs/app` and `docs/api`
10
11## Architecture
12
13The app still uses Tangled's public knot and PDS APIs for canonical repo and profile data. The API project adds two complementary capabilities:
14
151. Global search over indexed Tangled content
162. Index-backed summaries for data that is hard to derive from the public API alone, such as followers
17
18That keeps direct browsing honest while giving the client one place to ask for cross-network discovery and graph augmentation.
19
20## Development
21
22Use the top-level [`justfile`](justfile) for common workflows:
23
24```bash
25just dev
26just build
27just test
28just api-run-api
29```
30
31To enable indexed search in the client, set `VITE_TWISTER_API_BASE_URL` in `apps/twisted/.env`.
32
33## Run Locally
34
35Install dependencies once from the repo root:
36
37```bash
38pnpm install
39```
40
41Start the Ionic/Vite app:
42
43```bash
44pnpm dev
45# or: just dev
46```
47
48That serves the client from `apps/twisted` with Vite.
49
50To run the Go API locally, make sure `packages/api/.env` has at least:
51
52- `TURSO_DATABASE_URL`
53- `TURSO_AUTH_TOKEN`
54
55Then start the API:
56
57```bash
58pnpm api:run:api
59# or: just api-dev
60```
61
62This serves the API and search site on `http://localhost:8080`.
63
64To run the indexer as well, `packages/api/.env` also needs:
65
66- `TAP_URL`
67- `TAP_AUTH_PASSWORD`
68- `INDEXED_COLLECTIONS`
69
70Then start the indexer in a separate terminal:
71
72```bash
73pnpm api:run:indexer
74# or: just api-run-indexer
75```
76
77Typical local setup is three terminals:
78
791. `pnpm dev`
802. `pnpm api:run:api`
813. `pnpm api:run:indexer`
82
83If you want the app to call the local API, set this in `apps/twisted/.env`:
84
85```bash
86VITE_TWISTER_API_BASE_URL=http://localhost:8080
87```
88
89## Infrastructure Setup
90
91### Turso
92
93Use one Turso database per environment, for example:
94
95- `twister-dev`
96- `twister-prod`
97
98Do not introduce separate app variable names for dev and prod. Always use the same variables:
99
100- `TURSO_DATABASE_URL`
101- `TURSO_AUTH_TOKEN`
102
103Only the values change per environment.
104
105Example:
106
107```bash
108# Development
109TURSO_DATABASE_URL=libsql://twister-dev-your-org.turso.io
110TURSO_AUTH_TOKEN=...
111
112# Production
113TURSO_DATABASE_URL=libsql://twister-prod-your-org.turso.io
114TURSO_AUTH_TOKEN=...
115```
116
117### Railway
118
119Create or reuse one Railway project containing:
120
121- existing `tap`
122- `api` running `twister api`
123- `indexer` running `twister indexer`
124
125Set these shared variables on the Railway services:
126
127- `TURSO_DATABASE_URL`
128- `TURSO_AUTH_TOKEN`
129- `LOG_LEVEL`
130- `LOG_FORMAT`
131
132Set these API-specific variables:
133
134- `HTTP_BIND_ADDR`
135- `SEARCH_DEFAULT_LIMIT`
136- `SEARCH_MAX_LIMIT`
137
138Set these indexer-specific variables:
139
140- `TAP_URL`
141- `TAP_AUTH_PASSWORD`
142- `INDEXED_COLLECTIONS`
143
144If you use separate Railway environments for dev and prod, keep the same variable names in both and only swap the Turso values.
145
146### First Bootstrap
147
148For a brand-new environment:
149
1501. Point `TURSO_DATABASE_URL` and `TURSO_AUTH_TOKEN` at the target database.
1512. Deploy `api` and `indexer` on Railway.
1523. Verify API readiness and indexer health.
1534. Run `twister backfill` with your seed file.
1545. Treat the environment as search-ready only after historical backfill completes.
155
156## Docs
157
158- Index: [`docs/README.md`](docs/README.md)