Gemeten: 709 seconden voor 318 images, terwijl de netwerktijd zo'n 48 seconden
is. Twee oorzaken.
- het aantal tegelijk gold in totaal in plaats van per registry. Registries
knijpen per host af en tweederde staat op Docker Hub, dus ghcr, lscr en quay
stonden daarachter te wachten zonder dat dat iets oploste. Nu vier per
registry, registries naast elkaar
- elke ronde controleerde alles opnieuw. Geslaagde controles blijven een week
staan, met spreiding per image zodat niet alles op dezelfde dag verloopt. De
sleutel is de naam met tag, dus een gewijzigde tag wordt altijd
gecontroleerd; mislukkingen komen nooit in de cache
Gemeten na de wijziging: koude cache 43s, warme cache 0s.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- overnemen: een compose-app die buiten Server Up om draait, met een knop
erbij trekken. Er wordt niets verplaatst of gekopieerd; de stackmap wordt een
verwijzing naar de map die de gebruiker al heeft. Kopieren zou de relatieve
paden in zijn compose-bestand breken
- kan Server Up niet bij die map (hij ziet alleen wat via BASE_DIR gekoppeld
is), dan zegt hij dat met waar de map moet staan
- verwijderen van een container die niet bij een app hoort, met in de vraag dat
alleen de container weggaat en niet zijn gegevens of image
- hoort hij bij een compose-project, dan staat erbij dat hij terugkomt zodra
dat project ergens anders start en dat overnemen waarschijnlijk is wat je
zoekt. Daarom staat overnemen links van verwijderen
- een overgenomen app verwijderen haalt alleen de verwijzing weg; rmtree zou
daar bovendien op weigeren en halverwege stranden
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
DELETE /api/repos/<id> las r["id"] zonder controle, dus een regel zonder id gaf
een 500 - dezelfde fout die GET /api/repos had. Verwijderen haalt alle regels
met die id weg, zodat een dubbele vermelding in een klik weg is.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
Met twee repo's die dezelfde id dragen tekende de store geen kaarten terwijl de
knop "Nog N tonen" een dalend getal liet zien: klikken verlaagde het getal met
zestig en er verscheen niets.
De repolijst wordt getekend met :key="repo.id". Dubbele keys zijn voor Alpine
ongedefinieerd gedrag, dus ontbrekende of verkeerde blokken, terwijl de tellers
gewoon doorrekenen over de gegevens.
GET /api/repos geeft een id nu nog maar een keer terug.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De appslijst bleef leeg na het rechtzetten van de paden, terwijl de API de apps
gewoon leverde: de pagina haalde ze nooit opnieuw op. goto() wisselt alleen van
pagina en saveSettings() verversde niets, dus je keek naar de lijst van bij het
laden van de pagina.
- bij een padwijziging worden de appslijst en de containers opnieuw opgehaald
- saveSettings() gooide het antwoord van de server weg en meldde altijd
"opgeslagen", ook als de server de opslag weigerde. Sinds v0.8.05 een pad
buiten de koppeling weigert was dat het verschil tussen aangepast en niets
gebeurd; de melding komt nu in beeld
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
Oorzaak van de lege appslijst: LIBRARY_DIR stond op /srv/serverup/stacks
terwijl alleen /opt/serverup gekoppeld is. Dat pad bestaat binnen de container
niet, dus geen apps in de lijst en alle containers onder "handmatig gestart" —
want beheerd leest dezelfde map. Nergens stond waarom.
paden.bereikbaar() bestond al sinds v0.7.92 maar hing alleen aan het veld
Hoofdmap en aan het verhuizen. De drie padvelden schrijven rechtstreeks naar
PUT /api/settings, en daar stond geen wacht.
- PUT /api/settings weigert nu een pad waar Server Up niet bij kan, met de
regel voor .env erbij. Een ongewijzigd pad blokkeert niets, anders kun je met
een kapotte instelling niets meer wijzigen
- een lege appslijst zegt nu waarom in plaats van "Geen apps gevonden"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
api_stacks sloeg elke map zonder compose-bestand over met een kale continue.
Zo'n map dook daarna nergens meer op: niet in de lijst, en de containers die
erbij horen belandden onder "handmatig gestart" omdat beheerd op datzelfde
compose-bestand afgaat.
De interface heeft er wel een weergave voor - rode stip, streepje in plaats van
een status, geen knoppen - die door dat continue nooit te zien kon zijn.
Ze staan er nu tussen met die waarschuwing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De koppeling van BASE_DIR kan intact zijn terwijl de container er toch niets
ziet. Docker bindt met propagation rprivate: een koppeling die op de host na
het aanmaken van de container ontstaat komt daar niet doorheen, en dan ziet de
container de lege map eronder.
- --doctor loopt met findmnt alle koppelingen onder BASE_DIR langs en
vergelijkt met de mountlijst van de container
- ontbreekt er een, dan staat erbij welke en hoe je hem meekoppelt
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De app store toonde geen kaarten met daaronder een knop die 106 apps beloofde.
Het raster liep over de repolijst, de tellers over de opgehaalde apps: liepen
die uit elkaar, dan stond er een getal onder een leeg scherm zonder dat er
ergens een fout te zien was.
- storeResultaat en storeVerborgen tellen nu over dezelfde lijst die ook de
kaarten oplevert
- een lege store zegt wat er aan de hand is (geen repository, of geen apps die
aan het filter voldoen) in plaats van leeg te blijven
- GET /api/repos gaf een 500 op een repo zonder id, waardoor de repolijst in de
interface leeg werd en dus de hele store; zulke regels worden overgeslagen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
"fatal: shallow file has changed since we read it" komt van twee git fetch in
dezelfde map. Bij het opstarten synchroniseert Server Up alles, en ondertussen
kan iemand op Synchroniseren drukken of een app installeren. Er zat geen slot
op, dus een synchronisatie kon over een andere heen lopen en de cache
halverwege achterlaten - waarna de repo zich niet meer liet bijwerken en de app
store leeg bleef.
- een slot per repo, zodat er nog maar een git tegelijk in een cache werkt
- lukt bijwerken niet, om welke reden dan ook, dan wordt de cache weggegooid en
opnieuw opgehaald. Er staat niets in dat bewaard hoeft te blijven, dus dat is
het juiste antwoord op elke fout hier. Dit repareert ook caches die al stuk
zijn
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De koppelingscontrole in --doctor keek of het pad in /proc/self/mountinfo
voorkwam. Een bind mount wijst echter naar een inode, niet naar een pad: is de
map op de host vervangen nadat de container was aangemaakt, dan kijkt de
container naar de oude en meestal lege map terwijl het pad nog netjes in de
mountlijst staat.
- --doctor telt nu aan beide kanten en vergelijkt
- onderscheidt "map bestaat niet in de container" van "map is leeg"
- staat er buiten wel iets en binnen niet, dan is dat een fout met de weg
terug erbij (docker compose up -d --force-recreate)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- "stack" heet in de interface voortaan "app": 24 teksten per taal plus de
terugvalteksten in de pagina. Je installeerde een app uit de App Store en
kreeg een stack; dat moest je maar net weten
- code, API-paden, mapnamen en .serverup.json houden `stack` — dat leest
niemand, en hernoemen zou opgeslagen gegevens en URL's breken
- de aparte sectie "Overige containers" is verdwenen. Handmatig gestarte
containers staan nu tussen de rest met het label "Handmatig gestart", met
starten, stoppen en logs. De zoekterm geldt voor allebei; een
categoriefilter laat ze vallen, want ze hebben geen categorie
- de waarschuwing bij backups zei nog dat appdata er niet in zit; sinds
v0.7.88 zit die er juist wel in, met een databasedump erbij
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- `git pull --rebase --autostash` stopte met "Cannot rebase onto multiple
branches" zodra branch.<tak>.merge meer dan een waarde had; daarmee werkte
geen enkele repo meer bij en bleef ook de app store leeg, want die leest uit
dezelfde cache
- tweede fout in dezelfde regel: `git pull` zonder argumenten haalt de tak op
waarop ooit gekloond is, dus de branch uit de repo-instellingen werd
genegeerd. Van main naar dev omzetten deed stilzwijgend niets
- het bijwerken haalt nu de ingestelde tak op en zet de cache daar hard op:
ongevoelig voor de upstream-instellingen, volgt een gewijzigde branch, en
laat zich niet blokkeren door lokale wijzigingen
- --doctor vraagt Server Up zelf welke LIBRARY_DIR en DATA_DIR hij gebruikt,
hoeveel stacks hij daar ziet en hoeveel apps er in de store-cache zitten.
Dat verschil tussen "wat staat er op de host" en "waar kijkt de app" was
nergens zichtbaar
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- tools/backup_rondgang.py draait backup en terugzetten tegen een echte
Docker-daemon in de CI: postgres-sidecar vullen, backuppen, alles weggooien,
terugzetten, en controleren dat de database daarna nog kan schrijven. Alle
bestaande backuptests vervangen Docker door een nep, dus die keten was nooit
bewezen
- daardoor gevonden: het terugzetten gaf de appdata de verkeerde eigenaar. Het
archief bevat de echte uid (postgres draait als 70 en zegt dat nergens in de
metadata); die gaat nu voor op PUID en op onze eigen uid
- een mislukte --update rolt terug naar de commit van ervoor en start die
opnieuw, in plaats van een stilstaande server en een rijtje commando's
- met een registry-image (SU_IMAGE) wordt er gepulld in plaats van gebouwd
- nieuw --reconfigure: bind, poort, account of hoofdmap wijzigen zonder de
broncode aan te raken
- nieuw --uninstall --purge: ook het volume, de gegevensmap en het account,
per onderdeel gevraagd. Zonder --purge somt --uninstall nu op wat blijft
- --dir wordt op een volledig pad gecontroleerd, het tijdelijke bestand voor
het beheerdersaccount is niet meer voorspelbaar, en er gaat nog een
rondgang naar de docker-daemon in plaats van twee
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
Ik sprong met tientallen (0.7.90 → 0.8.00 → … → 0.9.00 → 0.10.00) en liep
daarmee de reeks uit: dit schema rolt over bij .90, dus na 0.9.90 hoort 1.0.00
te komen. "0.10.00" bestond niet, en schond ook het formaat v0.0.00 uit de
projectafspraken.
De vijftien uitgaven van deze sessie zijn hernummerd naar 0.7.81 t/m 0.7.95,
aaneengesloten. In één doorloop met een tabel, want 0.8.81 wordt 0.7.90 en
0.7.90 wordt 0.7.81 — achtereenvolgende vervangingen zouden elkaar overschrijven.
Meegenomen: verwijzingen in de documentatie, .env.example, install.sh en de
tests. Verkorte vormen als "vanaf v0.10" zijn vervangen door het volledige
nummer, want die waren niet automatisch te herleiden.
De commit-onderwerpen in de geschiedenis dragen nog de oude nummers; VERSION en
CHANGELOG zijn leidend.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- bijwerken vanuit de interface kon nooit werken: selfupdate schreef SU_TAG naar
<werkmap>/.env, maar die map is nergens in de container gemount. De
helper-container mount hem wel en zet de tag nu
- een vastgepinde versie kon niet bijgewerkt worden: `git reset --hard
origin/<tag>` bestaat niet. Resetten gaat nu naar FETCH_HEAD, wat voor takken
en tags allebei klopt
- de token stond in .git/config en in ps; hij gaat nu via een bestand met modus
0600 dat na afloop weer weg is (git via een credential-helper, curl via
--config). Schema en host komen uit bron_url, want git zoekt op exact die
combinatie
- nieuwe optie --base-dir PAD: de hoofdmap bij de installatie zetten in plaats
van achteraf in .env, waarna je de data alsnog moet verhuizen. Relatieve
paden en systeemmappen worden geweigerd
- nieuwe actie --doctor: een installatie doorlichten zonder iets te wijzigen —
container, bereikbaarheid op het ingestelde adres, het account versus SU_UID
in .env, of BASE_DIR echt gekoppeld is, de rechten van .env en de vrije
ruimte. Exitcode 1 bij fouten
- de CI draait --doctor na elke deploy tegen de echte installatie
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De runner draait in python:3.12-slim, zonder curl. Daar faalde elke poging en
toetsten deze tests niet meer dan "curl ontbreekt". Ze krijgen nu een eigen
curl-schilletje op $PATH, zodat ze overal vastleggen wat ze horen vast te
leggen: welk adres het script opvraagt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- vragen werden bij `curl | sh` niet gesteld en zelf met "ja" beantwoord:
vraag() keek naar stdin (de pipe) in plaats van naar /dev/tty. Docker werd
daardoor van get.docker.com gehaald zonder dat het gevraagd was en
--uninstall brak af zonder bevestiging. Eén terminal_beschikbaar() voor alle
vijf de plekken
- met --bind <eigen ip> mislukten de healthcheck en het aanmaken van het
beheerdersaccount, omdat het script altijd 127.0.0.1 vroeg terwijl compose op
$BIND publiceert; het controleadres volgt nu $BIND, met blokhaken om IPv6
- een mislukte update meldde "Bijgewerkt." met exitcode 0; hij stopt nu met een
foutmelding, en een verse installatie zegt in het slot eerlijk dat er niet
geantwoord is
- curl kreeg tijdslimieten bij het pollen, zodat het aantal pogingen weer iets
betekent; SU_WACHT_POGINGEN maakt het instelbaar
- het slot noemde nog "beheert Docker als root" en toont nu het account
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
`+chown,dac_override,fowner` kwam door elke stringtest heen maar werd door
setpriv geweigerd met "bad capability string", waarna de container niet meer
opstartte. Alleen de CI-stap in een echte container zag dit.
- CAPS is nu +chown,+dac_override,+fowner
- de test laat de echte setpriv over de string oordelen in plaats van hem te
vergelijken met een verwachte tekst; met de oude waarde faalt hij
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De CI-runner draait als root, en drie tests gingen daar onderuit omdat ze
stilzwijgend van een gewone gebruiker uitgingen:
- rechten intrekken met chmod 000 houdt root niet tegen, dus er werd niets
overgeslagen; de weigering komt nu uit het inpakken zelf
- `backups.os` ís de os-module, dus het onderscheppen van chown ving ook wat
tarfile als root zelf chownt; er wordt nu op het exacte doelpad getoetst
- het geval "draait al als niet-root" liep als root juist de hele afdaal-tak in
en zou daar echt een gebruiker aanmaken; de uid wordt nu nagebootst
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- bij de installatie wordt gevraagd onder welk account Server Up draait: een
nieuw systeemaccount 'serverup', het account waarmee je werkt, een bestaand
account, of root zoals voorheen (--user NAAM slaat de vraag over)
- nieuw docker-entrypoint.sh: start als root, zet /data, stacks en backups
klaar, en zakt met setpriv af naar SU_UID:SU_GID met de capabilities die
nodig blijven (chown, dac_override, fowner - alle drie al in Docker's
standaardset)
- appdata blijft daarbij bewust ongemoeid; die mappen zijn van de apps zelf
- de gid van de docker-socket wordt uit de socket zelf gelezen, zodat het
account niet in de docker-groep hoeft (dat zou root op de host geven)
- installatieformulier vult PUID/PGID met de ids waaronder Server Up draait in
plaats van de 1000 die 44 sjablonen blind noemen
- een onleesbaar bestand laat de rest van de backup niet meer sneuvelen; wat
ontbreekt komt in het log en in de metadata (skipped)
- terugzetten herstelt het eigenaarschap van appdata, dat tarfile met
filter="data" laat vallen
- CI controleert in een echte container dat setpriv bestaat, dat er wordt
afgezakt, dat de socket-gid meekomt, dat /data schrijfbaar is en dat SU_UID=0
root laat blijven
- SU_UID=0 in .env is de ontsnappingsklep naar het oude gedrag
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
`shutil.copy2` neemt de rechten mee maar niet de eigenaar, en Server Up draait
als root. Verhuisde appdata werd daardoor root:root, waarna een container die
als PUID 1000 draait er niet meer in kon.
- elk bestand, elke map, elke symlink én de hoofdmap krijgen de uid/gid van het
origineel
- lukt chownen niet (je draait niet als root), dan gaat de verhuizing door met
een waarschuwing in plaats van te struikelen
- tests voor beide gevallen, en voor het feit dat de uid van de bron komt
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De CI draait zelf in een container, dus `bereikbaar()` viel daar al bij
`buiten_mount` uit voordat de schrijftest werd bereikt — de test slaagde alleen
op een machine zonder /.dockerenv.
- `_in_container()` afgesplitst, zodat de tests kiezen welke tak ze toetsen
- de schrijftest zet dat expliciet uit
- twee tests erbij voor de mountcontrole zelf, inclusief dat een gekoppelde
/opt/serverup de map /opt/serverup-oud niet bereikbaar maakt
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- LIBRARY_DIR, DATA_DIR en BACKUP_DIR worden afgeleid van BASE_DIR in plaats
van hard op /opt/serverup te staan
- docker-compose geeft BASE_DIR nu ook aan de container door; die stond alleen
in de mount, dus de app bleef /opt/serverup voorstellen bij een /srv-mount
- het installatieformulier vult appdata_dir met de ingestelde DATA_DIR, zodat
alle 286 sjablonen de juiste map voorstellen
- Instellingen → Paden heeft een hoofdmap met afgeleide submappen, een
kopieerknop per pad en "Alles overnemen"
- nieuw GET /api/paths/check: is het pad schrijfbaar en binnen de gemounte
BASE_DIR, met de .env-regel als dat niet zo is
- nieuw POST /api/paths/move: stacks stoppen, kopiëren, controleren, paden in
compose/.env/metadata omschrijven, stacks starten en pas dán het oude
opruimen
- jobs.voortgang() plus een voortgangsbalk boven het terminallog
- core/paden.py met meten, bereikbaarheid, verhuizen en omschrijven
- docs/installeren.md en .env.example beschrijven BASE_DIR als de manier om
alles te verplaatsen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- De poortcontrole werd aangesloten op vertaalsleutels die er al waren, en twee
daarvan verwachten een plaatshouder die ik niet meegaf: port_free wil {port},
port_in_use wil {port} en {by}
- Nieuwe test die elke t('sleutel', {...}) in de interface vergelijkt met de
plaatshouders in de Nederlandse tekst, in beide richtingen en ook voor
aanroepen zonder variabelen. Die laatste toevoeging was nodig: de eerste
versie van de test liet juist de fout passeren waar hij voor gemaakt was
- De test kent nu ook de verkorte objectnotatie van JavaScript ({name} betekent
{name: name}); zonder dat meldde hij vier bestaande aanroepen ten onrechte
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- /api/ports/check bestond al en kijkt naar wat Docker publiceert en naar wat
er rechtstreeks op de host luistert, maar het installatieformulier riep hem
nergens aan. Er stond hooguit een regeltje als de standaardwaarde bezet was;
typte je zelf iets, dan hoorde je niets
- Een poortveld heeft nu een min- en plusknop, een vergrootglas om te
controleren, en een melding: vrij, of bezet en door welke container, met een
knop om naar de eerstvolgende vrije poort te springen. De controle loopt ook
bij het openen van een stap
- Kan de host niet uitgelezen worden, dan zegt de melding dat "vrij" een
aanname is in plaats van dat te verzwijgen
- De knoppen zitten alleen op velden die ook echt een poort zijn; puid en pgid
zijn ook getallen
- De installatiemodal is op een telefoon schermvullend, met de kop en de
knoppenbalk vast en alleen de inhoud die scrollt. Vorige en Volgende vullen
samen de breedte
- Sluitknop in de kop van de modal: schermvullend betekent geen achtergrond meer
om op te tikken, en die was er nog niet
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- filteredStore() werd per repo drie keer per reactieve tick aangeroepen (in de
x-show, de x-for en de teller in het filtermenu) en liep elke keer alle apps
langs met een toLowerCase() per veld. Bij elke toetsaanslag. De catalogus ging
deze reeks van 142 naar 286 apps en dat begon te merken; het filteren gebeurt
nu een keer per filterstand
- Nog maar zestig kaarten tegelijk in de DOM, met een knop Nog N tonen eronder.
De limiet valt terug zodra je het filter of de zoekterm wijzigt
- Het zoekveld wacht 200 ms voordat het filtert
- 28 apps in de dunste hoeken: 2FAuth, Passbolt, OpenBao, Trivy, Verdaccio,
Docker Registry, MkDocs Material, LiteLLM, Flowise, Speaches, Pelican Panel,
Gameyfin, EmulatorJS, Mainsail, Fluidd, Kanboard, Wekan, Filestash,
Linkwarden, Slash, RSSHub, Apprise, Mailpit, Dashy, Plausible, NetBird,
LibreSpeed en PinePods
- Alle 318 images opnieuw tegen hun registry gecontroleerd
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- Een backup bevatte alleen de stackmap: compose, .env en metadata.
LIBRARY_DIR en de appdata-map staan naast elkaar, geen genestelde mappen, dus
je maakte een backup, kreeg een groen vinkje en hield bij terugzetten een lege
app over. Een archief heeft nu drie takken: de stackmap, de appdata van die
stack, en een dump per database
- De dump is geen dubbelop: een tar van een draaiende PostgreSQL is een
momentopname van bestanden die tijdens het inpakken veranderden. Bij
terugzetten komt de dump erin nadat de container draait, met een wachtlus.
Stond de container tijdens de backup uit, dan is dat een waarschuwing in het
log en geen stille overslag
- Nieuwe instelling BACKUP_APPDATA (standaard aan), uit te zetten bij een
mediabibliotheek waar dit in de honderden gigabytes loopt
- apps/newt en apps/pangolin. Server Up had al een Pangolin-integratie met een
publiceerknop per stack, maar je moest Pangolin zelf elders vandaan halen
- Nieuwe stap in de setup-wizard na git: koppelen aan een bestaande Pangolin,
hier installeren, of overslaan. De wizard hing zijn afhandeling aan
stapnummers, dus met een stap ertussen ging de git-stap mis; dat gaat nu op de
naam van de stap
- depends_on waarschuwt nu ook op de stackpagina. Haal je Mosquitto later weg,
dan viel Zigbee2MQTT stil zonder dat iets zei waarom
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- Het auditlog toonde ruwe id's als 'store', 'reconfigure' en
'credentials_view'. Die hebben nu namen, ook in de filterlijsten, en de
kolomkoppen zijn vertaald in plaats van hardgecodeerd Nederlands. Onbekende
waarden vallen terug op de ruwe tekst zodat een module niets kapotmaakt
- Nieuwe test die de broncode afloopt en elke audit.log() zonder vertaling
aanwijst
- Een modulepagina heette in de titelbalk letterlijk 'mod:mijnmodule'
- De store herkende een installatie aan de mapnaam: een stack telde alleen mee
als hij 'sonarr' of 'sonarr-...' heette. Wie zijn stack 'media-tv' noemde
kreeg te zien dat Sonarr niet geinstalleerd was. Nu via de source uit
.serverup.json, met een duidelijk Geinstalleerd-label per installatie waar je
op kunt klikken om ernaartoe te gaan
- Twaalf icoonknoppen per stack werden op een telefoon drie rijen plaatjes
zonder naam. Daar blijven starten, herstarten en logs staan, plus een menu met
de rest, mét namen. Op een breed scherm verandert er niets
- De rij van twintig categorieknoppen boven de stacks is hetzelfde compacte menu
geworden als in de app store
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- Twintig categorieknoppen en veertien labelknoppen stonden altijd uitgeklapt
boven de store; bij 256 apps vulde dat een half scherm. Nu een knop Filter
met een popover: categorieen in een raster van twee kolommen met kleur en
aantal, labels met een eigen zoekveld, en onderaan het aantal resultaten met
een wisknop. Sluit met Escape of door ernaast te klikken
- De labelfilter werkte maar half: de rij was afgekapt op veertien terwijl er
297 labels zijn, dus 283 daarvan waren niet te kiezen. Het menu zoekt nu in
de volledige lijst; zonder zoekterm de veertig meest gebruikte, en een gekozen
label blijft zichtbaar ook als het zeldzaam is
- Actieve filters staan als chips naast de knop, met een kruisje per stuk. Het
zoekveld heeft een wisknop
- Nieuwe test die het hele sjabloon op gebalanceerde HTML-tags controleert. Een
verkeerd geplaatste </div> schuift de rest van de pagina in een andere tak en
dat merk je anders pas in de browser
- Nieuwe JS-tests voor de filterlogica: filteren op categorie en label, de
teller, wissen, en zoeken naar een zeldzaam label
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- Nieuwe metadata-sleutel depends_on: een sjabloon kan zeggen welke andere app
het nodig heeft en waarom. Het installatiescherm toont dat voor het invullen,
met een knop naar dat sjabloon. Advies, geen blokkade -- de broker of Home
Assistant kan net zo goed op een andere machine staan
- De reden is verplicht; een waarschuwing zonder uitleg klik je weg. De korte
vorm ["mosquitto"] werkt ook, voor sjablonen uit externe repo's
- Toegepast op acht sjablonen waar het gemis onzichtbaar was: zigbee2mqtt,
alloy, alertmanager, node-exporter, cadvisor, collabora, double-take, soularr.
Niet op element, open-webui, exportarr, unpackerr en onlyoffice: die werken
met meerdere alternatieven, en depends_on kent geen "een van deze"
- Vijftien domotica-apps, van 12 naar 27 in die categorie: Piper, Whisper en
openWakeWord (spraakbediening van Home Assistant, tot nu toe volledig
afwezig), Matter Server, Matter Hub, AppDaemon, go2rtc, Double Take,
Domoticz, openHAB, DSMR-reader (P1-poort slimme meter), rtl_433 (433 MHz
sensoren naar MQTT), Traccar, Snapcast en EMQX
- Catalogus van 241 naar 256 apps; alle 285 images gecontroleerd
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- Sjablonen kunnen nu secret_format ("hex" of "laravel") en secret_bytes
opgeven. De generator maakte altijd url-veilige base64, en dat is precies wat
Laravel, Homarr en LibreChat weigeren
- Daarmee kwamen twee fouten uit v0.8.00 aan het licht: Homarr en LibreChat
kregen sleutels die hun containers niet accepteren. Rechtgezet
- Snipe-IT en Invoice Ninja alsnog toegevoegd; die vielen vorige ronde af omdat
hun APP_KEY niet te genereren was
- 19 vervangers voor big tech erbij, van 197 naar 218 apps:
Baikal en Radicale (Google Agenda/Contacten), LibreTranslate (Translate),
CryptPad, Collabora en ONLYOFFICE (Google Docs), Formbricks (Forms),
Jitsi Meet (Meet/Zoom), PeerTube, Invidious en Tube Archivist (YouTube),
Owncast (Twitch), Mastodon (X), Pixelfed (Instagram), Lemmy (Reddit),
Cal.com (Calendly), Rallly (Doodle), DocuSeal (DocuSign), Penpot (Figma)
- Communicatie van 12 naar 16 apps, productiviteit van 21 naar 31
- Nieuwe JS-test voor de sleutelformaten; alle 242 images in de catalogus
opnieuw tegen hun registry gecontroleerd
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- Catalogus van 142 naar 197 apps. Het zwaartepunt lag na het ARR-werk op media
(42 apps) terwijl communicatie er 4 had, AI 4, financien 3 en foto's 2
- Drie nieuwe categorieen: Statistiek, Zakelijk en Spellen
- Homelab-gereedschap: Dockge, Komodo, Glance, Gatus, Scrutiny, Backrest,
Headscale, Zoraxy, CrowdSec, NetAlertX, Pocket ID, Authentik
- Communicatie van 4 naar 12: Mattermost, Synapse, Element, Listmonk, Mumble,
Roundcube, Stalwart
- Notities: Outline, Trilium, SilverBullet, Readeck, Docmost, Kiwix
- Verder LibreChat, AnythingLLM, LocalAI, Ghostfolio, Wallos, Maybe, Lychee,
Piwigo, Homebox, wger, Donetick, Dawarich, Gitea, Adminer, code-server,
Woodpecker, Semaphore, Opengist, MinIO, Pingvin Share, Umami, Matomo, Odoo,
FreeScout, EspoCRM, RomM, Minecraft, Leantime, PrivateBin, Emby, ConvertX
- Drie bestaande apps waren niet installeerbaar: Forgejo wees naar een
latest-tag die dat project niet publiceert, Planka naar een tag 1 die niet
bestaat, en Baby Buddy naar een ghcr-pad dat er niet is. Gevonden door alle
213 images in de catalogus langs de registries te halen
- Twee testregels waren te krap: een config.yaml in files/ die geen compose is
telde niet mee voor "veld wordt gebruikt", en geheimen die de gebruiker zelf
aanlevert stonden in een handmatige namenlijst. Dat laatste is nu een vlag in
het sjabloon: "eigen_invoer": true
- Nieuwe controles voor de 36 apps met een eigen database: elke extra container
draagt de servicenaam als voorvoegsel, geen vaste databasewachtwoorden, en er
wacht altijd iemand met depends_on op de database
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- Elk *arr-onderdeel is nu ook een losse app in de store (46 nieuwe sjablonen);
los en gebundeld komen uit één bron (tools/arr_sjablonen.py) met een test die
bewaakt dat ze niet uiteen lopen
- Alles deelt één /data-map, zodat hardlinks werken; losse /tv-, /movies- en
/downloads-mounts zijn eruit, UMASK=002 erbij
- Nieuwe eerste stap "Onderdelen" in het invulmenu, met kopjes per soort; de
dubbele groepsschakelaar en de lege kaarten in Instellingen zijn weg
- Eigen IP-adres per container in plaats van per stack; containers zonder adres
houden hun poortmapping. Ook Pangolin publiceert nu per container
- Huntarr vervangen door NeutArr (project offline na lekken, image bestaat niet
meer), Maintainerr naar zijn nieuwe organisatie
- 31 apps toegevoegd uit het *arr-ecosysteem, alle images tegen hun registry
gecontroleerd
- data_dir hernoemd naar appdata_dir in de hele catalogus, naast de nieuwe
data_root; qBittorrent van poort 8080 naar 8097
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De knop Volgende deed niets. Alpine haalt een boolean-attribuut alleen weg bij
null, undefined of false; het getal 0 zet het juist AAN. Mijn
:disabled="stepMissing().length" gaf bij een ingevuld formulier 0 en zette de
knop dus permanent uit. De logica klopte, de binding niet — met losse logica
niet te vinden, dus er draait nu een test die de echte modal met Alpine in een
DOM rendert en erop klikt.
Tijdzones:
- Nieuwe instelling TIMEZONE, standaard die van de server (TZ, /etc/timezone,
/etc/localtime). In alle 77 sjablonen stond Europe/Amsterdam hard ingevuld.
- Apps zonder tijdzoneveld krijgen TZ er automatisch bij; die draaiden in UTC.
Poorten:
- _bezette_poorten() telt nu ook mee waar de host zelf op luistert, gelezen uit
/proc/net/tcp in een hulpcontainer met --network host. Een nginx buiten
Docker zag Server Up eerder niet.
- GET /api/ports/check geeft vrij/bezet plus een alternatief, en meldt of de
host echt gecontroleerd kon worden.
Netwerken:
- APP_NETWORKS: meerdere gedeelde bridge-netwerken in plaats van één waar élke
app aan hing. Per app kies je welke; aanmaken kan vanuit het invulmenu, met
eigen naam of een voorstel (su-<appnaam>).
- add_shared_network() accepteert een lijst; één naam blijft werken.
- GET /api/networks/<n>/ip-check controleert subnet, bereik, Docker-toewijzing
en de ARP-tabel van de host (vangt een fysiek apparaat met DHCP-adres) en
stelt een vrij adres voor.
Pangolin (nieuw, core/pangolin.py):
- Publieke URL per app via een tunnel, zonder poorten open te zetten.
- De API veranderde in 1.9 (resource hing onder een site, staat nu los); beide
routes worden geprobeerd en bij een fout krijg je beide meldingen.
- API-sleutel is write-only. Getest tegen een nagebouwde API, niet tegen een
echte server.
Nieuw: docs/pangolin.md; docs/netwerken.md uitgebreid. 2369 tests groen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
Invulmenu:
- Vaste stappen (Basis, Verbinden, Instellingen, Toegang, Controleren) in
plaats van één lange lijst. Eén stap per groep werkt niet: de mediane app
heeft één groep, arr-stack eenentwintig. Lege stappen worden overgeslagen.
- Volgende controleert de verplichte velden van die stap; die melding kwam
eerder pas bij het installeren.
- Geavanceerde opties achter één schakelaar die op elke stap zichtbaar is,
plus 'Alles op één pagina' voor het oude gedrag. Beide onthouden.
Geheimen naar .env:
- compose_transform.geheimen_naar_env() vervangt geheime waarden door
${NAAM} en schrijft ze naar .env met rechten 0600. Werkt ook midden in
een database-URL. Poorten en paden blijven leesbaar in compose.
- .serverup.json bevat geen geheimen meer en krijgt ook 0600; daar stonden
ze wereldleesbaar in. Het herconfiguratieformulier leest ze terug uit
.env via een bewaarde veld-naar-sleutel-koppeling.
- docs/beveiliging.md legt uit wat dit niet oplost: docker inspect toont de
waarde nog steeds.
Bewerken:
- Laatste stap toont het gerenderde resultaat met jouw waarden en is
bewerkbaar; compose_override/env_override gaan mee bij het installeren.
Ongeldige YAML wordt geweigerd voordat er een map bestaat.
- De bestaande editor heeft tabbladen (compose/.env) en biedt herstarten na
opslaan. De .env-PUT weigert een regel zonder '=' en logt in audit.
Inloggegevens:
- /api/stacks/<n>/credentials plus paneel op de stackkaart: adres,
gebruikersnaam, wachtwoord achter een oog-knop, kopieerknop. Alleen voor
beheerders, elk bekijken komt in het auditlog.
- Nieuw 'credential'-kenmerk in template.json met naamherkenning als
terugval, zodat de bestaande 96 sjablonen meteen werken.
Herstel van een regressie uit v0.7.60: acht inlogwachtwoorden hadden hun
genereerknop verloren toen die aan 'generate' werd gehangen. Terug, behalve
waar een verzonnen waarde fout is (WireGuard-sleutel, externe tokens).
De menulogica wordt getest door de echte component uit index.html in Node uit
te voeren; slaat zichzelf over waar node ontbreekt. 2295 tests groen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
Aanleiding: Homepage weigerde met "Host validation failed" omdat de
standaardwaarde van allowed_hosts poort 3001 noemde terwijl het poortveld op
3002 stond. Alle 96 sjablonen zijn daarop nagelopen.
Systemisch:
- De dobbelsteenknop, waar zeventien apps in hun uitleg naar verwijzen,
verscheen nooit: hij hing af van een veld 'secret' dat fields() niet
meestuurde. Wachtwoorden stonden daardoor leesbaar in het formulier.
- 27 velden die je toch nooit zelf typt (databasewachtwoorden, JWT- en
versleutelingssleutels) worden nu voorgevuld met een willekeurige waarde.
Inlogwachtwoorden krijgen alleen een knop, want die moet je noteren.
- De knop hangt nu aan 'generate' in plaats van aan 'secret': voor een
WireGuard-privésleutel of een token uit een andere app is een verzonnen
waarde juist fout.
- required werd nergens gecontroleerd. Je kon installeren met een leeg
databasewachtwoord of een lege sleutel. Nu geweigerd bij installeren en bij
herconfigureren, met vermelding van de lege velden. Velden achter een
uitgeschakelde groepsschakelaar tellen niet mee.
- Wachtwoorden werden uitgeschreven in het installatielog; nu gemaskeerd.
Losse fouten:
- homepage: allowed_hosts stond op localhost:3001, nu * met uitleg.
- baserow, hedgedoc, ntfy: URL in de standaardwaarde wees naar een poort waar
niets luistert.
- Vast wachtwoord in acht sjablonen weggehaald: ghost, immich, miniflux,
paperless-ngx, unifi-network en vikunja kregen allemaal dezelfde
database-wachtwoorden; grafana en gotify stonden op 'admin'.
- data_dir bij keycloak, metube, miniflux en teslamate stond in het formulier
maar kwam nergens terecht (die apps gebruiken een Docker-volume).
- puid/pgid bij freshrss: het image kent ze niet.
- prometheus gaf de gevraagde tijdzone niet door.
Nieuw tests/test_app_templates.py: rendert elke app met zijn standaardwaarden
en controleert ongedefinieerde variabelen, velden zonder werking,
niet-gedeclareerde volumes, depends_on, dubbele containernamen,
poortconflicten, poortnummers in standaardwaarden en vaste wachtwoorden.
2236 tests groen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
Het onbewaakte deel was de zwakke plek: geplande taken draaiden 's nachts en
een storing kwam alleen in het auditlog terecht.
Meldingen (core/notify.py):
- ntfy, webhook (Discord/Slack/Gotify) en e-mail, alle drie met de
standaardbibliotheek.
- Gebeurtenissen: mislukte backup, onleesbaar archief, vastgelopen taak,
weinig schijfruimte, beschikbare update, gestopte container.
- Eén bericht per ronde; bij schijfruimte en gestopte containers alleen bij
de overgang, zodat je niet elk uur hetzelfde krijgt.
- Testknop die eerst opslaat, zodat je test wat je net hebt ingevuld.
- send() gooit nooit: het kanaal mag de taak die de melding veroorzaakte niet
alsnog laten omvallen.
Schijfruimte (core/diskspace.py):
- Controle vóór elke backup; past het niet, dan weigeren in plaats van
halverwege afbreken.
- DISK_MIN_FREE_GB blijft gereserveerd, DISK_WARN_PCT kleurt de balk rood.
- Per filesystem één regel in de backuplijst.
Backups controleren:
- Elk nieuw archief wordt helemaal uitgelezen (tar-structuur plus
gzip-checksum, die aan het eind staat).
- Diepe variant pakt echt uit naar een tijdelijke map, met dezelfde
beperkingen als een echt herstel.
- Resultaat staat in de metadata en als schildje in de lijst.
Backups de deur uit:
- Downloadknop.
- BACKUP_OFFSITE_DIR kopieert elke nieuwe backup naar een gemounte schijf,
NFS- of SMB-share, via .part zodat een afgebroken kopie herkenbaar onaf is.
- Ruimtecontrole op de bestemming, want een weggevallen mount laat vaak een
lege map op de systeemschijf achter.
NOTIFY_TOKEN en NOTIFY_EMAIL_PASSWORD zijn write-only.
Nieuw: docs/meldingen.md; docs/backups.md uitgebreid. Getest tegen een
draaiende server met een echte ontvanger. 1064 tests groen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
Het installatiescript kan nu allebei zelf regelen, zodat je na afloop niet
meer naar de webinterface hoeft om een account te claimen en niet meer in
.env hoeft te duiken om erbij te kunnen.
Beheerdersaccount:
- Op een terminal wordt gevraagd of je er meteen een wil, met naam en
wachtwoord (twee keer, echo uit).
- Automatisch via --admin NAAM plus --admin-password-file of
SU_ADMIN_PASSWORD; zonder bron en zonder terminal maakt het script er
zelf een van 24 tekens en toont die.
- --admin-password weigert bewust: argumenten zijn zichtbaar in 'ps'. Het
wachtwoord gaat via stdin naar curl, niet als argument.
- Nieuw --create-admin voor een installatie die al draait.
Bereikbaarheid:
- Keuzemenu voor BIND (deze server / hele netwerk / eigen adres), met het
gedetecteerde serveradres erbij.
- Bij opnieuw installeren is de bestaande instelling het uitgangspunt, zodat
enter je server niet ongemerkt terugzet op loopback.
Opgeloste fouten:
- Een bestaande .env bleef altijd ongemoeid, ook met --bind: de installatie
leek te lukken terwijl de server op het oude adres bleef luisteren.
- --update rekende met de standaardpoort in plaats van met wat er in .env
staat, waardoor de wachtlus en het slotadres niet klopten.
- --dry-run riep 'sudo docker' aan en vroeg dus om een wachtwoord terwijl
het net beloofd had niets te doen; zonder terminal liep het daarop vast.
- Ongeldig bind-adres en poort buiten 1-65535 worden nu meteen geweigerd.
Getest met een pseudo-terminal voor de vragen en tegen een echt draaiende
server voor het aanmaken van het account, inclusief een wachtwoord vol
aanhalingstekens en backslashes, een geweigerd tweede account en een server
die niet reageert. De e2e-tests slaan zichzelf over waar curl ontbreekt,
zoals in het CI-image. 992 tests groen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
De teststap draait in python:3.12-slim, waar curl ontbreekt. Het
installatiescript brak daar af op de vereistencontrole, waardoor
test_dry_run_wijzigt_niets en test_dry_run_toont_de_hele_gang_van_zaken
faalden op de runner (runs 74 en 75).
Ontbrekende curl/tar is nu een waarschuwing bij --dry-run in plaats van
een harde fout, net als bij Docker: een proefdraai hoort juist te tonen
wat er zou gebeuren op een machine waar nog niets staat.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
curl -fsSL https://git.ramonbesselink.nl/bes-r/server-up/raw/branch/main/install.sh | sh
install.sh controleert het systeem, biedt aan Docker te installeren als dat
ontbreekt, kloont de repo (of pakt het tar-archief uit als git ontbreekt), maakt
.env aan, bouwt en start, wacht op /healthz en toont waar je terecht kunt met de
waarschuwing meteen een account aan te maken.
- Opties: --dir, --port, --bind, --branch, --token, --update, --uninstall,
--yes, --dry-run.
- --update haalt nieuwe code op en herstart; .env, stacks en gegevens blijven.
- --uninstall stopt de container maar laat gegevens staan, en vertelt hoe je
die alsnog opruimt.
- Gebruikt alleen sudo waar nodig: kun je zelf in de doelmap schrijven en
docker aanroepen, dan blijft alles onder je eigen account.
Tijdens het testen gevonden en verholpen:
- `docker compose --project-directory` zoekt zonder -f het compose-bestand in de
huidige map; bij `curl | sh` is dat je thuismap. Nu altijd -f erbij.
- De wachtlus gaf anderhalve minuut geen teken van leven; nu een punt per
poging en 90 in plaats van 120 seconden.
- Bij --dry-run braken ontbrekende Docker-onderdelen de voorvertoning af; nu
waarschuwingen zodat je de hele gang van zaken ziet.
- De versie-uitlezing uit /healthz tolereert nu ook json met spaties.
Documentatie: docs/installeren.md met alle opties, bijwerken, verwijderen en een
probleemoplostabel; README verwijst ernaar.
Tests: syntaxis onder sh/dash/bash, geen bashismen, --help noemt alle opties,
ongeldige invoer stopt, een proefdraai maakt niets aan, en de installatieregel
in README en docs is identiek.
958 tests groen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
Defect (v0.7.00): add_shared_network() hing elke service aan het gedeelde
netwerk, ook services met network_mode. Docker compose weigert die combinatie
("declares mutually exclusive network_mode and networks"), waardoor Homebridge,
Scrypted, Beszel en de ARR-stack met Gluetun niet te installeren waren met de
standaardkeuze "Verbinden met andere apps". Die services worden nu overgeslagen;
blijft er niets over, dan ook geen netwerkblok. Test over alle 96 apps.
Instellingen wijzigen na installatie:
- De gemaakte keuzes worden bij installatie opgeslagen in .serverup.json
(values + format); zonder die waarden viel het formulier niet te heropenen.
- GET /api/stacks/<naam>/config geeft de opgeslagen waarden plus het actuele
veldschema; POST /reconfigure maakt een backup, rendert opnieuw, past netwerk
en eigen IP opnieuw toe, valideert en herstart. Mislukt het valideren, dan
wordt de backup teruggezet.
- Knop Instellingen op de stackkaart opent dezelfde modal in wijzigen-stand,
met een waarschuwing dat handmatige compose-wijzigingen verloren gaan.
- Stacks van voor deze versie: knop uit met uitleg.
Bestaande stacks koppelen:
- POST /api/stacks/<naam>/connect zet een bestaande stack op het gedeelde
netwerk, valideert en herstart; wordt de compose ongeldig, dan wordt de
wijziging teruggedraaid.
Audit-log:
- audit.query()/count() accepteren filters op bron, actie, status, periode en
vrije tekst; facets() levert de keuzelijsten. /api/audit ondersteunt die als
queryparameters plus doorbladeren. Filterbalk in de UI.
Documentatie:
- README.md (bestond niet), docs/apps-maken.md met het volledige
templateformaat, docs/README.md als index.
- Changelog-secties voor v0.5.44/45/46 aangevuld; release.yml haalt de notes
daaruit, dus een tag daarop gaf een lege release. Test die afdwingt dat het
huidige VERSION een sectie heeft.
941 tests groen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
- Nieuw core/categories.py: zeventien categorieen, elk met naam (nl/en), kleur
en pictogram. Kleuren zijn middentonen die in licht en donker leesbaar zijn;
de interface gebruikt ze als tekstkleur op een doorzichtige variant.
- Alle 96 apps ingedeeld via metadata.categories. Een app mag in meerdere
categorieen zitten; 39 apps doen dat (Frigate onder domotica en media,
Immich onder fotos en opslag, Kavita onder media en documenten).
- Apps uit externe repos geven geen categorieen op; die worden afgeleid uit
tags en omschrijving, zodat ook zij een kleur en een plek in het filter
krijgen.
- App store: gekleurde categoriebalk met aantallen, klikbare badges per app,
werkt naast het bestaande zoekveld en de tagfilters.
- Stackslijst: dezelfde balk met alleen de categorieen die je draait, gekleurde
rand per kaart en klikbare badges.
- Nieuw /api/categories geeft de definities met kleur, zodat interface en
backend dezelfde kleur voor dezelfde categorie gebruiken. /api/stacks geeft
de categorieen mee; een stack van voor deze versie valt terug op "overig"
in plaats van kleurloos te blijven.
- Tests: elke app heeft geldige categorieen, kleuren zijn uniek, en er staat
geen categorie in het filter zonder apps.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb