Eén app store, twee apps

umbrelOS leest per store één repo, dus twee apps in twee repo's kan niet. Deze
repo is de store en bevat vanaf nu Electrum Gate en het werk aan Evolu Relay.
Opgezet als verse repo op verzoek van de gebruiker: de historie van ElectrumTLS
en van EvoluRelay komt niet mee.

Dat heeft één gevolg dat verder gaat dan opruimen. In de historie van
ElectrumTLS staat het domein van de gebruiker en het certificaatpad, van vóór de
opschoning van 19-08. Die komt hier niet in. Zolang die repo op de Git-server
blijft staan verandert dat niets, dus het weghalen ervan is het laatste stuk van
open punt 3 van het plan Appstore, en geen bijzaak.

De store zelf hoefde niet te veranderen: store-id whatsnext, en dus blijft het
app-id whatsnext-electrum-gate. Dat hangt aan het store-id en niet aan de URL,
dus voor umbrelOS is dit dezelfde app in een andere store. Dat de store op 19-08
naar de maker genoemd werd in plaats van naar deze ene app, betaalt zich hier
uit.

Wat de documentatie betreft is dit één wortel voor beide apps, en dat was de
reden om samen te voegen en niet de prijs ervan: de appstore-spec, het pinnen
van images en de werkwijze golden al voor allebei en stonden in twee repo's naast
elkaar. De kruisverwijzing die daarvoor nodig was (Referenties/Umbrel-appstore.md
in de oude EvoluRelay-repo) is verdwenen; wat daarin stond over de plekken waar
de relay een ander geval is, staat nu als ontwerp in het masterplan Umbrelapp §4.

Botsende namen kregen een achtervoegsel met de app, en alleen die: Publicatie
werd Publicatie-Gate en Publicatie-Relay, CHANGELOG.md werd
CHANGELOG-electrum-gate.md. Proefopstelling kreeg 007, tussen de twee bestaande
nummers, zodat de bovenkant van de reeks op tier-orde blijft staan.
CONTINUE_HERE.md heeft een kolom App, maar de tiers lopen over beide apps heen:
er is één volgorde van werken.

Electrum Gate gaat naar 0.0.15, want website, repo, support, submission en icon
wijzen nu naar UmbrelApps en zonder versieverhoging rolt dat niet uit. De release
notes leggen aan de gebruiker uit dat hij de store opnieuw moet toevoegen. Of een
geïnstalleerde app een wisseling van store-URL overleeft is nog steeds niet
uitgezocht; dat blijkt bij het omzetten.

Twee dingen in de plannen van Electrum Gate waren door deze verhuizing niet meer
waar en zijn bijgewerkt: de taak "de repo hernoemen" in fase 7 is afgevinkt, en
de repo-vorm in PLAN.md §4a toonde nog de store-id electrumtls, die al sinds
fase 7 achterhaald was.

