From f059cb118c556d1f0279350507f74b8a47d5a98a Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Fri, 11 Sep 2026 00:19:06 +0200 Subject: docs: remove the documents MESHBAY_DESIGN.md replaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Twenty-four files, about 17 000 lines: the two architecture drafts, the three security reviews, eleven design notes, the roadmap, the decisions file, the v1–v4 archive, the deprecated user guide and the stale quickstart. Their content is in MESHBAY_DESIGN.md, and git history holds the originals. The reason to delete rather than keep bannered: a document that is superseded but present still gets read, and a reader cannot always tell which of two accounts of one mechanism is the live one. That was the argument for retiring the user guide rather than repairing it, and it applies to the whole set. What made this safe is the concordance. Roughly 290 comments and docstrings cite these files by section — `musicbay.md §6`, `mediacenter.md §5.5`, `draft-v6 §2.11` — and section 16 maps every one onto its replacement, so not a single comment needs editing to stay followable. It now says plainly that the files are gone and where to recover them, and it gained rows for the three reviews (their findings are section 13), and for the two guides. Four kept documents pointed into the set and were repointed first: `playlists.md` (nine references — it is a live proposal and must not dangle), `WINDOWS-PORT.md`, and CLAUDE.md's example. No dangling reference remains outside section 16. Two files were dropped from the list after checking what they hold. `HTTPS.md` is an operational runbook — Caddy, certificate renewal, DNS, troubleshooting — and MESHBAY_DESIGN.md deliberately covers no operations, so nothing would replace it; the versioned Caddyfile is the config, not the procedure. `cast-smart-tv.md` is the plan for the unbuilt DLNA phase of a feature whose first two phases ship, and section 11.4 summarises it in four lines rather than carrying the SSDP/UPnP work. There is no user guide now, and section 0.1 says so rather than leaving a reader to discover it. Suites green: 2258 passed, 4 skipped. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01YVoHVCcfBqud6ZjG4db3y7 --- docs/photos.md | 516 --------------------------------------------------------- 1 file changed, 516 deletions(-) delete mode 100644 docs/photos.md (limited to 'docs/photos.md') diff --git a/docs/photos.md b/docs/photos.md deleted file mode 100644 index b5612ec..0000000 --- a/docs/photos.md +++ /dev/null @@ -1,516 +0,0 @@ -# MeshBay — Photos application (design) - -> **Superseded by `MESHBAY_DESIGN.md`.** This was the Photos application design; its design -> content now lives in §9.9. -> -> It is kept because code comments, tests and other documents cite its -> sections and its labels, and because it records reasoning a synthesis -> compresses. **Where it disagrees with `MESHBAY_DESIGN.md`, the design -> document is right; where either disagrees with the code, the code is.** -> `MESHBAY_DESIGN.md` §16 maps every section reference here onto its -> replacement, and §13 defines every label. - -> Status: **built** — `photos-app.js`, `photos-app-settings.js` and -> `enrich_photo.py` all shipped; this header said "not implemented" long after -> they did. Read `docs/apps.md` first — Photos is -> a new group application built on the plug-in mechanism described there. -> Read `docs/mediacenter.md` and `docs/musicbay.md` second: Photos reuses -> their node-side pattern (thumbnails generated and cached by the node, -> delivered through the existing chunk path, `IndexEntry` gains a few more -> additive fields) wherever the same shape applies, and this document states -> only where Photos differs and why. -> -> Follows the project convention: every claim names the adversary it holds -> against (§8). - ---- - -## 0. What was asked, in one paragraph - -A group "application" with the same principles as Videos/Music — a view over -the existing file index, no catalogue, enable/disable per group on the same -signed-op mechanism — for a shared photo library: the classic photo-album -elements (album grid, next/previous within a folder, a lightbox), a small -button to download a photo folder as a zip (Files already has this), and -optional per-photo info read from the image's own EXIF data. Three things are -explicitly **not** wanted, and they are what makes Photos smaller than Videos, -not bigger: **several** root folders rather than one, a single album-grid view -rather than a mode toggle with a "flat" fallback, and no third-party service -at all. - ---- - -## 1. What this design does not reopen - -Everything Videos/Music already established stands, and this plan fits -inside it: - -- **Views over the index, never a catalogue** (`desktop-client-v1.md` §6.10, - draft-v6 §2.7). A file stays tied to its filesystem representation; an - album is a directory, exactly as a season is a folder in Videos. -- **The apps plug-in mechanism** (`apps.md`): a new `photos-app.js`, one - registry entry, one node-side `ALLOWED_APPS` entry, i18n keys, the asset - list, the two file-set tests. Enablement is a per-group, operator-signed - setting, same shape as `member_upload`/`apps_enabled`. -- **Group-related server state lives on the node** (E9). Nothing here puts a - row on the hub. -- **Node-side derived-data caching, never in a shared root** — thumbnails - live in `data_dir/media_cache.db`, the same file Videos and Music already - use, never beside the originals. -- **Filesystem portability** (§6.8) — nothing here writes into a shared root. -- **`thumb_hash`/`width`/`height` on `IndexEntry` are already generic**, not - video-specific despite their current comments (`protocol.py:166`) — Photos - populates them exactly like Videos does, no new delivery mechanism. - ---- - -## 2. Where Photos differs from Videos/Music, and why - -### 2.1 Several roots, not one - -Videos and Music each gate on a single `video_root`/`audio_root` — one -folder, because their expensive work (TMDB/MusicBrainz lookups) needed an -explicit, deliberate opt-in and a real media library is usually one tree. -A photo library is routinely scattered: a "Vacances" folder here, a -"Famille" folder there, an old "Scans" folder from a different import, -none of them nested inside a common parent that would make sense to expose -whole. **Photos takes a *set* of root folders**, each independently chosen, -each independently removable. - -- New per-group setting: `photo_roots` — a JSON list of root-relative paths, - stored the same way `enabled_apps` already is (`roster.py`, - `SETTING_ENABLED_APPS`'s own `json.dumps(sorted(...))` pattern): - - ```python - SETTING_PHOTO_ROOTS = "photo_roots" - - async def photo_roots(self, group_id: str) -> list[str]: - value = await self.get_setting(group_id, self.SETTING_PHOTO_ROOTS) - if value is None: - return [] - try: - return list(json.loads(value)) - except (ValueError, TypeError): - return [] - - async def set_photo_roots(self, group_id: str, roots: list[str], - set_by: str = "") -> list[str]: - await self.set_setting(group_id, self.SETTING_PHOTO_ROOTS, - json.dumps(sorted(roots)), set_by) - return roots - ``` - - Empty list means "nothing configured yet" — same "absent means show - nothing" discipline `underVideoRoot` already established, not "the whole - index": the node runs no thumbnail/EXIF work for a group before at least - one root exists either (§2.3's enrichment gate), so falling back to - everything would show files nothing has enriched. - -- New signed op, same shape as `apps_enabled` (a *set*, not a single value, - signed in one message rather than one op per root — adding three folders - in Settings costs one signature): - - ``` - photo_roots { roots: [...] } # client → node - photo_roots_ack { roots: [...] } # node → every connected peer - ``` - - `OP_PHOTO_ROOTS = "photo_roots"` in `adminop.py`, subject = the sorted, - comma-joined root list — identical convention to `apps_enabled`'s subject, - so the operator's browser and the node arrive at identical bytes to - sign/verify without inventing a second serialization. - -- **Validation happens before a signature is ever asked for**, same - principle as `apps_enabled`'s "empty set refused up front" and - `video_root`'s path check: every candidate path is resolved against the - group's actual `RootSet` and must name a real, currently-readable - directory, or the whole request is refused immediately — one bad path - in a batch of five never reaches the operator's browser as a signing - prompt. Unlike `apps_enabled`, an **empty** `roots` list is accepted (it - is the "nothing configured yet" state, not a lockout — there is no - Photos-equivalent of "the operator would be locked out of their own - group" to guard against here). -- Broadcast in `handshake_ack` next to `video_root`/`audio_root` - (`"photo_roots": list(self._group_ctx().get("photo_roots") or [])`), and - `photo_roots_ack` to every already-connected peer on change, same as - `video_root_ack`. -- **No root may be nested inside another already-configured root** — - same rule §6.7 of `desktop-client-v1.md` already applies to a group's - *named* roots, applied here one level down to avoid double-listing the - same directory's images once directly and once as part of a parent. - Checked case-insensitively (§6.8), at validation time, alongside the - real-directory check. - -### 2.2 UI: an add/remove list, not a single `` built from `rootFolderOptions`, one path, -confirm-on-change) does not fit a *set*. Photos gets its own small -component: the same `rootFolderOptions` `