a love letter to tangled (android, iOS, and a search API)
1---
2title: Mobile App Reference
3updated: 2026-03-25
4---
5
6Twisted is an Ionic Vue mobile app for browsing Tangled, a git hosting platform built on the AT Protocol. It targets iOS and Android via Capacitor (no web target).
7
8## Tech Stack
9
10- **Vue 3** with TypeScript and Composition API
11- **Ionic Vue** for native-feeling UI components
12- **Capacitor** for iOS/Android builds
13- **Pinia** for state management
14- **TanStack Query** for async data with caching
15- **@atcute/client** and **@atcute/tangled** for AT Protocol XRPC
16
17TypeScript files use `.js` extensions in imports. Package management via pnpm.
18
19## Architecture
20
21Three-layer design:
22
23**Presentation** — Vue components and pages using Ionic's component library. Five-tab navigation: Home, Explore, Activity, Bookmarks/Profile, Settings. Repo detail uses segmented tabs: Overview, Files, Issues, PRs.
24
25**Domain** — TypeScript types modeling the app's data: UserSummary, RepoSummary, RepoDetail, RepoFile, PullRequestSummary, IssueSummary, ActivityItem. These are app-internal representations, decoupled from API response shapes.
26
27**Data** — Service layer that fetches from external sources and normalizes into domain types. The flow is: Vue component → composable → TanStack Query hook → service function → XRPC call → normalizer → domain model.
28
29## Directory Structure
30
31```sh
32src/
33 app/ — App shell, router, global config
34 core/ — Shared utilities, constants
35 services/ — API clients and data fetching
36 atproto/ — @atcute client setup, error handling
37 tangled/ — Endpoints, normalizers, TanStack Query hooks
38 domain/ — TypeScript type definitions
39 features/ — Feature modules (home, explore, repo, etc.)
40 components/ — Shared UI components
41```
42
43## Data Sources
44
45The app reads from multiple sources depending on what's needed:
46
47- **Knots** (Tangled XRPC servers) — Git data: file trees, blobs, commits, branches, diffs. Each repo is hosted on a specific knot.
48- **PDS** (Personal Data Servers) — AT Protocol records: profiles, issues, PRs, comments, stars, follows. Accessed via `com.atproto.repo.getRecord` and `com.atproto.repo.listRecords`.
49- **Twister API** — Search and index-backed summaries (when available).
50- **Constellation** — Social signal counts and backlinks (stars, followers, reactions).
51
52The app calls the Twister API for app data. Twister proxies knot and PDS reads,
53handle resolution, Constellation counts, and the Jetstream activity stream.
54
55## Completed Features
56
57### Navigation & Shell (Phase 1)
58
59Five-tab layout with Vue Router, skeleton loaders, placeholder pages, and a
60local Bookmarks area for repos, strings, and saved files.
61
62### Public Browsing (Phase 2)
63
64All release-mode browsing works without authentication:
65
66**Repository browsing** — Metadata display, README rendering (markdown), file tree navigation, file viewer with syntax context, commit log with pagination, branch listing.
67
68**Profile browsing** — Avatar, bio, links fetched from PDS. User's repos listed.
69
70**Issues** — List view with open/closed state filter, detail view with threaded comments.
71
72**Pull Requests** — List view with status filter (open/closed/merged), detail view with comments.
73
74**Caching** — TanStack Query configured with per-data-type stale times.
75Persistence currently uses IndexedDB via `idb-keyval`, with a separate local
76bookmarks store for saved repos, strings, files, and READMEs.
77
78## Storage Migration
79
80IndexedDB is the current implementation for cache and bookmark persistence, but
81it should be treated as an interim step.
82
83- Local cache and offline-content storage should migrate toward SQLite so larger
84 saved payloads, better inspection, and more explicit schema management are
85 available on-device.
86- Sensitive auth/session material should migrate toward Ionic secure storage
87 instead of living in browser-style storage primitives.
88- Until that migration lands, IndexedDB should stay limited to non-sensitive
89 cached data and user-saved offline reading content.
90
91## Auth Split
92
93Production builds are read-only and hide auth entry points. Dev builds keep the
94current OAuth flow available for testing future authenticated features.
95
96## Routing
97
98The app resolves identities through AT Protocol: handle → DID (via PDS resolution) → records. For repo git data, the knot hostname is extracted from the repo's DID document.
99
100Home tab currently provides direct handle-based browsing: enter a known handle to view their profile and repos. This works without any index or search dependency.