3.4 KiB
3.4 KiB
Specifications
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:
noteortodo - body text
- tags
- device name
- sync status
- optional last error
org output
todo:
* TODO buy printer paper :home:errands:
:PROPERTIES:
:CREATED: [2026-05-17 sun 14:31]
:SOURCE: android
:ID: phone-20260517-143122-a8f2
:END:
note:
* 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:
/data/synq.org
/data/capture.sqlite3
/data/rejected.log
recommended host mapping:
/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:
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
- implement server first using curl tests.
- implement android local capture with room.
- implement manual sync.
- add workmanager opportunistic sync.
- add history screen and resend handling.
- polish launch speed and widget/share-target only after core path works.
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
backup
what to back up
the server writes to one directory (the /data volume). back up the whole thing:
/data/synq.org ← the canonical org capture file
/data/capture.sqlite3 ← idempotency store (dedup ids)
/data/token.txt ← auto-generated token (if not using PHONE_CAPTURE_TOKEN env var)
on unraid the host path is whatever you mapped in compose, e.g. /mnt/user/ben/synq/phone-capture.
restore behavior
- restore the
/datavolume to a new container and start it. the server will pick up where it left off. synq.orgis append-only plain text — it is human-readable and recoverable even without the sqlite db.- if
capture.sqlite3is lost butsynq.orgis intact, the server will accept re-posted captures that were already in the org file (no dedup). the android app marks them synced either way (already_seenoraccepted), so the only side effect is duplicate org entries for anything re-synced. restore the db from backup to avoid this. - if
token.txtis lost, delete it and let the server generate a new one on next start, then update the app settings.