# synq, a tiny android-to-org capture system. open app. type, optionally mark as todo, optionally add tags, save. if home server accessible, post unsynced captures to lan-only service and appended to `phone.org`. ## non-goals - no org parser on android - no agenda on android - no sync provider dependency - no nextcloud file editing - no conflict resolution - no public internet exposure - no ai tagging in v1 - no account system in v1 ## architecture ```text android app kotlin + jetpack compose room sqlite local queue workmanager + manual sync okhttp/retrofit client home server docker container on jeeves/unraid python + fastapi sqlite idempotency store append-only org writer flow user saves capture locally app marks it pending sync runs when server is reachable app posts pending captures to fastapi server validates, dedupes by id, appends to phone.org app marks capture synced ``` ## v1 behavior the app launches into a focused text box. the user can type immediately. controls: - note/todo toggle - optional tags field - save - save and close - sync now - small history view showing pending, synced, and failed entries each capture has: - stable client-generated id - created timestamp with timezone - kind: `note` or `todo` - body text - tags - device name - sync status - optional last error ## org output todo: ```org * TODO buy printer paper :home:errands: :PROPERTIES: :CREATED: [2026-05-17 sun 14:31] :SOURCE: android :ID: phone-20260517-143122-a8f2 :END: ``` note: ```org * note :retcon: :PROPERTIES: :CREATED: [2026-05-17 sun 14:33] :SOURCE: android :ID: phone-20260517-143322-b91c :END: mobile capture should stay dumb and append-only. ``` ## server paths default container paths: ```text /data/synq.org /data/capture.sqlite3 /data/rejected.log ``` recommended unraid host mapping: ```text /mnt/user/synq/phone-capture:/data ``` or map `/data/synq.org` directly to wherever the real org file lives. prefer a dedicated capture file first; emacs can include it in agenda later. ## security model v1 is lan-only. bind the service to the host lan and do not expose it through swag/cloudflare/public dns. minimum useful controls: - shared bearer token in app and server env - server only accepts json - server rejects empty body - server dedupes ids - server writes append-only org - server never edits or parses existing org - docker volume is backed up ## repo layout suggested monorepo: ```text synq/ android/ app/ server/ app/ main.py models.py org_writer.py store.py tests/ Dockerfile pyproject.toml docs/ api.md android-notes.md server-notes.md docker-compose.example.yml .env.example tasks.org README.md ``` ## build order 1. implement server first using curl tests. 2. implement android local capture with room. 3. implement manual sync. 4. add workmanager opportunistic sync. 5. add history screen and resend handling. 6. polish launch speed and widget/share-target only after core path works. ## v2 parking lot - android share target - quick settings tile or widget - tag chips from recent tags - configurable default tag - edit unsynced entries only - multi-device capture - wireguard-aware sync - local export/import - optional emacs ingest helpers