feat: replace SFTP drop with Syncthing share path

Remove SFTPGo; mount event data from the Syncthing folder, watch
incoming/, and name variants after the source stem.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Frank Schwenk
2026-07-18 14:06:57 +02:00
parent 83d4468b69
commit d5b44b221e
13 changed files with 167 additions and 189 deletions
+22 -22
View File
@@ -6,23 +6,24 @@
## One-Liner
Event photo pep pipeline: SFTP -> gmic/rembg -> web. Upload a photo at the
event, get back weird/fun filtered variants seconds later.
Event photo pep pipeline: Syncthing drop -> gmic/rembg -> web. Upload a
photo at the event, get back weird/fun filtered variants seconds later.
## Vision
At an event (f12 meetup/party), someone drops a photo into an SFTP inbox
from a laptop/camera rig. A worker rips the background off, runs it
At an event (f12 meetup/party), someone drops a photo into a Syncthing
folder from a phone/camera rig. A worker rips the background off, runs it
through a random gmic filter/blend chain, and a handful of variants show
up on a shared web page almost immediately — no app install, no login, no
waiting for someone to "process the photos later". If a variant is fun,
remix it with different filters right there.
remix it with different filters right there. Finished jobs sync back to
the phone via the same Syncthing share.
## Audience
Event organizers and attendees at f12 events, on their phones, often on
bad venue wifi. Nobody signs up, nobody logs in. Whoever has the link
(and whoever's uploading from the SFTP side) is the whole audience.
(and whoever's syncing photos in) is the whole audience.
## Tone & Wording
@@ -41,7 +42,7 @@ bad venue wifi. Nobody signs up, nobody logs in. Whoever has the link
|---------|------|-----|
| Success | `Remix erzeugt.` | `Dein Kunstwerk ist fertig! 🎉` |
| Error | `Foreground-Filter fehlgeschlagen: Timeout nach 120s` | `Etwas ist schiefgelaufen.` |
| Empty state | `Noch keine Jobs. Bild per SFTP hochladen, dann kurz warten.` | `Hier ist noch nichts los... lade doch was hoch! 😊` |
| Empty state | `Noch keine Jobs. Bild in den Sync-Ordner legen, dann kurz warten.` | `Hier ist noch nichts los... lade doch was hoch! 😊` |
## Design
@@ -55,33 +56,32 @@ bad venue wifi. Nobody signs up, nobody logs in. Whoever has the link
- No web auth / accounts / login product — anyone with the link sees
everything, by design, for this event tool.
- No camera-to-phone client — upload path is SFTP only.
- No camera-to-phone client in this repo — upload path is Syncthing
(phone/folder setup is out of band).
- No beamer/projector product built into this repo.
- Not a DAM (digital asset manager) — no albums, tagging, search,
retention policies. `inbox/` and `jobs/` are the whole data model.
- No auto-deletion of inbox uploads. Ever. The worker only reads/copies.
retention policies. `incoming/` and `jobs/` are the whole data model.
- No auto-deletion of incoming uploads. Ever. The worker only reads/copies.
- No Syncthing container in this compose — Syncthing runs on the host.
## Infrastructure (project-local)
- Workdir on server: `/home/frank/live.f12.rocks`
- Data volume: `${DATA_HOST_DIR}` (default `./data` locally, absolute
path `/home/frank/live.f12.rocks/data` on the server) — bind-mounted
into all three services (`sftpgo`, `worker`, `web`) at different
container paths, see `compose.yml` header comment.
- SFTP: host port `12121` -> `sftpgo:2022` (spec `121212` is not a valid
TCP port). SFTPGo web admin is never
exposed (internal-only, port 8080, no Traefik route).
- Data volume (Syncthing share): `${DATA_HOST_DIR}` — prod default
`/home/frank/sync.schwenk.online/data/livef12`, local override `./data`.
Bind-mounted into `worker` and `web` at `/data` (see `compose.yml`).
- Layout under the share: `incoming/` (phone drop), `jobs/` (full tree
syncs back), `processed.json`.
- Domain: `live.f12.rocks`, routed via the shared external `traefik`
network, TLS via `myresolver` (see `INFRASTRUCTURE.md`).
- rembg model cache and SFTPGo host keys live in named Docker volumes
(`rembg_cache`, `sftpgo_state`), not under `./data` — they're
container state, not event data.
- rembg model cache lives in the named Docker volume `rembg_cache`, not
under the Syncthing share — container state, not event data.
## Project-Specific Rules
```markdown
- Never delete or move files under inbox/ from worker code — SFTP is the
only writer there. (reason: uploads are the one copy of the original
- Never delete or move files under incoming/ from worker code — Syncthing
is the writer there. (reason: uploads are the one copy of the original
that exists outside a phone's camera roll)
- Keep every intermediate image in jobs/<id>/intermediates/ — don't clean
them up automatically. (reason: useful for debugging bad filter picks,