aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/MESHBAY_DESIGN.md88
-rw-r--r--docs/USERGUIDE.md37
2 files changed, 124 insertions, 1 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md
index 47fe62a..06ccaca 100644
--- a/docs/MESHBAY_DESIGN.md
+++ b/docs/MESHBAY_DESIGN.md
@@ -3323,6 +3323,88 @@ are two albums.
---
+### 9.12 Photo backup (Android)
+
+The Android application sends the photos taken on the phone to **one folder of
+one group**, chosen by the member, once a day. It is a client feature over the
+upload path that exists: a backed-up photo is a `file_upload` into a writable
+root under a slot the node granted, with every rule of §6.4, and its owner is
+recorded as for any upload. **No message, no node state and no hub state was
+added for it**; the node cannot tell a backed-up photo from one sent by hand,
+and does not need to.
+
+**Split.** The phone (`photos/` in the Android package, reached as
+`platform.photoSync`) lists the photos through MediaStore, keeps the ledger and
+hands the bytes over. The page (`photo-sync.js`) decides when a run is due and
+does the sending, because the transport and the group key are there. Bytes
+cross by an opaque token the page fetches from its own origin,
+`/photosync/<token>`, served by the shell's request interception: valid for the
+run that issued it and for the one photo it names. The page never receives a
+`content://` URI. A browser and the desktop have no camera roll and no such
+object — absent, not refusing (§11.3).
+
+**When.** A run is due 24 hours after the last run that *finished*; an
+interrupted one is retried at the next chance, at most every fifteen minutes.
+Due-ness is checked at start, on return to the foreground, when the network
+turns unmetered, and by one timer at the due time — nothing polls. A scheduled
+run needs an **unmetered** network (`NET_CAPABILITY_NOT_METERED`, not "Wi-Fi":
+a phone on another phone's hotspot is on Wi-Fi and spending that phone's data).
+"Back up now" runs whenever; on a metered network it first states the count and
+size and asks — the one confirmation in this feature that is not about where
+the photos go. Turning metered mid-run stops after the file in flight; the
+node's partial upload resumes it (§8.5).
+
+**One photo at a time, under a slot.** Each upload asks for a transfer slot
+like a member sending by hand and gives it back, so a family's daily backups
+never occupy the node's upload pool ahead of a person.
+
+**Where.** The member chooses the group (one per phone) and a folder among
+those that are writable, available and shown by the group's Photos tab — a
+folder outside those would take the photos and show them nowhere. Inside it,
+each photo goes under `YYYY/MM` from when it was taken, because an album is a
+directory (§9.9) and one folder of twenty thousand is a slow album. Albums on
+the phone are chosen too; the camera alone is the default, because screenshots
+and saved images are where photos nobody meant to share live. **By default the
+photos already on the phone are sent, newest first**, then each new one; "from
+now on" is an option. A confirmation is drawn **when the destination or the
+starting point changes, never per run and never for a change of albums alone**:
+it names the group, its owner, its member count, the folder, the count and size
+about to go, and says that members can download them and that what they
+downloaded cannot be taken back.
+
+**Additive by construction.** The backup never deletes, renames or replaces
+anything on the node: `photo-sync.js` reaches no such operation
+(`test_photo_sync.py` reads it for them). **The ledger is the memory of what was
+sent, never a mirror of the phone**: per (account, group, folder), each photo's
+MediaStore id, modification date, size, the SHA-256 of the bytes sent and the
+name the node's ack gave. A run sends what the ledger lacks and never compares
+the other way, so a photo deleted on the phone stays in the group, and one
+deleted on the node is not sent again. An empty ledger (a reinstall) is
+reconciled against the folder by name and size before anything is sent.
+
+**Edits.** A photo edited in place keeps its id and changes its modification
+date; when the size also changed, or the bytes no longer hash to what was sent,
+the edit is sent **beside the original**, as `<stem>-edited-<YYYYMMDD-HHMMSS>.<ext>`
+from the edit's date. A touch that left the bytes alone sends nothing. "Save as
+copy" makes a new photo and needs no rule.
+
+**Location.** The manifest does not ask for `ACCESS_MEDIA_LOCATION`, so a
+photo read through MediaStore has its EXIF location **redacted by the
+platform**: a camera roll going to a group does not say where its owner lives,
+and nobody had to do anything for it.
+
+**Refusals.** A refusal that will hold tomorrow — `disk_full` (§6.4), a folder
+no longer writable, gone or on a drive that is not plugged, the member removed
+from the group, the photo permission withdrawn — stops the run, is said once in
+a notification and in Settings, and is retried a day later rather than at every
+opening. Anything else (the node offline, the network gone) is an interruption
+and is retried.
+
+**Screen off.** The sending lives in the page, so a run holds a `dataSync`
+foreground service (`BackupService`) and the WebView reported visible, like a
+cast (§11.3). Android 15 limits that type to six hours a day; the service stops
+when told and the run carries on at the next opening.
+
## 10. Filesystem portability
**exFAT and NTFS on Windows are the common case, not an edge case.** Most users are
@@ -3457,7 +3539,8 @@ narrow bridge — and Android has all three:
locks and the renderer's priority policy do not prevent it. A cast's pipeline
lives in the page (WebRTC → decrypt → relay), so while one runs the shell
keeps the WebView reported visible and holds a media-playback foreground
- service; nowhere else, because a page never hidden is never throttled.
+ service. A photo backup does the same with a `dataSync` service of its own
+ (§9.12); nowhere else, because a page never hidden is never throttled.
- **Notifications reach a closed application with nothing to install, and
never through a vendor push service.** Android lets nothing hold a connection
for an application that is not running, so there are three ways to wake a
@@ -4048,6 +4131,7 @@ seeking, audio-language and subtitle selection, transfer leases with queueing,
pause and resume, the group-application framework with Chat, Files, Videos,
Music and Photos, cross-group search with source merging, per-account playlists,
casting to a Chromecast with subtitles rebased onto the relay's clock, the
+phone's photo backup (§9.12), the
operator CLI and loopback control API, the desktop client through its identity
and download stages, account recovery, the Windows port through packaging, and
the Android client — the shell, native keys, downloads and uploads, casting,
@@ -4079,6 +4163,8 @@ process runs it — `systemctl --user` on Linux, Task Scheduler on Windows.
| — | **Bitmap subtitles** (PGS, VOBSUB — about a fifth of the embedded streams). No WebVTT without OCR; they are not listed rather than listed and blank. Burn-in covers them and costs `-c:v copy`, which is what the eight-slot sizing assumes never happens |
| — | Delegation (§3.4) |
| — | Tier 3 roster attestation (§3.3) |
+| — | **HEIC/HEIF in Photos.** The indexer does not classify `.heic`/`.heif` as images and no browser but Safari draws them, so a phone that shoots HEIC has its backed-up photos stored and listed in Files but absent from Photos. Needs `pillow-heif` in every package and a JPEG rendition for the viewer (§9.12) |
+| — | **Photo backup with the application closed**, and **"remove what this phone sent"** (§9.12). A closed application has no page and so no transport; it runs at the next opening |
| — | **Android: phone behaviour and release** — the back button driving the page, recovery from a network handover, keeping a download alive with the screen off, lock-screen media controls, and an update channel (§11.3) |
| — | **Federation between two hubs.** The protocol is written and switched off in the code (§7.6); what is not built is one run between two machines |
diff --git a/docs/USERGUIDE.md b/docs/USERGUIDE.md
index 7afb77b..74dae15 100644
--- a/docs/USERGUIDE.md
+++ b/docs/USERGUIDE.md
@@ -378,6 +378,37 @@ coordinates are still inside the photo itself, as your phone wrote them, so
anyone who downloads the original file has them. Strip them before sharing if
that matters to you.
+### Backing up your phone's photos
+
+On the Android application, **Settings → Photo backup** sends the photos taken
+on your phone to a folder of one of your groups, once a day.
+
+- **Set up** asks for access to your photos, then for a group, a folder and the
+ albums to send. Only folders you may add to and that the group's Photos tab
+ shows are offered. The camera is ticked; screenshots and other albums are
+ yours to add.
+- By default **the photos already on the phone are sent too**, newest first,
+ then each new one. Choose "Only photos taken from now on" to skip the ones
+ already there.
+- Before anything is sent you are told where the photos go, how many members
+ the group has and how much will be sent. **Everyone in that group will be
+ able to see and download them.** You can delete what you sent afterwards,
+ but not the copies others have already downloaded — so pick the group with
+ care. Changing the group or the folder later asks again.
+- It runs **on Wi-Fi only** (more exactly, on a connection that is not charged
+ by the amount), once a day, while the application is open — with the screen
+ off too. If the application was not opened all day, it runs the next time it
+ is. **Back up now** runs at once; on mobile data it tells you how much it is
+ about to send and asks first.
+- Photos go into folders by year and month (`2026/10`). **A photo you delete
+ from the phone stays in the group**, and one deleted from the group is not
+ sent again. A photo you edit on the phone is sent again beside the original,
+ with `-edited-` and the date in its name.
+- **Where a photo was taken is removed** from the copy that is sent.
+- If the backup cannot go on — the node's disk is full, the folder no longer
+ accepts files, you left the group — it stops, says why once in a
+ notification and in Settings, and tries again the next day.
+
### Search
The magnifying glass in the sidebar searches **across every group you are in**
@@ -1030,6 +1061,12 @@ Better to know now than to go looking for it:
with the screen off, from one track to the next, with a notification shown
while it plays. A phone browser works too.
- **A node cannot be hosted on Android**, and is not planned to be.
+- **Photo backup only runs while the application is open** (the screen may be
+ off). There is no button yet to remove everything the phone sent to a group
+ in one go — delete those files from the group instead.
+- **Photos in the HEIC format are backed up but do not show in Photos** yet:
+ they are in the folder (Files lists them) and can be downloaded. Most Android
+ phones take JPEG unless set otherwise.
- **Hubs do not talk to each other yet.** Everyone in a group needs an account
on the same hub.
- **Casting reaches Chromecast devices** from the desktop and Android