• v2026.8.7 397a615d56

    v2026.8.7
    All checks were successful
    CI / release-scripts (pull_request) Successful in 6s
    security-scan / SBOM (trivy) (pull_request) Successful in 9s
    security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 15s
    security-scan / JS SCA (npm audit) (pull_request) Successful in 16s
    security-scan / Python SAST (bandit) (pull_request) Successful in 21s
    CI / pre-commit (pull_request) Successful in 28s
    security-scan / Python SCA (pip-audit) (pull_request) Successful in 37s
    test-build / build (frontend) (pull_request) Successful in 55s
    test-build / build (backend) (pull_request) Successful in 58s
    test-build / build (pull_request) Successful in 0s
    CI / frontend-test (pull_request) Successful in 1m5s
    CI / backend-test (pull_request) Successful in 2m0s
    CI / e2e (pull_request) Successful in 2m10s
    CI / release-scripts (push) Successful in 6s
    security-scan / Python SAST (bandit) (push) Successful in 20s
    security-scan / SBOM (trivy) (push) Successful in 11s
    security-scan / Filesystem scan (trivy fs) (push) Successful in 14s
    security-scan / JS SCA (npm audit) (push) Successful in 15s
    CI / pre-commit (push) Successful in 27s
    security-scan / Python SCA (pip-audit) (push) Successful in 38s
    publish-main / build (frontend) (push) Successful in 58s
    publish-main / build (backend) (push) Successful in 1m2s
    publish-main / build (push) Successful in 0s
    CI / frontend-test (push) Successful in 1m4s
    CI / backend-test (push) Successful in 1m58s
    CI / e2e (push) Successful in 2m9s
    release-and-deploy / release-scripts (push) Successful in 5s
    release-and-deploy / pre-commit (push) Successful in 22s
    release-and-deploy / release (push) Successful in 28s
    release-and-deploy / build (frontend) (push) Successful in 56s
    release-and-deploy / frontend-test (push) Successful in 59s
    release-and-deploy / build (backend) (push) Successful in 1m2s
    release-and-deploy / build (push) Successful in 0s
    release-and-deploy / backend-test (push) Successful in 1m55s
    release-and-deploy / e2e (push) Successful in 2m5s
    release-and-deploy / ci (push) Successful in 0s
    release-and-deploy / deploy (push) Successful in 1m54s
    Stable

    robbertbos released this 2026-08-07 19:27:37 +00:00 | 129 commits to main since this release

    Let op bij het uitrollen

    • Deze release vraagt een stop-then-start-deploy, geen rolling update. De
      vorige en de nieuwe versie kunnen niet tegelijk op dezelfde database: zolang
      ze naast elkaar draaien, krijgt elke gebruiker foutmeldingen van de oude
      versie.
    • Draai de twee controlequery's uit docs/deployment.md vooraf (identifiers en
      cleanup_undo_state). Vindt een van beide iets, ruim dat op vóór de deploy -
      de migratie stopt er anders op.
    • Een export uit een oudere versie kan geweigerd worden bij het
      terugzetten.
      Een bundel die op een SQLite-installatie is gemaakt bevat
      tijdstippen zonder tijdzone; de import weigert die nu met
      Input should have timezone info (HTTP 400). docs/deployment.md beschrijft
      hoe je zo'n bundel repareert: de tijdstippen in de JSON een Z geven.

    Nieuw bericht opstellen

    • Je kunt nu nieuwe berichten opstellen en laten afleveren in een kanaal of als
      direct bericht bij een persoon: kies een doel, schrijf je bericht met opmaak,
      @-mentions en bijlagen, en verstuur het direct of plan het in. Openen via
      "Nieuw bericht" in het menu of met de sneltoets c.
    • Een bericht dat je nog niet wilt versturen bewaar je als concept. Je kunt aan
      meerdere concepten tegelijk werken; ze staan onder Concepten, waar je ze weer
      opent. Ook een mislukt gepland bericht pak je daar op om het opnieuw te plannen.
    • Een concept gooi je weg op de Concepten-pagina, of door het helemaal leeg te
      maken - dat laatste geldt ook voor een antwoord in een thread. Je hebt tien
      seconden om dat ongedaan te maken; daarna verdwijnt het concept met zijn
      bijlagen.
    • Je kunt nu ook een bijlage meesturen met een concept of gepland bericht;
      voorheen kon dat alleen bij een direct antwoord.
    • In alle composers toont het kopjesmenu per niveau een icoon, zodat je Kop 1
      tot en met Kop 6 sneller uit elkaar houdt.

    Overzichtspagina's

    • Nieuwe pagina's Concepten, Uitgaande post en Notities (via het menu)
      verzamelen je concepten, geplande en verzonden berichten, en notities op één
      plek.

    Automatisch opruimen

    • Afgehandelde berichten en voltooide of gelezen kaarten worden nu desgewenst
      vanzelf opgeruimd (standaard na 90 dagen; instelbaar op uit, 30, 90, 180 of
      365). Concepten en kaarten met een notitie blijven altijd staan.
    • Bij bestaande accounts staat deze optie standaard uit. Deze accounts krijgen
      een eenmalig bericht dat aanbiedt om het op 90 dagen te zetten.
    • Bijlagen van geannuleerde en mislukte berichten bleven onbeperkt op het volume
      staan. Dat lossen we ook direct op.

    Plannen en uitstellen

    • Bij "Zelf kiezen…" kies je datum en tijd nu met een echte kalender (met
      weeknummers) en een keuzewiel ernaast, in plaats van met twee kale
      invoervelden.
    • De plan- en snooze-popover zijn nu met het toetsenbord te bereiken en te
      bedienen; het waren muis-only dialogen die buiten de focus-trap vielen. De
      focus gaat er bij openen in en keert bij sluiten terug naar de knop, je loopt
      met de pijltjestoetsen door de opties, en Escape sluit alleen de popover, niet
      de kaart eronder (WCAG 2.1.1).
    • De API weigert nu een tijdstip zonder tijdzone, in plaats van er UTC van te
      maken. Een gepland bericht dat om 09:00 werd ingestuurd zonder offset
      vertrok daardoor een tot twee uur te laat, afhankelijk van zomer- of
      wintertijd. De app zelf stuurde altijd al een tijdzone mee; dit raakt eigen
      scripts, handmatig bewerkte import-bestanden en exports uit een oudere versie
      (zie "Let op bij het uitrollen").

    Voorwaarden en welkom

    • Je ziet nu op de voorwaardenpagina wanneer je de voorwaarden accepteerde, en
      kunt ze altijd teruglezen via het menu-item Voorwaarden.
    • De welkomstpagina stopt na het accepteren van de voorwaarden; Mattermost
      koppelen doe je in Instellingen (een banner wijst je daarheen als er nog geen
      server gekoppeld is).

    Toegankelijkheid

    • Nieuwe link "Direct naar de inhoud" bovenaan elke pagina: druk op Tab en je
      slaat het menu over. Ook een schermlezer springt nu direct naar de inhoud.
    • Focus blijft binnen een geopende modal: de focus-trap zag knoppen in
      web-components en de tekst-editor (contenteditable) eerder over het hoofd,
      waardoor Tab naar de achtergrond kon weglopen (WCAG 2.4.3).
    • De sneltoets / opent de zoekbalk niet meer terwijl je typt in een invoerveld
      binnen een web-component (zoals het Mattermost-token-veld), en ook niet meer
      achter een geopende kaart (WCAG 2.1.4).
    • Een reactie op een bericht vertelt nu ook aan een schermlezer of jij hem
      zelf hebt gegeven; dat was alleen aan de kleur te zien.
    • De kaartdetail-modal markeert het paneel zelf als dialoog in plaats van de
      achtergrondlaag, zodat een schermlezer de juiste grens aanhoudt.
    • Instellingen gebruikt nu overal dezelfde opbouw voor een veld: label, hint
      en foutmelding komen uit NLDD. Hints worden daardoor ook echt voorgelezen;
      ze waren eerder alleen zichtbaar.
    • Een mislukte opslag bij Voorkeuren was volledig stil en is nu zichtbaar.
      Een thema dat niet opgeslagen kon worden draait ook weer terug.
    • De vinkjes in de import-tabel heten nu hetzelfde als hun zichtbare label
      ("Toepassen: Thema" in plaats van "Toepassen: theme"), zodat je ze met
      spraakbediening kunt aanwijzen.
    • Bij "Account verwijderen" springt de focus nu echt naar het eerste vinkje;
      dat was de bedoeling maar gebeurde niet. Het e-mailveld doet geen
      spellingscontrole meer.

    Tekst en vormgeving

    • Tekst is groter, gelijkmatiger en staat ruimer op de regel. Berichten,
      uitlegteksten, formulierlabels en knoppen stonden verspreid op 10 tot 16px
      terwijl de pagina op 18px staat; ze volgen nu de basis, met een regelafstand
      van 1.5 in plaats van 1.125. Compacte menu's houden bewust 16px aan, het
      formaat dat NLDD zelf voor dat soort oppervlakken gebruikt.
    • Waggle heeft veel minder eigen ontwerp-tokens: lettergroottes, spacing,
      hoekafronding, letterdiktes, schaduwen, focus-ring en overgangen komen nu uit
      NLDD in plaats van uit een eigen reeks ernaast. Vetgedrukte tekst wordt
      daardoor iets minder zwaar (600 in plaats van 700) en de kleinste iconen
      worden 16px (waren 12-14px).
    • Hoeken en kaders zijn overal gelijk: kaarten, vensters, menu's en zwevende
      panelen (plannen, bron-pad, "Aan") zijn even rond en krijgen alleen schaduw
      en hoekstraal, geen extra haarlijn. Sommige menu's en popovers waren nog
      vierkant.
    • Knoppen, lege toestanden, labels en initialen-cirkels komen nu uit NLDD in
      plaats van uit eigen CSS. De knopjes op kaarten, in het kaartdetail en op de
      rijen van uitgaande post zijn daardoor overal even groot, reageren hetzelfde
      op de muis en zijn met Tab allemaal bereikbaar; een kapotte profielfoto valt
      vanzelf terug op de initialen. Daarmee staat er nergens in de app nog een
      hardgecodeerde lettergrootte.
    • Een paar iconen dragen nu het begrip dat ze bedoelen: een video-bijlage toonde
      een leeg vakje en krijgt een afspeel-driehoek, "Verzend nu" een pijl naar het
      eind in plaats van een terugdraaiende klok, en Backlog een eigen icoon zodat
      het niet meer hetzelfde oogt als Inbox.
    • NLDD-design-system naar 0.8.78: kaarten hebben nu een rand in plaats van een
      schaduw, en foutmeldingen en scheidingslijnen in menu's krijgen meer ruimte.

    Opgelost

    • Waggle gebruikt RijksSans niet meer. Dat font is volgens de voorwaarden van de
      Rijksoverheid voorbehouden aan publicaties van de Rijksoverheid en aan werk in
      haar opdracht; Waggle valt daarbuiten. De app gebruikt nu het systeemlettertype
      en levert de fontbestanden ook niet meer mee. JetBrains Mono (vrij
      gelicentieerd) blijft voor code.
    • Foutmeldingen zijn weer rood. Ze verwezen naar een kleur-token dat niet
      bestaat, waardoor 19 meldingen (banners, toasts, formulierfouten, mislukte
      bijlagen) in gewone tekstkleur stonden en de rode banner-achtergrond helemaal
      wegviel.
    • De opmaak van Mattermost-berichten staat nu op één plek. Zes componenten
      hadden er elk een eigen kopie van, die onderling uit elkaar waren gelopen:
      koppen ontbraken op de inbox-kaart, en de spatiëring verschilde per scherm.
    • De muiscursor volgt nu de NLDD-conventie: knoppen tonen de standaardpijl; het
      handje is voor links en klikbare kaarten/rijen. Voorheen was dit door elkaar
      (de ene knop toonde wel een handje, de andere niet).

    Onder de motorkap

    • Waggle draait nu alleen nog op Postgres; de SQLite-optie is vervallen. Dit
      maakt tijdzone-bewuste datums en database-validatie mogelijk. Een andere
      database-URL dan postgresql+asyncpg:// wordt bij het starten geweigerd, en
      een URL uit backend/.env werkt weer.
    • Identifiers zijn nu echte UUID's in plaats van tekst die er zo uitziet: de
      database controleert ze, vergelijkt ze sneller en slaat ze half zo groot op.
      De ongedaan-maken-momentopname van een kaart was tekst met JSON erin en is nu
      een echte JSON-kolom.
    • Negen ongebruikte Python-pakketten uit het backend-image gehaald (50 -> 41).
      Ze telden wel mee in de kwetsbaarhedenscan, die een uitrol kan blokkeren op
      code die nooit draait. De beheercommando's waggle generate-secrets en
      waggle rotate-keys werken ongewijzigd.
    • De backend-container start sneller: de Python-bytecode zit nu in het image in
      plaats van dat elke start hem opnieuw wegschrijft onder /app (1,60 s -> 0,68 s
      voor het inladen van de app; het image wordt er 34 MB groter van).
    • Een bijlage die je uploadt staat nu ook onderweg op het gegevensvolume in
      plaats van op de schijf van de pod. Die schijf kon vollopen buiten het zicht
      van de ruimtecontrole om, met een pod-herstart als gevolg; een volle schijf
      geeft nu de nette melding in plaats van een serverfout.
    • Geparkeerde bijlagen worden nu versleuteld op schijf (eigen sleutel-domein),
      zodat een volume-snapshot of backup de inhoud niet prijsgeeft.
    • Nieuwe dagelijkse retention_sweep-loop past de bewaartermijnen per gebruiker toe
      en legt alleen aantallen per categorie vast in het audit-log (retention_purged).
    • Logging is samengevoegd tot één centrale pijplijn (structlog
      ProcessorFormatter op de root-handler): structlog-, stdlib- én
      uvicorn-logs gaan door dezelfde redactie en dezelfde rendering (JSON in
      productie). Voorheen omzeilden structlog en uvicorn de redactie allebei.
    • Redactiepatronen verbreed: ook geciteerde/JSON-vormen ("token": "..."),
      alle cookie-pairs, OAuth-queryparameters (?code=/&state=),
      secret-veldnamen en traceback-tekst worden geredact.
    • Logniveau instelbaar via WAGGLE_LOG_LEVEL (default INFO); stdlib-INFO
      (o.a. CSRF-blocks, audit-events) verscheen voorheen helemaal niet.
      Elke request krijgt een request_id in alle bijbehorende logregels.
    • Alembic zet de logging-config niet meer terug bij het opstarten: de
      in-process migratie sloopte de redactie-handler en dempte de
      uvicorn-loggers op elke boot (fileConfig draait nu alleen nog voor de
      losse Alembic-CLI).
    • De build en de tests slaan nu alarm bij fouten die eerder geruisloos
      doorgingen: een verdwenen ontwerp-token, een meegeleverd RijksSans-font, een
      icoonnaam die niet meer bestaat, een ongeldige waarde op een NLDD-component
      (variant, kleur, formaat) en een NLDD-component die zijn padding weer op de
      buitenkant zet.
    • CI is sneller: de e2e-job bouwde de frontend twee keer en typecheckte opnieuw
      wat de frontend-job al deed, en draait nu op drie parallelle workers met een
      eigen backend en database per worker (lokaal 76s -> 25s). De backend-suite
      draait op een vast aantal workers in plaats van -n auto, dat de cores van de
      hele host claimde en naast een tweede CI-run tot tienvoudige looptijden leidde.
    • Renovate bumpt npm- en Python-dependencies nu ook binnen een bestaande range
      (rangeStrategy: bump). De default replace liet >=-floors en
      caret-ranges op hun oude versie staan, waardoor routine-updates (inclusief
      in-range security-patches) stil bleven liggen.
    • Dependencies bijgewerkt: fastapi 0.141.1, uvicorn 0.52.1, sqlalchemy 2.0.51,
      alembic 1.19.0, pydantic 2.13.4, structlog 26.1, tiptap 3.29.2, dompurify
      3.4.13, vite 8.2.0, typescript-eslint 8.66 en cryptography 50.0.0
      (security-advisory).
    • CI-toolchain bijgewerkt: uv 0.12.1, trivy 0.73.0, node 24.19.0-alpine en een
      nieuw nginx-basisimage; de fail-closed sha256-pins voor uv en trivy zijn
      tegen de upstream-checksums gecontroleerd.
    • Drie ongebruikte toegankelijkheidspakketten verwijderd; dat scheelt 134
      pakketten en vier van de zes high-severity meldingen in npm audit.
    • Alle vensters (opstellen, kaartdetail, herstelcode, sneltoetsen) delen nu één
      Modal-component: overlay, focus-trap, scroll-lock, Escape, header en breedte
      zitten op één plek in plaats van in vier eigen kopieën.

    Container images