2026-08-25 16:27:57 +02:00
|
|
|
# UmbrelApps - projectspecifieke afspraken
|
|
|
|
|
|
|
|
|
|
De algemene werkafspraken staan in `HomeGit/CLAUDE.md` en worden hier niet herhaald. Hieronder alleen wat
|
|
|
|
|
eigen is aan dit project.
|
|
|
|
|
|
|
|
|
|
**Deze repo is één community app store met twee apps erin.** umbrelOS leest per store één repo, en dat is
|
|
|
|
|
de reden dat ze samen in één repo zitten in plaats van elk in een eigen. Eerst de regels die voor allebei
|
|
|
|
|
gelden, dan per app wat alleen daar geldt.
|
|
|
|
|
|
|
|
|
|
| App | Map | Toestand |
|
|
|
|
|
|-|-|-|
|
|
|
|
|
| **Electrum Gate** | `whatsnext-electrum-gate/` | draait op de Umbrel, wordt gebruikt |
|
2026-08-25 17:18:22 +02:00
|
|
|
| **Evolu Relay** | `whatsnext-evolu-relay/` | gepakketteerd, nog nooit geïnstalleerd; zie het plan **Umbrelapp** |
|
2026-08-25 16:27:57 +02:00
|
|
|
|
|
|
|
|
**Zet geen CLAUDE.md of andere werkbestanden in een app-map.** umbreld kopieert bij installatie de héle
|
|
|
|
|
app-map naar `~/umbrel/app-data/<app-id>/` met `rsync --archive`, dus alles wat daar staat belandt op het
|
|
|
|
|
apparaat en in de back-up. Documentatie hoort in `Docs/`, tests in `tests/`, allebei in de repo-root.
|
|
|
|
|
|
|
|
|
|
## Umbrel-regels die je niet mag omzeilen
|
|
|
|
|
|
|
|
|
|
Deze gelden voor élke app hier, want het zijn eigenschappen van umbrelOS. Met bron in
|
|
|
|
|
[Docs/Referenties/Umbrel-appstore-spec.md](Docs/Referenties/Umbrel-appstore-spec.md).
|
|
|
|
|
|
|
|
|
|
**Geen accolade-variabelen in een `*.template` die er niet horen.** umbreld haalt bij elke start elk
|
|
|
|
|
`${...}` in zo'n bestand door `envsubst`, ook een variabele die niet bestaat, en die wordt dan leeg. Dat
|
|
|
|
|
sloopt Python-code, en in een nginx-config betekent het geen `$host`, geen `log_format` en geen
|
|
|
|
|
`access_log` met variabelen. Moet er tóch een dollarteken in een nginx-directive, dan hoort die directive
|
|
|
|
|
in een bestand dat het `command`-blok van de compose wegschrijft, want daar is `$$` te ontsnappen.
|
|
|
|
|
|
|
|
|
|
**Wat bij een update meekomt is een whitelist**: `docker-compose.yml`, `*.template`, `exports.sh`, `torrc`,
|
|
|
|
|
`hooks` en `umbrel-app.yml`. Al het andere bereikt een bestaande installatie nooit, zonder foutmelding.
|
|
|
|
|
Zet logica die later nog moet kunnen wijzigen dus in de compose of in een `*.template`, en nooit in een
|
|
|
|
|
los bestand of in een submap.
|
|
|
|
|
|
|
|
|
|
**Een wijziging zonder verhoging van `version` in `umbrel-app.yml` wordt niet uitgerold.** Geen melding,
|
|
|
|
|
geen fout; umbrelOS ziet hetzelfde nummer en doet niets. Dat heeft hier een keer een dag gekost. De
|
|
|
|
|
versies staan per app los van elkaar.
|
|
|
|
|
|
|
|
|
|
**Alle gebruikersstaat onder `${APP_DATA_DIR}/data/...`, en nooit erbuiten schrijven.** Elke map die bij
|
|
|
|
|
de eerste start moet bestaan, heeft een `.gitkeep` in de repo.
|
|
|
|
|
|
|
|
|
|
**Geen wachtwoord of ander geheim in de repo.** umbrelOS levert `${APP_PASSWORD}` en `${APP_SEED}` aan,
|
|
|
|
|
per installatie afgeleid. Deze repo is publiek, dus een literal is een gepubliceerd wachtwoord. Dat wordt
|
|
|
|
|
pas echt scherp bij Evolu Relay, want daar hoort een Postgres bij.
|
|
|
|
|
|
|
|
|
|
**Mapnaam gelijk aan het `id` in het manifest, en allebei met het store-id `whatsnext` ervoor.**
|
|
|
|
|
|
|
|
|
|
## Electrum Gate
|
|
|
|
|
|
|
|
|
|
### De tests draaien
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
python tests/test_agent_certificates.py
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
python tests/test_server_start_zonder_certificaat.py
|
|
|
|
|
```
|
|
|
|
|
|
2026-08-25 17:18:22 +02:00
|
|
|
Deze twee gaan over Electrum Gate en noemen die app-map bij naam. Er is een derde die over de **store**
|
|
|
|
|
gaat en zijn apps zelf vindt, dus over beide:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
python tests/test_appstore_vorm.py
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Geen testrunner en geen afhankelijkheden: het zijn losse scripts die 0 teruggeven als alles goed is. Alle
|
|
|
|
|
drie horen bij "de suite" en draaien voor een commit; de uitvoer eindigt met een regel "N goed, M fout".
|
|
|
|
|
Er is geen watch-modus; de suite kost minder dan een seconde.
|
|
|
|
|
|
|
|
|
|
`test_appstore_vorm.py` toetst **expres niet** dat images op een digest gepind zijn. Dat is wél de regel,
|
|
|
|
|
maar geen van de twee apps haalt hem vandaag, en een suite die altijd rood staat wordt niet gelezen. Hij
|
|
|
|
|
drukt de pinstatus wel af.
|
2026-08-25 16:27:57 +02:00
|
|
|
|
|
|
|
|
Twee dingen om te weten voordat je een groene uitslag vertrouwt:
|
|
|
|
|
|
|
|
|
|
- **sommige toetsen slaan zichzelf over en melden dat.** De vergelijking met `ssl` heeft de
|
|
|
|
|
certificaatwinkel van het besturingssysteem nodig, en de subjectAltName-toets heeft netwerk nodig. Staat
|
|
|
|
|
er `OVERGESLAGEN` in de uitvoer, dan is dat deel níet bewezen. Lees de uitvoer dus, tel niet alleen de
|
|
|
|
|
exitcode;
|
|
|
|
|
- **de suite dekt de agent, niet de pagina.** Alles in `index.html.template` is handwerk in een browser.
|
|
|
|
|
|
|
|
|
|
### Architectuurregels
|
|
|
|
|
|
|
|
|
|
**Geen Docker-socket.** De agent kan nginx daarom niet zelf herladen; hij zet een vlagbestand neer en de
|
|
|
|
|
nginx-container herlaadt zichzelf. Als je denkt de socket nodig te hebben, is er bijna zeker een
|
|
|
|
|
vlagbestand-oplossing.
|
|
|
|
|
|
|
|
|
|
**De pagina start altijd, ook zonder certificaat.** Het TLS-blok staat daarom niet in
|
|
|
|
|
`nginx.conf.template` maar in `stream.conf.template`, en het `command`-blok van de compose zet dat pas in
|
|
|
|
|
`/var/lib/gate/tls/` als de agent een `cert.conf` geschreven heeft; `nginx.conf` haalt die map met een
|
|
|
|
|
jokerteken op. Zet het blok niet terug in `nginx.conf`, hoe netjes dat ook staat: nginx weigert te starten
|
|
|
|
|
als een `listen ssl` geen certificaat heeft, en dan komt de pagina waarop je dat certificaat kiest ook niet
|
|
|
|
|
omhoog. Dat was de fout in 0.0.3. `tests/test_server_start_zonder_certificaat.py` houdt het dicht.
|
|
|
|
|
|
|
|
|
|
**Bij twijfel over een certificaat weigert de app.** Meerdere kandidaten zonder keuze van de gebruiker
|
|
|
|
|
levert géén automatische keuze op, ook niet "de nieuwste". Een verkeerd certificaat geeft een verbinding
|
|
|
|
|
die het lijkt te doen en pas bij de wallet stukloopt op naamverificatie, en dat is veel lastiger te vinden
|
|
|
|
|
dan een app die weigert en zegt waarom.
|
|
|
|
|
|
|
|
|
|
### Feiten
|
|
|
|
|
|
|
|
|
|
- App-id en mapnaam `whatsnext-electrum-gate`.
|
|
|
|
|
- De TLS-poort is **50022**, niet de conventionele 50002: die bezet Fulcrum op de host.
|
|
|
|
|
- De app leest de certificaatmap van Zoraxy alleen-lezen. Dat is het meest ongebruikelijke aan dit
|
|
|
|
|
pakket; zie het masterplan **Publicatie-Gate** §4.
|
|
|
|
|
|
|
|
|
|
## Evolu Relay
|
|
|
|
|
|
|
|
|
|
**De relay-code is niet van ons.** Dit pakketteert `trezor/trezor-suite-sync`; er worden geen wijzigingen
|
|
|
|
|
aan die software gedaan en er wordt niet bovenstrooms bijgedragen.
|
|
|
|
|
|
2026-08-25 17:18:22 +02:00
|
|
|
**Het bouwrecept staat in `tools/evolu-relay/`, nooit in de app-map.** Trezor publiceert geen image, dus er
|
|
|
|
|
is een bouwstap. Die hoort niet in `whatsnext-evolu-relay/`: een `Dockerfile` staat niet in de
|
|
|
|
|
update-whitelist, dus bouwen-in-de-app kost bij elke nieuwe versie een deïnstallatie plus herinstallatie.
|
|
|
|
|
Wat wij toevoegen aan hun Dockerfile is uitsluitend de **pin** op een commit; bouw hun stappen niet na.
|
|
|
|
|
|
|
|
|
|
**Verhoog je de pin in `build.sh`, dan verhoog je ook `version` in het manifest.** Anders is er een nieuwe
|
|
|
|
|
image en een oude installatie, zonder dat iets dat meldt.
|
|
|
|
|
|
|
|
|
|
**De app-proxy staat op `PROXY_AUTH_ADD: "false"` en dat is met opzet.** Trezor Suite is geen browser met
|
|
|
|
|
een sessiecookie. Zet het niet "voor de veiligheid" terug: dan krijgt Suite een inlogpagina in plaats van
|
|
|
|
|
de relay en werkt de app niet meer. De keerzijde hoort erbij en staat in de compose: wie de poort bereikt,
|
|
|
|
|
bereikt de relay. Voeg dus geen pagina toe achter diezelfde poort zonder daar apart over na te denken; zie
|
|
|
|
|
het plan **Umbrelapp**, `OPEN.md` punt 2.
|
|
|
|
|
|
|
|
|
|
**De quota-manager hoort erbij en is geen restje.** De relay weigert elke eigenaar zonder rij in de
|
|
|
|
|
limietentabel, en dit is wat die rijen maakt. Haal hem er niet uit omdat hij bij Trezor bij betaalde
|
|
|
|
|
hosting hoort.
|
|
|
|
|
|
|
|
|
|
**"Gebouwd" is hier nog verder van "werkend" dan bij Electrum Gate:** er is nog nooit iets van deze app op
|
|
|
|
|
een Umbrel gedraaid. Meld dat expliciet in plaats van het te laten meelezen als werkend.
|
2026-08-25 16:27:57 +02:00
|
|
|
|
|
|
|
|
## Repo-feiten
|
|
|
|
|
|
|
|
|
|
- Remote: `https://sc.kamenier-hamer.nl/sysop/UmbrelApps.git`, **SHA-1** en **publiek**. Alle drie zijn
|
|
|
|
|
eisen en geen voorkeuren: umbreld kloont met isomorphic-git, en die spreekt alleen smart-HTTP, kan alleen
|
|
|
|
|
SHA-1, en krijgt geen inloggegevens mee.
|
|
|
|
|
- **Store-id `whatsnext`** in `umbrel-app-store.yml`. Elk app-id moet daarmee beginnen en gelijk zijn aan
|
|
|
|
|
de mapnaam.
|
|
|
|
|
- **Aangemaakt op 25-08-2026 zonder historie**, toen Evolu Relay erbij kwam. De voorganger was de repo
|
|
|
|
|
`ElectrumTLS`; die bevatte één app en zijn naam werd onhoudbaar bij een tweede. De historie is bewust
|
|
|
|
|
niet meegenomen. Zolang die oude repo op de Git-server staat, staat het domein van de gebruiker daar nog
|
|
|
|
|
in; zie het plan **Appstore**, `OPEN.md` punt 3.
|
|
|
|
|
- **De URL is de identiteit van de store.** Verandert hij, dan is het voor umbrelOS een andere store en
|
|
|
|
|
moet de gebruiker hem opnieuw toevoegen.
|
|
|
|
|
|
|
|
|
|
## Taal
|
|
|
|
|
|
|
|
|
|
Codecommentaar en documentatie zijn Nederlands. **Zichtbare tekst is Engels**: de pagina, `umbrel-app.yml`,
|
|
|
|
|
de meldingen die de agent naar de pagina stuurt, en de root-`README.md`, want dat is wat een bezoeker van
|
|
|
|
|
een publieke app store als eerste ziet. Die grens loopt precies langs "ziet de gebruiker dit": een reden
|
|
|
|
|
uit `choose()` belandt op het dashboard en is dus Engels, een commentaarregel erboven niet.
|