Files
synq/docs/spec.md
2026-05-21 13:20:30 -04:00

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: note or todo
  • 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

  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.

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 /data volume to a new container and start it. the server will pick up where it left off.
  • synq.org is append-only plain text — it is human-readable and recoverable even without the sqlite db.
  • if capture.sqlite3 is lost but synq.org is 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_seen or accepted), so the only side effect is duplicate org entries for anything re-synced. restore the db from backup to avoid this.
  • if token.txt is lost, delete it and let the server generate a new one on next start, then update the app settings.