Tests: 39 goed 0 fout en 54 goed 0 fout, niets overgeslagen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Harmen
2026-08-25 16:27:57 +02:00
co-authored by Claude Opus 5
commit 67ed9b603b
45 changed files with 8652 additions and 0 deletions
@@ -0,0 +1,213 @@
# Appstore - masterplan
> **Status: nog niet actief.** Dit is één bestand en dat is bewust: er is nog geen `TAKEN.md`,
> `PROGRESS.md` of `OPEN.md`, want er wordt nog niet aan gewerkt. Bij promotie naar
> `Plannen/Actief/NNN-Appstore/` worden de paragrafen hieronder over die vier bestanden verdeeld; zie
> `HomeGit/Docs/Werkproces.md` §1b.
>
> Afhankelijk van:
## 1. Doel
De app draait nu als een met de hand neergezette docker-compose die umbrelOS niet kent. Gevolg: na een
herstart van de Umbrel, of als een app waar deze van afhangt omvalt, moet er met de hand
`docker compose down` en `up` gedaan worden. Dit plan maakt er een echte Umbrel-app van in een eigen
community app store: een tegel met icoon, die umbrelOS zelf installeert, start en na een herstart weer
opbrengt.
Als dit af is, is de repo tegelijk de app store: de URL erin plakken in umbrelOS is genoeg om de app te
installeren, en een `git push` is genoeg om een update uit te leveren. De repo staat op de eigen
Git-server, `https://sc.kamenier-hamer.nl/sysop/ElectrumTLS.git`, en dat kan: umbreld doet geen enkele
controle op de hostnaam. Zie §4e voor wat dat wél afdwingt.
## 2. Afbakening
- De repo omzetten naar de vorm die umbrelOS voor een community app store verwacht.
- `docker-compose.yml` omzetten naar de moderne vorm: `app_proxy`, geen zelfgebouwd netwerk, geen
handmatige host-poorten waar dat niet hoeft.
- De Electrum-backend via de afhankelijkheid aanspreken in plaats van via een hardgecodeerde
containernaam, zodat Electrs, Fulcrum en ElectrumX alle drie werken.
- Een image die gepind kan worden, in plaats van `alpine:latest` met `apk add` bij elke start.
- Het manifest compleet en eerlijk maken: eigen icoon, eigen gallery, kloppende velden.
- De oude `install.sh` en `uninstall.sh` weghalen.
De volledige spec waar dit tegenaan moet, met bronvermelding per feit, staat in
[Referenties/Umbrel-appstore-spec.md](../../Referenties/Umbrel-appstore-spec.md). Die is bij het schrijven
van dit plan uitgezocht en hoeft niet opnieuw opgezocht te worden.
## 3. Niet-doelen
- **De hardgecodeerde waarden eruit halen.** Het domein `sync.kamenier-hamer.nl` en het Zoraxy-pad blijven
in dit plan staan zoals ze zijn. Dat is het plan **Configuratie**, en het apart houden is bewust: een
commit die tegelijk de structuur omgooit en de configuratie herontwerpt is niet meer na te lezen.
Wel een harde koppeling: **de repo gaat pas naar GitHub als Configuratie af is**, want anders staat een
persoonlijk domein en de indeling van een privé-server in een publieke repo. Zie open punt 3.
- **De web-UI eerlijk maken.** De pagina toont verzonnen status. Dat is het plan **Webinterface**. Hier
wordt de pagina alleen verhuisd en aan `app_proxy` gehangen, niet herschreven.
- **Meerdere apps in de store.** De store krijgt de vorm die meer apps toelaat, maar er komt er één in.
- **Indienen bij de officiële Umbrel App Store.** Een community store is er juist om dat niet te hoeven.
Als het later toch aantrekkelijk wordt, is de spec-eis grotendeels dezelfde, dus dit sluit niets af.
## 4. Ontwerp
### 4a. De repo-vorm
```
ElectrumTLS/
├── umbrel-app-store.yml id: electrumtls
├── electrumtls-electrum-tls/
│ ├── umbrel-app.yml id: electrumtls-electrum-tls
│ ├── docker-compose.yml
│ ├── entrypoint.sh
│ └── web/index.html
├── Docs/
├── README.md
└── CHANGELOG.md
```
De store-id is `electrumtls`, gekozen op 18-08-2026. De prefix-eis is hard: mapnaam en manifest-`id`
moeten gelijk zijn en allebei met de store-id beginnen.
### 4b. Backend-onafhankelijk, en waarom dat bijna niets kost
umbrelOS 1.3 heeft swappable dependencies. Fulcrum en ElectrumX declareren allebei `implements: [electrs]`
en hun `exports.sh` aliast `APP_ELECTRS_IP`, `APP_ELECTRS_NODE_IP` en `APP_ELECTRS_NODE_PORT` naar hun
eigen waarden. De gebruiker kiest de implementatie in de umbrelOS-instellingen; umbrelOS laadt de
`exports.sh` van de gekozen app.
Deze app hoeft daarvoor dus **geen keuzemechanisme te bouwen**. Het is dit:
```yaml
dependencies:
- electrs
```
en in de compose `${APP_ELECTRS_NODE_IP}:${APP_ELECTRS_NODE_PORT}` gebruiken.
Twee vallen om te vermijden. De eerste: de huidige compose zet `ELECTRS_HOST=${APP_ELECTRS_IP}`, en dat
is de **web-UI-container** van Electrs, niet de Electrum-server; dat moet `APP_ELECTRS_NODE_IP` worden.
De tweede: alleen `IP`, `NODE_IP` en `NODE_PORT` worden gealiast, dus alles wat Electrs-specifiek is
(zoals `APP_ELECTRS_RPC_HIDDEN_SERVICE`) mag hier niet gebruikt worden.
### 4c. De image: nginx `stream` in plaats van stunnel
Het huidige `alpine:latest` plus `apk add stunnel` bij elke start is op drie manieren fout: het is niet
te pinnen, het faalt zonder internet, en het maakt de starttijd afhankelijk van een Alpine-mirror. De
app-store-eis is een image gepind op de multi-arch index-digest.
Er zijn drie wegen, en de aanbeveling is de derde:
1. **Eigen image bouwen** met een `Dockerfile` en een GitHub Actions-workflow die multi-arch naar GHCR
duwt. Correct, maar het voegt CI, een registry en een tweede uitleverstroom toe aan een app die verder
uit twee shellscripts bestaat.
2. **Een bestaande stunnel-image pinnen.** Er is geen onderhouden multi-arch stunnel-image die het
vertrouwen waard is. Afgevallen.
3. **De officiële `nginx`-image gebruiken en de `stream`-module de TLS-terminatie laten doen.** Die image
is multi-arch, wordt onderhouden en is gewoon te pinnen. Dan valt er meer weg dan alleen het
bouwprobleem:
- dezelfde container serveert de web-UI én termineert TLS, dus van drie containers blijft er één over;
- een certificaatwissel wordt `nginx -s reload` **binnen** de container, dus de `cert-monitor` heeft de
Docker-socket niet meer nodig. Die socket is nu read-only gemonteerd, maar read-only op de
Docker-socket beschermt niets: wie de socket kan lezen kan containers starten en is daarmee root op
de host. Dat weghalen is de grootste beveiligingswinst in dit plan;
- een reload verbreekt bestaande verbindingen niet, een containerherstart wel.
**Te verifiëren voordat hierop gebouwd wordt:** dat de officiële `nginx:alpine` daadwerkelijk met
`--with-stream` en `--with-stream_ssl_module` gebouwd is. Dat is de aanname waar deze hele keuze op
rust en hij is in één commando te controleren (`nginx -V`). Klopt hij niet, dan valt dit terug op weg 1.
De `awk`-splitsing van de certificaat-chain uit `entrypoint.sh` blijft bruikbaar en wordt overgenomen.
### 4e. De eigen Git-server als app store
De repo komt op `https://sc.kamenier-hamer.nl/sysop/ElectrumTLS.git`. umbreld valideert de URL alleen met
de `URL`-constructor en kloont met isomorphic-git; er is geen GitHub-eis. Wat er wél uit die aanroep volgt
en wat dus getest moet worden:
- **HTTPS, niet SSH.** De URL hierboven heeft de goede vorm.
- **Anoniem kloonbaar.** umbreld geeft geen inloggegevens mee, dus de repo moet in Gitea op publiek
staan. Een privérepo werkt niet, en er is geen omweg.
- **Geldig certificaat op `sc.kamenier-hamer.nl`.** Node valideert de keten. Loopt die host al via
Zoraxy met Let's Encrypt, dan is dit in orde, maar het is het controleren waard voordat het klonen
onverklaarbaar faalt.
- **Alles op de standaardbranch.** Er wordt met `depth: 1, singleBranch: true` gekloond, dus een tag of
tweede branch levert niets op.
- **De URL is de identiteit van de store.** Wijzigt hij, dan ziet umbrelOS een andere store en moet hij
opnieuw toegevoegd worden. Kies hem dus één keer goed.
### 4d. Poorten
`port:` in het manifest is de **web-UI-poort** van de tegel, niet de TLS-poort. Dat staat nu op 50002 en
is daarmee fout.
De TLS-poort blijft een gepubliceerde host-poort; daar helpt `app_proxy` niet, want dat is voor HTTP.
Welke poort dat wordt is een open punt in **Configuratie**: Fulcrum bezet host-poort 50002 en botst dus
met de huidige keuze.
## 5. Het werk in grote lijnen
**Fase 1 - De repo-vorm.** `umbrel-app-store.yml` erbij, de app-bestanden naar
`electrumtls-electrum-tls/`, het app-id met prefix, `install.sh` en `uninstall.sh` eruit. Uitkomst: de
repo heeft de vorm die umbrelOS herkent.
**Fase 2 - De compose.** `app_proxy` erin, het externe `umbrel_main_network` en de handmatige
`APP_..._PORT`-plaatshouders eruit, de mounts op `${APP_DATA_DIR}` en `${UMBREL_ROOT}`. Uitkomst: een
compose die umbrelOS zelf kan draaien.
**Fase 3 - Backend-onafhankelijk.** `dependencies: [electrs]` en `${APP_ELECTRS_NODE_IP}` /
`${APP_ELECTRS_NODE_PORT}`. Uitkomst: de app werkt met Electrs, Fulcrum en ElectrumX zonder aanpassing.
**Fase 4 - De image.** `nginx:alpine` gepind op digest, `stream`-configuratie in plaats van stunnel,
`cert-monitor` samengevoegd en de Docker-socket eruit. Uitkomst: één gepinde container, geen `apk add`
bij start, geen socket.
**Fase 5 - Het manifest.** Eigen icoon en gallery in de repo, `port` op de web-UI-poort, `developer`,
`repo`, `support`, `submitter` en `submission` kloppend, `website` naar de eigen repo. Uitkomst: een
tegel die er klopt uitziet en niet naar andermans plaatjes wijst.
**Fase 6 - Installeren en verifiëren.** Store toevoegen in umbrelOS, installeren, en de dingen nalopen
die alleen op het apparaat te zien zijn: start hij mee na een herstart, komt hij terug als Electrs
omvalt, en werkt de TLS-verbinding vanaf een echte wallet.
## 6. Open punten
1. **Draait `nginx:alpine` met de `stream`- en `stream_ssl`-module?** De hele keuze uit §4c hangt hierop.
**Moment:** als eerste taak van fase 4, vóór er iets herschreven wordt. **Eigenaar:** uitvoerder.
2. **Wat gebeurt er met een bestaande installatie?** Er draait nu een handmatig neergezette
`electrum-tls` op de Umbrel. Die moet met de hand weg voordat de echte app geïnstalleerd wordt, anders
vecht hij om de poort. Hoort daar een korte migratie-aanwijzing bij in de README, of doet de gebruiker
dat eenmalig zelf? **Moment:** bij fase 6. **Eigenaar:** gebruiker.
3. **Wanneer wordt er voor het eerst gepusht?** **Beslist op 18-08-2026: meteen.** De repo staat sinds
die dag publiek op `https://sc.kamenier-hamer.nl/sysop/ElectrumTLS.git`, met de
installatiespecifieke waarden er nog in. Dat de repo publiek moest, stond niet ter discussie: umbreld
kloont anoniem. Alleen de volgorde was een keuze, en die is bewust vóór **Configuratie** gevallen.
Het gevolg dat vastligt: **`sync.kamenier-hamer.nl` en het certificaatpad staan nu in de publieke
historie.** Ze eruit halen in Configuratie haalt ze uit de bestanden, niet uit de historie; daarvoor
zou de historie herschreven moeten worden, en dat is bij een repo die anderen al gekloond kunnen
hebben geen schoonmaak maar een breuk. Behandel het domein dus als bekend, en laat het geen argument
worden om Configuratie uit te stellen: de winst daarvan zit nu in herbruikbaarheid, niet meer in
geheimhouding.
4. **Eigen icoon.** Het manifest wijst nu naar het Electrs-icoon in andermans repo. Er moet een eigen
SVG komen en een gallery-plaatje. Wie maakt die, en waar staan ze (in de repo of extern gehost)?
**Moment:** fase 5. **Eigenaar:** gebruiker.
## 7. Verificatie
Er zijn geen tests in dit project en die zijn hier ook niet zinvol: de app is configuratie, geen code.
Wat er wél moet, en wat per se handmatig op het apparaat gebeurt:
- de store laat zich in umbrelOS toevoegen en de app verschijnt met icoon en tegel;
- installeren via de umbrelOS-interface werkt zonder SSH;
- **na `sudo reboot` komt de app vanzelf terug.** Dit is de aanleiding voor het hele plan en dus de
belangrijkste controle;
- de app komt ook terug nadat Electrs handmatig gestopt en gestart is;
- een Electrum-wallet verbindt over TLS en verifieert het certificaat;
- omschakelen naar Fulcrum in de umbrelOS-instellingen laat de app werken zonder aanpassing.
Wat automatisch gecontroleerd kan worden, en de moeite waard is omdat het de fouten vangt die je niet
ziet: dat de YAML geldig is, dat het `id` in het manifest gelijk is aan de mapnaam, en dat elke `image:`
een `@sha256:`-digest heeft.
@@ -0,0 +1,62 @@
# Plan: Trezor Suite Sync als Umbrel App
## Status quo (onderzocht 25 aug 2026)
- Trezor's custom-sync-server heet **Evolu Relay**, onderdeel van de repo `trezor/trezor-suite-sync`.
- De repo bevat twee services: **evolu-relay** (poort 4000, de eigenlijke sync-relay) en **quota-manager** (poort 4001, betaal/quota-server) plus een **Postgres**-database.
- Er bestaat een `Dockerfile` en `docker-compose.yaml` in de repo — dus containeriseren is al gedeeltelijk gedaan door Trezor zelf.
- **Geen bestaande Umbrel-app**: niet in de officiële store (`getumbrel/umbrel-apps`), en ik heb geen relevante custom store gevonden die 'm aanbiedt.
- Conclusie: je zou de eerste zijn. Dat is haalbaar, want Umbrel-apps zijn in de kern "een `umbrel-app.yml` manifest + een `docker-compose.yml`" bovenop een al bestaande Docker-gebaseerde app.
## Doel
Een installeerbare Umbrel-app die de Evolu Relay (en evt. quota-manager) draait, zodat je in Trezor Suite bij "Custom server" een lokale/eigen URL kunt invullen die naar je Umbrel wijst.
## Belangrijke open vraag eerst
De quota-manager lijkt bedoeld voor **Trezor's eigen betaalde/quota-gebaseerde hosting** (het noemt een "Payment Server" en Notion API-spec). Voor puur privégebruik op je eigen Umbrel heb je waarschijnlijk **alleen de evolu-relay** nodig, zonder quota-manager. Dit moet je bevestigen door de `.env.sample` en broncode door te nemen — mogelijk verwacht de relay wél een werkende quota-manager-verbinding om te draaien. Zet dit als eerste stap in je proof-of-concept.
## Stap 1 — Proof of concept (lokaal, buiten Umbrel om)
1. Clone `trezor/trezor-suite-sync`.
2. Draai `docker compose up` zoals in de README, met alleen Postgres + evolu-relay (probeer quota-manager eerst weg te laten).
3. Test of Trezor Suite (desktop) succesvol labels kan syncen naar `http://<jouw-ip>:4000`.
4. Documenteer welke environment variables daadwerkelijk nodig zijn (uit `.env.sample`).
5. **Blocker-check:** als de relay hard afhankelijk blijkt van de quota-manager, moet die ook mee gepakketteerd worden.
## Stap 2 — Umbrel App Framework structuur opzetten
Volgens `getumbrel/umbrel-apps` heeft elke app een vaste structuur:
```
trezor-suite-sync/
├── umbrel-app.yml # manifest: naam, versie, poort, categorie, beschrijving
├── docker-compose.yml # services, aangepast voor Umbrel's netwerkconventies
└── exports.sh (optioneel) # env vars die andere apps kunnen gebruiken
```
Aandachtspunten bij het omzetten van Trezor's eigen `docker-compose.yaml`:
- Alle services moeten achter Umbrel's **`app_proxy`** draaien (voor routing/auth), tenzij je zelf auth afhandelt (zoals bv. Gitea/Budibase doen met `PROXY_AUTH_ADD: "false"`).
- Poorten mogen niet botsen met andere geïnstalleerde apps — kies een vast, uniek poortnummer.
- Data (Postgres-volumes) moet in Umbrel's `${APP_DATA_DIR}`-conventie staan zodat backups/updates werken.
- Vervang eventuele Kubernetes-specifieke config (`.k8s/` map) — die is niet relevant voor Umbrel, puur Docker Compose telt.
## Stap 3 — HTTPS / bereikbaarheid van buitenaf
Trezor Suite (desktop/mobiel, ook onderweg) moet de relay kunnen bereiken:
- **Alleen thuisnetwerk:** lokaal IP + poort volstaat, geen HTTPS nodig als je Suite ook alleen thuis gebruikt.
- **Ook buitenshuis:** dan heb je een manier nodig om je Umbrel veilig van buitenaf te bereiken — bijvoorbeeld via **Tailscale** (Umbrel heeft hier al een officiële app voor, zoals ook bij hun Nostr-relay-app wordt geadviseerd) of via een reverse proxy met een eigen domein + TLS-certificaat.
- Aanbevolen aanpak: begin met Tailscale, dat is de weg van de minste weerstand en vermijdt dat je zelf poorten moet open zetten op je router.
## Stap 4 — Testen
- Test op echte hardware: Raspberry Pi 5, x86-systeem, of Umbrel Home (zoals Umbrel's eigen testrichtlijnen voorschrijven).
- Test het volledige label-sync-scenario: label toevoegen op device A, checken of het verschijnt op device B na sync.
- Test update-/herstart-gedrag: overleeft de Postgres-data een app-herstart of Umbrel-OS-update?
## Stap 5 — Distributie: officieel vs. eigen store
| Optie | Voor | Nadeel |
|---|---|---|
| **PR naar `getumbrel/umbrel-apps`** | Bereikt alle Umbrel-gebruikers, officieel gereviewd | Moet aan Umbrel's kwaliteitseisen voldoen, review kan lang duren, mogelijk willen ze afstemming met Trezor zelf |
| **Eigen custom app store** (zoals `dentropy/dentropys-umbrel-appstore`) | Snel live, volledige controle | Alleen bereikbaar via handmatige CLI-toevoeging (`sudo ~/umbrel/scripts/repo add <url>`), kleiner bereik |
**Advies:** begin met een eigen custom store/repo voor je eigen gebruik en testen. Als het stabiel werkt, overweeg een PR naar de officiële store — lees eerst `AGENTS.md` in `getumbrel/umbrel-apps` voor de exacte richtlijnen.
## Risico's / dingen om in de gaten te houden
- Trezor kan de relay-architectuur wijzigen (het is een vrij nieuw, actief project — laatste release v0.1.8, april 2026).
- Quota-manager suggereert mogelijk een businessmodel rond gehoste sync; zelf-hosten omzeilt dat, maar controleer of er geen impliciete afhankelijkheden zijn (bv. licenties, rate-limits ingebakken in de relay-code).
- Data is end-to-end versleuteld volgens Trezor (client-side), dus zelf-hosten van de relay verandert niets aan de privacy-garanties — het haalt alleen Trezor's eigen server uit de vergelijking.
## Volgende concrete actie
Begin met **Stap 1**: lokaal draaien zonder Umbrel, en uitzoeken of quota-manager verplicht is. Dat bepaalt of dit een simpel 1-service-pakket wordt of een 3-service-stack (relay + quota-manager + postgres).
@@ -0,0 +1,76 @@
# Bereikbaarheid - masterplan
> **App: Evolu Relay.** Status: nog niet actief. Dit is één bestand en dat is bewust: er wordt nog niet
> aan gewerkt. Bij
> promotie naar `Plannen/Actief/NNN-Bereikbaarheid/` worden de paragrafen hieronder over de vier
> bestanden verdeeld; zie `HomeGit/Docs/Werkproces.md` §1b.
>
> Afhankelijk van: **Umbrelapp**. Er valt niets bereikbaar te maken zolang er niets draait. Eén bevinding
> uit **Proefopstelling** stuurt dit plan wel al: accepteert Trezor Suite een `http://`-adres, of eist het
> TLS?
## 1. Doel
Trezor Suite ook buiten het thuisnetwerk laten synchroniseren met de eigen relay, zonder dat daarvoor een
poort op de router open hoeft.
## 2. Afbakening
De weg van een apparaat onderweg naar de relay op de Umbrel, en wat daarvoor op de Umbrel en op het
apparaat geregeld moet worden. Inclusief de vraag wat er gebeurt als die weg wegvalt: een client die
buiten het netwerk niets kan synchroniseren, moet dat binnen het netwerk nog wel gewoon doen.
## 3. Niet-doelen
- **Geen poort openzetten op de router als het te vermijden is.** Een sync-relay die rechtstreeks aan het
internet hangt is een ander soort ding dan een relay op je eigen netwerk, en niets in dit project vraagt
erom.
- **Geen eigen certificaatbeheer bouwen.** Bestaat dat al op deze Umbrel, dan gebruiken we het. Zo niet,
dan is dat een reden om voor de weg te kiezen die geen certificaat nodig heeft.
- **Geen dienst van derden in het datapad die het verkeer termineert.** Dat is precies wat zelf hosten
moest oplossen.
## 4. Ontwerp
Twee wegen, en ze sluiten elkaar niet uit.
**Tailscale.** umbrelOS heeft er een officiële app voor, en het is de weg van de minste weerstand: geen
poort open, geen certificaat, geen domein. De prijs is een account bij een derde partij en een client op
elk apparaat dat mee wil doen. Voor het datapad is dat geen bezwaar, want het verkeer loopt versleuteld
tussen de apparaten zelf en niet via die partij, maar de coördinatie loopt er wel langs.
**Een reverse proxy met een eigen domein en TLS.** Zwaarder op te zetten, maar er is één ding dat het
makkelijker maakt dan het lijkt: op deze Umbrel draait al een reverse proxy die certificaten beheert. Dat
is dezelfde die Electrum Gate gebruikt. Het nadeel blijft dat er dan wél een poort open moet.
**Voorstel: beginnen met Tailscale**, en de reverse proxy pas overwegen als er een apparaat is dat geen
Tailscale-client kan draaien.
Wat dit plan stuurt en wat hier nu nog onbekend is: **eist Trezor Suite een `https://`-adres?** Zo ja, dan
valt de kale Tailscale-route weg of moet er alsnog een certificaat bij. Dat antwoord komt uit
**Proefopstelling**, fase 4.
## 5. Het werk in grote lijnen
**Fase 1 - de keuze onderbouwen.** Vastleggen welke apparaten mee moeten doen en of Suite TLS eist.
Uitkomst: één gekozen weg, met de reden erbij.
**Fase 2 - opzetten.** De gekozen weg inrichten op de Umbrel en op één apparaat.
**Fase 3 - verifiëren onderweg.** Synchroniseren vanaf een verbinding die niet het thuisnetwerk is, en
daarna controleren dat het thuis nog steeds werkt.
## 6. Open punten
1. **Welke apparaten moeten buitenshuis kunnen synchroniseren?** Alleen een laptop is iets anders dan een
telefoon, en het bepaalt of Tailscale volstaat.
**Moment:** fase 1 · **Eigenaar:** gebruiker
2. **Eist Trezor Suite TLS?** Zie hierboven.
**Moment:** komt uit Proefopstelling · **Eigenaar:** volgt uit dat plan
## 7. Verificatie
Synchroniseren vanaf een mobiel netwerk, dus niet vanaf de wifi thuis. Dat is de enige test die telt; een
test op het eigen netwerk met een externe naam kan slagen op een router die het verkeer naar binnen lust.
Daarna de tegenproef: werkt het thuis nog steeds, en werkt het nog als de gekozen weg wegvalt.
@@ -0,0 +1,217 @@
# Configuratie - masterplan
> **Status: nog niet actief.** Dit is één bestand en dat is bewust: er is nog geen `TAKEN.md`,
> `PROGRESS.md` of `OPEN.md`, want er wordt nog niet aan gewerkt. Bij promotie naar
> `Plannen/Actief/NNN-Configuratie/` worden de paragrafen hieronder over die vier bestanden verdeeld; zie
> `HomeGit/Docs/Werkproces.md` §1b.
>
> Afhankelijk van: het plan **Appstore**, omdat dit dezelfde bestanden herschrijft en die eerst hun
> nieuwe vorm moeten hebben.
## 1. Doel
De app is nu op één installatie toegesneden: het domein `sync.kamenier-hamer.nl`, het pad naar de
certificaten van Zoraxy en de poortnummers staan in de scripts en de compose. Daardoor kan hij niet
gedeeld worden, en, belangrijker, kan de repo niet publiek staan zonder de indeling van een privéserver
mee te publiceren. Dat laatste is geen theoretisch bezwaar: een community app store **moet** anoniem
kloonbaar zijn, anders kan umbrelOS hem niet ophalen.
Als dit af is, staat elke installatiespecifieke waarde in één configuratiebestand en bevat de repo zelf
niets persoonlijks meer.
## 2. Afbakening
- Alle vaste waarden uit de scripts, de compose en de web-UI halen: domein, certificaatpad,
certificaatbestandsnamen, TLS-poort, backend-poort.
- Eén configuratiebestand met verstandige standaardwaarden, dat bij een eerste start wordt aangemaakt als
het er nog niet is.
- De certificaatbron volledig instelbaar maken, met Zoraxy als standaard. Zo besloten op 18-08-2026.
**Uitgebreid op 19-08-2026** op verzoek van de gebruiker: er moeten drie bronnen zijn, en er moet
binnen zo'n bron een certificaat te **kiezen** zijn. Zie §4e.
- ~~Beslissen welke TLS-poort de standaard wordt, gezien de botsing met Fulcrum.~~ **Beslist op
19-08-2026: 50022.** De app draait er al op; zie open punt 1.
- Documenteren wat er ingesteld kan worden, in de README die de gebruiker op de repo-pagina ziet.
## 3. Niet-doelen
- **Een instellingenscherm in de web-UI**, met **één uitzondering: de keuze van het certificaat.**
Op 18-08-2026 was dit een heel niet-doel: instelbaar in een configuratiebestand is genoeg, en een
formulier dat configuratie wegschrijft vraagt een backend. Op 19-08-2026 heeft de gebruiker voor de
certificaatkeuze het tegendeel gekozen, en dat is te verdedigen omdat het de enige instelling is waar
de app de mogelijke waarden zélf al kent: hij kijkt in de gemounte mappen. Een keuzelijst met wat
gevonden is, is dan iets anders dan een configuratieformulier. De rest blijft in het bestand. Hoe de
keuze wordt weggeschreven staat in §4f.
- **Zelf certificaten aanvragen.** ACME, Let's Encrypt en verlenging blijven bij Zoraxy. Deze app leest
alleen. Dat is de hele reden dat hij zo klein kan blijven.
- **Meerdere domeinen of meerdere backends tegelijk.** Eén certificaat, één backend. Zolang daar geen
concrete aanleiding voor is, is dat onnodige complexiteit.
- **De poort die van buiten open staat.** Die is in de router doorgestuurd en staat daar op een ander
nummer; dat is netwerkbeheer en niet iets wat deze app kan of moet weten.
## 4. Ontwerp
### 4a. Waar de configuratie staat
In `${APP_DATA_DIR}/config/`. Dat is de map die umbrelOS aan de app toewijst, die een herinstallatie van
de app overleeft en die in de back-up meegaat. De repo bevat alleen een sjabloon; het werkelijke bestand
wordt bij de eerste start aangemaakt als het ontbreekt, en daarna nooit meer overschreven. Anders wist een
app-update de instellingen van de gebruiker, en dat is precies het soort fout dat je pas maanden later
merkt.
Vorm: een `.env`-achtig bestand met `SLEUTEL=waarde`, want dat is zonder hulpmiddelen te lezen door een
shellscript en met de hand te bewerken over SSH. YAML zou een parser vragen die er nu niet is.
### 4b. Wat er instelbaar wordt
| Sleutel | Standaard | Waarvoor |
|-|-|-|
| `TLS_DOMAIN` | leeg, dan automatisch detecteren | de naam waar het certificaat op staat |
| `CERT_DIR` | het Zoraxy-certificatenpad | de map met certificaat en sleutel |
| `CERT_FILE` | `${TLS_DOMAIN}.pem` | naam van het certificaat, voor bronnen die anders benoemen |
| `KEY_FILE` | `${TLS_DOMAIN}.key` | naam van de sleutel |
| `TLS_PORT` | open punt 1 | de poort waarop TLS binnenkomt |
| `CHECK_INTERVAL` | 300 | seconden tussen twee certificaatcontroles |
De backend komt hier bewust **niet** in te staan: die volgt uit `${APP_ELECTRS_NODE_IP}` en
`${APP_ELECTRS_NODE_PORT}`, die umbrelOS aanlevert op grond van de app die de gebruiker als
Electrum-server gekozen heeft. Zie het plan **Appstore**, en
[Referenties/Umbrel-appstore-spec.md](../../Referenties/Umbrel-appstore-spec.md) §4 voor waarom dat werkt.
### 4c. Automatisch detecteren van het domein
Staat `TLS_DOMAIN` leeg, dan zoekt de app in `CERT_DIR` naar een `.pem` met een gelijknamige `.key`
ernaast. Is er precies één paar, dan is dat het. Zijn het er meer, dan stopt de app met een leesbare
foutmelding die de gevonden namen noemt en vraagt om `TLS_DOMAIN` in te vullen.
Bewust **niet** "pak de nieuwste". Bij meer certificaten is de nieuwste een gok, en een verkeerd
certificaat kiezen levert een verbinding op die het lijkt te doen maar bij de wallet op een
naamsverificatiefout stukloopt. Dat is lastiger te vinden dan een app die netjes weigert te starten.
### 4d. Het certificaat lezen zonder een pad vast te leggen
Het Zoraxy-pad is nu twee keer als absoluut pad in de compose gemonteerd. Dat wordt
`${UMBREL_ROOT}/app-data/zoraxy/...`, wat hetzelfde oplevert maar niet aanneemt waar Umbrel staat.
Blijft over dat de mount in `docker-compose.yml` staat en de configuratie in een bestand: een gebruiker
die `CERT_DIR` naar iets buiten die mount wijst, ziet de map niet in de container. Dat moet in de README,
en de foutmelding moet het noemen. Het alternatief, de hele `${UMBREL_ROOT}/app-data` monteren, geeft de
app leestoegang tot de gegevens van elke andere app en dat weegt niet op tegen het gemak.
### 4e. Drie certificaatbronnen, met een keuze binnen de bron
Toegevoegd 19-08-2026 op verzoek van de gebruiker. De app moet kunnen terugvallen op meer dan Zoraxy:
| `CERT_SOURCE` | Waar de app kijkt | Wie beheert de vernieuwing |
|-|-|-|
| `zoraxy` (standaard) | `${UMBREL_ROOT}/app-data/zoraxy/data/config/conf/certs` | Zoraxy |
| `npm` | de certificatenmap van Nginx Proxy Manager | Nginx Proxy Manager |
| `own` | `${APP_DATA_DIR}/certs` | de gebruiker, met de hand |
| `custom` | wat er in `CERT_DIR` staat | onbekend |
Twee dingen die dit groter maken dan "nog een pad erbij", en die het ontwerp sturen:
- **Het is een keuze binnen een map, niet alleen een keuze van een map.** Zoraxy en Nginx Proxy Manager
beheren de certificaten van *alle* diensten op die machine, dus er staan er meestal meerdere. Welke van
die certificaten deze app moet gebruiken, is een aparte instelling. De detectie uit §4c is daarmee de
uitzondering en niet de regel: hij werkt alleen als er precies één paar staat, en dat is bij een
gedeelde certificatenmap juist zelden zo. Vandaar het harde weigeren bij meerdere treffers, met de
gevonden namen in de melding, want dát is de lijst waar de gebruiker uit kiest.
- **Nginx Proxy Manager benoemt anders.** Waar Zoraxy `<domein>.pem` en `<domein>.key` schrijft, zet NPM
zijn certificaten in genummerde mappen (`npm-<n>/fullchain.pem` en `privkey.pem`), dus het domein staat
níet in de naam. De detectie op naam werkt daar dus niet en de nummer-naar-domein-koppeling zit in de
database van NPM, die deze app niet mag lezen. **Voorlopige aanname, te verifiëren op de Umbrel voordat
dit gebouwd wordt.** Voor `npm` wordt de instelling daarom waarschijnlijk de map en niet het domein, en
leest de app het domein uít het certificaat in plaats van uit de bestandsnaam.
Gevolg voor de compose: elke bron die gemount moet worden, moet dat vooraf zijn, want een pad instellen
naar iets wat niet gemount is levert een map op die de container niet ziet. Drie read-only mounts dus
(Zoraxy, NPM, en de eigen map), en `custom` werkt alleen binnen een van die drie. Dat hoort in de README
en in de foutmelding, net als in §4d.
Sleutels die hierbij horen, bovenop de tabel in §4b: `CERT_SOURCE` met `zoraxy` als standaard, en
`CERT_NAME` voor de keuze binnen de bron. De twee samen vormen de id die §4f gebruikt, in de vorm
`bron/naam`.
### 4f. De keuze wegschrijven vanaf het dashboard
Besloten 19-08-2026 door de gebruiker: de keuze gaat via een keuzelijst op het dashboard en niet via het
configuratiebestand. Zie de uitzondering in §3.
De app kent de mogelijke waarden zelf, want ze staan in de gemounte mappen. De agent zet ze als
`certificates` in `status.json`, met per certificaat de bron, de bestandsnaam, het domein uit het
certificaat en de einddatum. De pagina toont die lijst met een keuzerondje en stuurt de gekozen id terug.
**Terugschrijven gaat via de agent**, een `PUT` op `api/certificate` die nginx doorstuurt. Dat is de
tweede container uit het plan **Webinterface** §4a0, waar ook staat waarom die er is.
Onderweg is dit twee keer van vorm veranderd, en de tussenstap is het opschrijven waard omdat hij eruit
zag als de goedkoopste oplossing:
- **eerst: de WebDAV-module van nginx.** Eén `location` met `dav_methods PUT` zet het bestand neer, geen
extra proces, geen taal erbij. Nadeel dat het onderuit haalde: WebDAV kan alleen een bestand neerzetten
en niets controleren. De validatie moest dan alsnog in de leeslus, en dan valideer je iets wat er al
staat in plaats van het te weigeren;
- **nu: de agent.** Die neemt de `PUT` aan, vergelijkt de id met wat hij zelf gevonden heeft, en weigert
met een leesbare fout als het niet klopt. Dat is dezelfde guard, maar op de plek waar hij hoort.
Waarom dit ook nu geen echt instellingenformulier is: de mogelijke waarden komen uit de gemounte mappen en
niet uit invoer van de gebruiker, dus er is niets vrij te typen. Het pad hangt achter de app-proxy van
umbrelOS, die er zijn eigen inlog voor zet, en de TLS-poort staat er los van. Het ergste wat een geslaagde
aanroep kan doen is een ander, ook bestaand, certificaat kiezen.
**De keuze staat in `${APP_DATA_DIR}/runtime/config/selected-cert`**, dus buiten de container, zodat hij
een herstart en een app-update overleeft. Dat is de eis uit §4a en hij geldt hier net zo goed.
## 5. Het werk in grote lijnen
**Fase 1 - Het configuratiebestand.** Sjabloon, aanmaken bij eerste start, inlezen in het startscript,
standaardwaarden. Uitkomst: de app leest zijn instellingen uit één bestand.
**Fase 2 - De waarden eruit.** Domein, paden en poorten uit `entrypoint.sh`, `cert-watch.sh`,
`docker-compose.yml` en `web/index.html` vervangen door de ingelezen waarden. Uitkomst: `grep` op
`kamenier` in de repo levert niets meer op buiten `Docs/`.
**Fase 3 - Automatisch detecteren en falen.** Detectie van het certificaatpaar, en leesbare fouten bij
nul of meer dan één treffer. Uitkomst: een verse installatie werkt zonder iets in te vullen, en een
onduidelijke situatie stopt met een bruikbare melding.
**Fase 4 - Documenteren.** De instellingen in de README, met de valkuil uit §4d. Uitkomst: iemand anders
kan de app installeren zonder de scripts te lezen.
## 6. Open punten
1. **Welke TLS-poort wordt de standaard?** - **50022** (19-08-2026, gebruiker).
50002 is de conventie voor Electrum over SSL, maar Fulcrum bezet die op de host, dus met Fulcrum erbij
zou de app niet starten, en dat is precies het omschakelen dat deze app moet ondersteunen. De poort
naar buiten is toch al een andere, want die staat in de router doorgestuurd, dus de conventie weegt
hier licht.
Al doorgevoerd in `docker-compose.yml` en `nginx.conf.template`, vooruitlopend op dit plan, omdat de
app op 19-08-2026 toch opnieuw geïnstalleerd werd. **Let op: dit vraagt eenmalig een aanpassing van de
doorstuurregel in de router**, anders komt een wallet van buiten niet meer binnen. De wallet zelf
merkt er niets van, want die gebruikt het externe poortnummer.
2. **Wat gebeurt er als het certificaat verdwijnt terwijl de app draait?** Nu wacht het startscript er bij
de start op, maar tijdens bedrijf is er geen gedrag afgesproken. Doorgaan met het oude certificaat in
het geheugen is waarschijnlijk het beste, maar het moet een besluit zijn en geen toeval. **Moment:**
bij fase 3. **Eigenaar:** uitvoerder.
3. **Blijft `Docs/` in de publieke repo staan?** De repo staat sinds 18-08-2026 publiek, mét het domein
en het certificaatpad in de historie. Daarmee is de geheimhoudingsvraag vervallen: `Docs/` alsnog uit
de repo halen verbergt niets meer.
Wat overblijft is een presentatievraag, en die is kleiner: de naslag beschrijft de indeling van één
specifieke server, wat voor een lezer van een publieke app store ruis is. Voorstel: laten staan, en de
installatiespecifieke voorbeelden in `Referenties/Architectuur-huidig.md` vervangen door de
configuratiesleutels zodra fase 2 klaar is. Dan documenteert de naslag het mechanisme in plaats van
één installatie. **Moment:** bij fase 4, samen met de README. **Eigenaar:** gebruiker.
## 7. Verificatie
- Een verse installatie zonder configuratiebestand start en detecteert het certificaat zelf.
- `TLS_DOMAIN` invullen overstemt de detectie.
- Twee certificaatparen in de map leveren een foutmelding op die beide namen noemt, en geen willekeurige
keuze.
- Een app-update overschrijft een bestaand configuratiebestand niet. Dit is de belangrijkste controle,
want dit is het soort fout dat pas bij de volgende update zichtbaar wordt.
- `grep -ri kamenier` over de repo levert buiten `Docs/` niets op.
@@ -0,0 +1,107 @@
# Publicatie-Gate - masterplan
> **App: Electrum Gate.** Er is ook een **Publicatie-Relay**; inleveren bij de officiële store is per app
> en de twee plannen delen alleen de eisen, niet het werk. Hernoemd op 25-08-2026, toen Evolu Relay bij
> deze store kwam; daarvoor heette dit plan **Publicatie**.
## 1. Waarom dit een eigen plan is
Op 20-08-2026 zei de gebruiker dat hij de app uiteindelijk als standaard-app voor Umbrel wil publiceren.
Dat verandert wat "af" betekent. Tot nu toe was de maatstaf "hij werkt op deze Umbrel", en de app haalt die
sinds diezelfde dag. De maatstaf van dit plan is een andere: **iemand anders keurt het pakket goed**, tegen
eisen die niet van ons zijn.
Daarom staat dit los van het plan **Appstore**. Dat plan gaat over de app als umbrelOS-app en over de
eigen community store, en die twee doelen zijn haalbaar zonder dat er ooit iemand meekijkt. Twee taken uit
dat plan verhuizen hier inhoudelijk naartoe (de images pinnen, de repo hernoemen); ze blijven daar staan
tot dit plan actief wordt, want een taak op twee plekken loopt uit elkaar.
## 2. Wat er af is
Niet alles hoeft nog te gebeuren. Bij het uitzoeken op 20-08-2026 bleek een deel al goed, en dat is geen
toeval: de eisen zijn dezelfde als die van de spec die dit project vanaf 18-08 als naslag bijhoudt.
- `app_proxy` met alleen omgevingsvariabelen, geen eigen poorten;
- de umbrelOS-inlog staat aan en er is geen `PROXY_AUTH_WHITELIST`, dus ook het API-pad zit erachter;
- `gallery: []`, wat voor een nieuw pakket precies goed is;
- alle gebruikersstaat onder `${APP_DATA_DIR}/data/...`, met een `.gitkeep` per map (sinds 0.0.9);
- de manifestvelden in de voorgeschreven volgorde, met een toets erop, en `icon` als laatste regel zodat
dat de enige is die bij inlevering weg hoeft (20-08-2026);
- niets wordt buiten `${APP_DATA_DIR}` geschreven;
- geen Docker-socket, geen privileged container, geen host-netwerk.
## 3. Wat er nog moet, in volgorde van moeilijkheid
1. **De images pinnen.** `python:3-alpine` en `nginx:alpine` staan kaal in de compose. Het moet
`repo:versie@sha256:<digest>` worden, met `linux/amd64` én `linux/arm64` in de manifest-lijst. Dit kan
alleen op de Umbrel en het is de grootste openstaande eis. Bijkomend voordeel dat losstaat van
publicatie: een gepinde image maakt de app reproduceerbaar, en dat was al een doel van het plan
**Appstore**, fase 4.
**Niet nu doen.** Besloten met de gebruiker op 20-08-2026: zolang er nog gedraaid, verbeterd en getest
wordt, kost een pin alleen werk. Elke keer dat je een nieuwere basisimage wilt, moet je opnieuw pinnen,
en tot de inlevering levert het niets op wat er nu ontbreekt.
De commando's staan in [Images-pinnen.md](../../Referenties/Images-pinnen.md), met de drie dingen die
erbij stil mis kunnen gaan: een tag die meebeweegt, de digest van één architectuur in plaats van die van
de index, en de aanname dat pinnen een eenmalige handeling is. Werkwijze: de gebruiker draait het
commando op de Umbrel en plakt de uitvoer, waarna de pin in `docker-compose.yml` gaat. Dat is een commit
met een versieverhoging, want de compose wordt daadwerkelijk uitgerold.
2. **Het app-id kaal maken.** `whatsnext-electrum-gate` wordt `electrum-gate`, en de mapnaam mee. Het
voorvoegsel is een eis van een community store, niet van de officiële. Let op: een id-wijziging is voor
umbrelOS een andere app, dus dat is opnieuw installeren. De gebruiker heeft daar op 20-08-2026 geen
bezwaar tegen.
3. **`icon` weghalen**, en dat kan pas op het moment van inleveren: zolang dit een eigen store is moet het
icoon er juist in. De volgorde zelf is op 20-08-2026 al goed gezet, en het icoon staat als laatste regel
zodat dit één verwijdering is. Wat er dan ook nog moet: `submission` naar de PR-URL laten wijzen.
4. **Drie tot vijf schermafbeeldingen aanleveren.** Niet zelf opmaken: het store-team maakt de
promo-afbeeldingen (achtergrond met het plaatje erop) en daarom zien ze er allemaal hetzelfde uit. Wie
het wél zelf wil, levert 1440 bij 900 in PNG. Details en de vorm voor een eigen store staan in
[Umbrel-appstore-spec.md](../../Referenties/Umbrel-appstore-spec.md).
Wat er op moet: het dashboard met echte gegevens, de certificaatkeuze open met meerdere kandidaten, en
de verbindingsregels per wallet. Dat laatste is waar iemand voor komt en het eerste is het bewijs dat het
werkt. **Met plaatsvervangende hostnamen**, want een echte schermafbeelding van deze machine zet veertien
subdomeinen van de gebruiker op een publieke winkelpagina.
5. **De repo verhuizen naar een publieke plek** met de URL-velden mee. Staat nu als taak in **Appstore**
fase 7, en is hier een voorwaarde: `repo`, `website`, `support` en `submission` moeten naar iets wijzen
dat een reviewer kan openen.
6. **De herstart-controle afronden.** Geen formele eis, maar wel de enige controle die dit project nooit
heeft kunnen doen, en het is een slecht idee om iets in te leveren waarvan je dat niet weet. Zie
**Appstore**, open punt 7.
## 3b. Bestaat dit al, en wat zeggen we in de PR
Uitgezocht op 20-08-2026, want dat is de eerste vraag die een reviewer stelt. Antwoord: **nee**, en de
onderbouwing is scherper dan "ik heb niets gevonden". De reverse proxies die al in de store staan, Nginx
Proxy Manager op kop, kunnen een certificaat wel op HTTP zetten maar niet op een gewone TCP-poort; daar
staat bij NPM een openstaand verzoek voor. Een Electrum-wallet praat geen HTTP, dus die apps lossen dit
niet op. Met bronnen in
[Vergelijkbare-apps.md](../../Referenties/Vergelijkbare-apps.md).
Die ene zin is de kern van de PR-tekst. Reken er daarnaast op dat er gevraagd wordt waarom dit geen VPN of
tunnel is. Het antwoord staat in datzelfde document en is **geen** afweging maar een verschil in soort: een
tunneldienst zit in het pad en termineert het verkeer daar, een mesh-VPN vraagt een account, een
coördinatieserver en een client op elk apparaat, en deze app vraagt geen van beide. De Engelse formulering
staat er ook, en sinds 0.0.11 in de `description` van het manifest.
## 4. Het risico dat niet in een checklist staat
De app leest de certificaatmap van een ándere app: `${UMBREL_ROOT}/app-data/zoraxy/...` staat alleen-lezen
gemount. Dat is toegestaan (de regel gaat over schrijven), maar het is het meest ongebruikelijke aan dit
pakket en het is precies het soort ding waar een review over valt.
Wat het antwoord daarop wordt, is nog niet beslist. Denkrichtingen, niet in volgorde:
- laten staan en uitleggen. Het is alleen-lezen, het is de kern van wat de app doet, en het alternatief is
dat iedere gebruiker zijn certificaat met de hand kopieert;
- het uploadpad uit 0.0.7 is er al en werkt zonder die mount. De app is dus bruikbaar zonder Zoraxy, en dat
maakt de mount een gemak in plaats van een voorwaarde;
- vragen vóór het inleveren in plaats van erna. Een issue in `umbrel-apps` kost minder dan een afgewezen PR.
## 5. Onderbouwing
De eisen staan niet in de README van `umbrel-apps` maar in de skill-documentatie waar die naar verwijst.
Met bron per regel, plus wat deze app er nu van doet, in
[Umbrel-appstore-spec.md](../../Referenties/Umbrel-appstore-spec.md).
@@ -0,0 +1,100 @@
# Publicatie-Relay - masterplan
> **App: Evolu Relay.** Er is ook een **Publicatie-Gate**; inleveren bij de officiële store is per app en
> de twee plannen delen alleen de eisen, niet het werk.
>
> Status: nog niet actief, en dit is het plan dat het langst mag wachten. Bij promotie naar
> `Plannen/Actief/NNN-Publicatie-Relay/` worden de paragrafen hieronder over de vier bestanden verdeeld;
> zie `HomeGit/Docs/Werkproces.md` §1b.
>
> Afhankelijk van: **Umbrelapp**, en van een image die te pinnen valt. Zie §4.
## 1. Doel
De app inleveren in de officiële Umbrel-appstore, zodat er niet eerst een store-URL geplakt hoeft te
worden. Dat verandert de maatstaf: niet "hij werkt hier" maar "iemand anders keurt het pakket goed",
tegen eisen die niet van ons zijn.
Het vooronderzoek noemde dit als keuze tussen een eigen store en de officiële. Die keuze is er niet echt:
je begint sowieso met een eigen store, want anders valt er niets te testen. De vraag is alleen of je
daarna inlevert.
## 2. Afbakening
Alles wat er tussen een werkend pakket in een eigen store en een aanvaarde bijdrage aan
`getumbrel/umbrel-apps` zit. Het pakket zelf is het masterplan **Umbrelapp**.
## 3. Niet-doelen
- **Geen functionaliteit erbij om de app aantrekkelijker te maken.** Wat er niet in zit omdat we het niet
nodig hebben, hoeft er niet in omdat een winkelpagina er beter van wordt.
- **Geen afstemming met Trezor**, tenzij een reviewer erom vraagt. Zie open punt 3.
## 4. Ontwerp
De eisen staan niet in de README van `umbrel-apps` maar in de skill-documentatie waar die naar verwijst.
Ze zijn uitgeschreven, met bron per regel, in
[Umbrel-appstore-spec.md](../../Referenties/Umbrel-appstore-spec.md). Wat daarvan hier het zwaarst weegt:
1. **Elke image gepind als `repo:versie@sha256:<digest>`, met `linux/amd64` én `linux/arm64`.** Dit is de
eis waar dit plan op kan stranden, en het is geen kwestie van uitvoeren: hij vraagt dat de image
überhaupt in een registry bestaat, voor beide architecturen. Publiceert Trezor er geen, dan bouw en
publiceer je zelf, en dan lever je een pakket in dat naar je eigen image wijst. Dat is een doorlopende
verplichting en een reviewer zal ernaar vragen.
2. **Een kaal app-id, dus zonder store-voorvoegsel.** Dat betekent voor de gebruiker één keer opnieuw
installeren, want voor umbrelOS is een ander id een andere app.
3. **`icon` weglaten en `gallery` leeg**, en dat kan pas op het moment van inleveren: zolang het een eigen
store is, moet het icoon er juist in. Zet `icon` daarom als laatste regel van het manifest, dan is dat
één verwijdering.
4. **Drie tot vijf schermafbeeldingen**, 1440 bij 900 in PNG, of gewone schermafbeeldingen waarna het
store-team de opmaak doet.
5. **De inlog van umbrelOS aan laten staan.** Dit is voor deze app geen formaliteit maar de kern van het
risico; zie §5.
## 5. Het risico dat niet in een checklist staat
Electrum Gate heeft er één, een leesmount in de map van een andere app. Dit pakket heeft er ook één, en
een andere: **de relay moet bereikbaar zijn voor een cliënt die geen umbrelOS-sessie heeft.** De
inlevereisen zeggen dat de inlog aan moet blijven en dat een `PROXY_AUTH_WHITELIST` alleen smal mag zijn,
en alleen voor paden die geen cookie kunnen sturen.
Of dat hier lukt, hangt volledig af van hoe de relay zelf authenticeert. Doet hij dat niet, dan lever je
een pakket in met een open eindpunt, en dan is dit geen presentatiekwestie meer maar een ontwerpkwestie.
Dat is de reden dat dit plan achter **Umbrelapp** staat en niet ernaast: het antwoord komt daarvandaan, en
zonder dat antwoord is inleveren zinloos.
Wat wél in ons voordeel werkt: deze app leest niets buiten zijn eigen map, heeft geen Docker-socket, geen
privileged container en geen afhankelijkheid van een andere app. Dat is een schoner pakket dan Electrum
Gate.
## 6. Het werk in grote lijnen
**Fase 1 - de harde eisen halen.** Images pinnen, app-id kaal maken, manifestvelden in de voorgeschreven
volgorde. Uitkomst: een pakket dat op de checklist niets meer rood heeft.
**Fase 2 - de presentatie.** Schermafbeeldingen met plaatsvervangende gegevens, en een `description` die
zegt waarom dit bestaat en niet wat het technisch is.
**Fase 3 - de vraag vóór de PR.** Het punt uit §5 voorleggen als issue in `umbrel-apps`. Een issue kost
minder dan een afgewezen PR.
**Fase 4 - inleveren en de review doorlopen.**
## 7. Open punten
1. **Willen we dit eigenlijk?** Een eigen store werkt en kost niets. Inleveren betekent een pakket
onderhouden voor onbekende gebruikers, en als de image van onszelf is, betekent het ook die
onderhouden. Dit is een echte keuze en geen vanzelfsprekend eindpunt.
**Moment:** als **Umbrelapp** af is en de app een tijd gedraaid heeft · **Eigenaar:** gebruiker
2. **Als de image zelf gebouwd moet worden, waar komt hij te staan?** En wie verhoogt hem als Trezor een
nieuwe versie uitbrengt?
**Moment:** valt samen met punt 1 · **Eigenaar:** gebruiker
3. **Afstemmen met Trezor?** Een reviewer kan vragen of Trezor hierachter staat, omdat het hun software is
en hun naam op de tegel.
**Moment:** fase 3 · **Eigenaar:** gebruiker
## 8. Verificatie
Deze is anders dan bij de andere plannen: het bewijs is de aanvaarde PR. Wat er vóór die tijd te
controleren valt, is dat elke regel van de checklist in §4 met een commando of een bestand te staven is,
en dat de app na het kaal maken van het app-id nog steeds vanaf nul installeert.
@@ -0,0 +1,145 @@
# Umbrelapp - masterplan
> **App: Evolu Relay.** Status: nog niet actief. Dit is één bestand en dat is bewust: er is nog geen
> `TAKEN.md`, `PROGRESS.md` of `OPEN.md`, want er wordt nog niet aan gewerkt. Bij promotie naar
> `Plannen/Actief/NNN-Umbrelapp/` worden de paragrafen hieronder over die vier bestanden verdeeld; zie
> `HomeGit/Docs/Werkproces.md` §1b.
>
> Afhankelijk van: **Proefopstelling**. Het aantal containers, de variabelen en de authenticatievraag
> komen daar vandaan, en zonder die antwoorden is elk manifest een gok.
## 1. Doel
Van een stack die lokaal draait naar een tweede app in deze store, die je in umbrelOS installeert en die
daarna vanzelf terugkomt. Concreet: een map `whatsnext-evolu-relay/` met een `umbrel-app.yml` en een
`docker-compose.yml`, geïnstalleerd op de Umbrel van de gebruiker, met Trezor Suite die erop
synchroniseert.
## 2. Afbakening
Het pakket en de installatie: manifest, compose, en de controles op het apparaat zelf. Ook het opruimen
van wat de eigen opzet van Trezor meebrengt en Umbrel niet wil, zoals de `.k8s/`-map en een eigen
netwerkblok.
De store zelf valt hier **buiten**: die bestaat al en serveert Electrum Gate. Wat er nog aan moet gebeuren
is één map erbij.
## 3. Niet-doelen
- **Geen bereikbaarheid van buiten het thuisnetwerk.** Masterplan **Bereikbaarheid**. Dit plan is af als
het op het eigen netwerk werkt.
- **Geen inlevering bij de officiële store.** Masterplan **Publicatie-Relay**. Dat is een andere maatstaf:
niet "hij werkt hier" maar "iemand anders keurt het goed".
- **Geen wijzigingen aan de relay zelf.** Wat Trezor levert, draaien we; wat het niet kan, kan het niet.
## 4. Ontwerp
### 4a. De vorm is bekend, de inhoud niet
De repo-vorm van een community store, de app-proxy, de whitelist bij updates en de regel dat een wijziging
zonder verhoging van `version` niet wordt uitgerold: dat staat allemaal al opgeschreven, met bron, in
[Umbrel-appstore-spec.md](../../Referenties/Umbrel-appstore-spec.md), en het hoeft niet opnieuw uitgezocht
te worden. Electrum Gate in dezelfde repo is bovendien een werkend voorbeeld van elke regel daaruit.
Wat hieronder staat is wat daar **niet** uit volgt, omdat die spec is opgeschreven vanuit een app die op
vier punten een ander geval is.
### 4b. De cliënt is geen browser, en dat raakt de app-proxy
**Dit is de ontwerpvraag die alles bepaalt**, en de reden dat dit plan wacht in plaats van alvast te
beginnen aan een manifest.
Electrum Gate heeft een dashboard dat een mens in een browser opent, en dat mag dus gewoon achter de inlog
van umbrelOS staan. Trezor Suite is geen browser met een sessiecookie. Komt de relay achter `app_proxy` met
de standaardinstelling te staan, dan krijgt Suite een inlogpagina in plaats van de relay, en dat is geen
configuratiefoutje maar het einde van het pad.
Twee bekende uitwegen, allebei met een prijs:
1. **`PROXY_AUTH_ADD: "false"`** op de proxy-service, zoals Gitea en Budibase in de officiële store doen.
Dan doet de app zijn eigen authenticatie, en de vraag wordt meteen: **dóét deze relay dat?** Zo niet,
dan zet je een open eindpunt op je Umbrel;
2. **een eigen `ports:` op de service**, zoals Electrum Gate met 50022 doet. Voor een niet-web-poort is dat
normaal en de inlevereisen noemen het ook zo. De poort moet dan wel uniek zijn op de host, en dat is
hier een echte controle: op deze machine draaien al Electrum Gate, een Electrum-server en een reverse
proxy.
Welke van de twee het wordt, hangt af van hoe Suite zich tegen de relay authenticeert. Dat antwoord komt
uit **Proefopstelling**, fase 4.
### 4c. Er is geen web-UI, en `port` is een verplicht veld
`port` in het manifest is de poort die umbrelOS voor de tegel gebruikt, dus een web-UI-poort. Deze app
heeft er geen. Wat andere apps zonder interface daarmee doen is niet uitgezocht; zie open punt 1.
### 4d. Er zit een database in de stack
Nieuw ten opzichte van Electrum Gate, dat niets bewaart.
- **De Postgres-datamap hoort onder `${APP_DATA_DIR}/data/postgres`**, niet in een naamloos Docker-volume.
Anders overleeft de data een herinstallatie niet en zit hij niet in de back-up van umbrelOS.
- **Het wachtwoord hoort niet in de repo.** umbrelOS levert `${APP_PASSWORD}` en `${APP_SEED}` aan, per
installatie afgeleid. Een literal in de compose is in een publieke repo een gepubliceerd wachtwoord.
- **`backupIgnore` verdient een overweging, en het antwoord is hier waarschijnlijk "niets".** De database
ís de waarde van deze app. Dat staat er expliciet omdat Electrum Gate het veld wél gebruikt, en
overnemen uit gewoonte zou hier precies het verkeerde weglaten.
### 4e. Geen afhankelijkheden, en niets om te vervangen
Electrum Gate declareert `dependencies: [electrs]` en leunt op het wisselmechanisme met Fulcrum en
ElectrumX. Deze app staat op zichzelf: geen `dependencies`, geen `implements`, en geen leesmount in de map
van een andere app. Dat maakt het pakket eenvoudiger en het haalt meteen het grootste review-risico weg dat
Electrum Gate wél heeft.
### 4f. De image is niet van ons, en misschien bestaat hij niet
Electrum Gate draait op `nginx:alpine` en `python:3-alpine`, twee images die gewoon in een registry staan
en die je alleen nog hoeft te pinnen. Hier is niet bekend of Trezor een image publiceert of alleen een
Dockerfile levert. Is het alleen een Dockerfile, dan bouw en publiceer je zelf, en dan ben je onderhouder
van een image geworden. **Proefopstelling** fase 1 levert het antwoord; zie
[Upstream-evolu-relay.md](../../Referenties/Upstream-evolu-relay.md) §4 punt 1.
## 5. Het werk in grote lijnen
**Fase 1 - de app-map.** `whatsnext-evolu-relay/` naast `whatsnext-electrum-gate/`, met een
`umbrel-app.yml` waarvan het `id` gelijk is aan de mapnaam. Uitkomst: umbrelOS toont een tweede tegel in
de store, ook al doet de app nog niets.
**Fase 2 - de compose.** De `docker-compose.yaml` van Trezor omzetten: `app_proxy`, geen eigen netwerkblok,
data onder `${APP_DATA_DIR}/data/`, geheimen uit umbrelOS-variabelen, en `.k8s/` blijft waar het is.
Uitkomst: een compose die op de Umbrel start.
**Fase 3 - het manifest afmaken.** Velden in de voorgeschreven volgorde, een eigen icoon, en een antwoord
op de `port`-vraag uit §4c.
**Fase 4 - installeren en verifiëren op de Umbrel.** Installeren, Suite laten synchroniseren, en daarna de
controles die je alleen op het apparaat kunt doen: overleeft de data een update, komt de app terug na een
herstart, en botst er geen poort met wat er al draait.
## 6. Open punten
1. **Wat wordt `port` in het manifest?** Dat veld is de web-UI-poort voor de tegel en deze app heeft geen
web-UI. Wat andere apps zonder interface daarmee doen is niet uitgezocht.
**Moment:** fase 3 · **Eigenaar:** uit te zoeken bij het schrijven van het manifest
2. **Komt er een statuspagina?** Electrum Gate heeft er een en die bleek in de praktijk het nuttigste deel
van de app. Hier zou dat kunnen: draait de relay, hoe groot is de database, wanneer was de laatste
synchronisatie. Het is echter een eigen container en een eigen onderhoudslast, en het is geen voorwaarde
om te kunnen synchroniseren. Voordeel dat pas sinds de samenvoeging bestaat: de pagina van Electrum Gate
staat in dezelfde repo en is grotendeels over te nemen.
**Moment:** pas overwegen als fase 4 geslaagd is · **Eigenaar:** gebruiker
3. **Blijft de quota-manager buiten het pakket?** Als **Proefopstelling** uitwijst dat het kan, dan ja.
Blijkt hij verplicht, dan verandert dit plan van vorm en hoort dit punt opnieuw beslist te worden.
**Moment:** bij promotie van dit plan · **Eigenaar:** volgt uit Proefopstelling
## 7. Verificatie
Alles behalve het laatste punt is op een laptop te controleren; het laatste punt is precies waarom dit plan
bestaat.
- YAML geldig, `id` in het manifest gelijk aan de mapnaam, elke `image:` met een `@sha256:`-digest. Dat
zijn de fouten die je anders pas op het apparaat merkt, en ze zijn automatisch te controleren;
- **op de Umbrel:** installeren, synchroniseren met Suite, en daarna een herstart van de app en van het
apparaat. Meld per controle of hij gedaan is, en meld ook expliciet welke niet;
- **en één die alleen bij een tweede app in een bestaande store bestaat:** dat het toevoegen van deze app
Electrum Gate niet raakt. Een kapot manifest in de ene map mag de andere niet meeslepen; of umbrelOS dat
netjes doet is niet uitgezocht.