Files
portal/CHANGELOG.md
T
Bendik Aagaard LynghaugandClaude Fable 5.1 19c8f541de Mail is content: a state's mail: and the invite mail, published for gdo
`mail: { to, subject, body }` on a state in aggregates.yaml sends when a
record enters that state, `to: submitter` or one address, templates
over the record's fields plus {site}, {chain}, {email}. An invite mails
its one-time link built in, reworded by `mail.invite` in site.yaml,
which also carries the sender (`mail.from`, `mail.reply_to`); without
it a site sends nothing and says so in the log. Portal renders the
text and an HTML alternative and publishes one message per state
change on portal.mail.send in the WORMHOLE stream, id <bucket>:<record>
:<state> so a retried transition sends once; uhhm/gdo holds the
durable consumer and talks SMTP. The lint requires a required email
field on every form recording into a bucket that mails the submitter.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-23 19:45:48 +02:00

13 KiB

Changelog

One line per change, grouped by the release that shipped it. Newest first. A release is a Cargo.toml bump plus a v<version> tag; the content repos pin the tag they run (see the end of this file).

0.3.43 (2026-09-23)

  • Mail is content: mail: { to, subject, body } on a state in aggregates.yaml sends when a record enters that state (to: submitter or one address; {field}, {site}, {chain}, {email} in the templates), and an invite mails its one-time link built in; site.yaml gains mail: { from, reply_to, invite }. Portal renders and publishes on portal.mail.send in the WORMHOLE stream; uhhm/gdo delivers. The lint requires a required email field on every form recording into a bucket that mails the submitter.

0.3.42 (2026-09-23)

  • people: the Kanidm person lookup reads the body, since Kanidm 1.11 answers a missing person with 200 and null rather than 404; before this every invite skipped account creation and failed on the group step

0.3.41 (2026-09-23)

  • publish: the iris release step retries on a fresh clone when its push loses a race against a push to iris main (the v0.3.40 tag never published)
  • iris: check --access prints the access matrix, and every check validates the compiled policy against the schema

0.3.40 (2026-09-23)

  • One access policy, compiled from content into Cedar on every load (src/access.rs): pages, resource reads, desk transitions, self transitions and the automation endpoint all decide through it; decisions carry rule ids, refusals and mutations publish on portal.access.decided, and portal.access.<site>.may answers the same question for other apps over NATS
  • invite: {group} on an alternative onboards a person into Kanidm from a desk (src/people.rs, KANIDM_API_TOKEN), recording the one-time credential link in portal_invites and on portal.people.invited

0.3.39 (2026-09-23)

  • publish: releases the matching uhhm/iris by proxy - re-pins, builds, tests and tags it as this version (needs the IRIS_PUSH_USER variable and IRIS_PUSH_TOKEN secret); iris carries portal's version number from here on

0.3.38 (2026-09-22)

  • publish: the iris build step gets a writable cargo home; the v0.3.37 tag never published

0.3.37 (2026-09-22)

  • The lint moves to its own repo, uhhm/iris: question_lint becomes iris check, needs_replay becomes iris replay; the tarball ships iris (pinned in publish.yml) instead of question_lint; the needs module and local loaders leave portal

0.3.36 (2026-09-22)

  • Question nav: a followup is offered only once earned - the verified chain answered the alternative leading there, or a link that records nothing leads on from an earned page. Standing on a page no longer unlocks the pages behind its forms; the chain index now records which alternative was answered
  • One bounded HTTP client for every server-side fetch: 20 s budget, size caps per kind of fetch (src/http.rs)
  • Uploads are refused past 20 MB while streaming, and the route body limit that had capped them at axum's 2 MB default is raised to match
  • tests/jetstream.rs: the store, the event log and the projection tested against a real JetStream (CI starts a throwaway one)
  • content split into gitea, validate, markdown, handlers; every path still content::x
  • This changelog, and the table of what each site runs
  • Business needs as a checkable spec: needs.yaml + question_lint pass
  • needs: success states and a resolved simulation model
  • needs: stages - every stage the business named must be a state
  • needs_replay: make simulated cases real aggregates, report buckets by state
  • needs: also_moved_by - a need carried by more than one group's desk

0.3.35 (2026-09-12)

  • Item cards: no paragraph margin under the description

0.3.34 (2026-09-11)

  • Question nav: offer followups by reach, not by carrying any chain

0.3.33 (2026-09-02)

  • Head preloads: latin font, wordmark, content-host preconnect

0.3.32 (2026-09-01)

  • Per-site favicon via site.yaml

0.3.31 (2026-09-01)

  • Markdown links allow tel:

0.3.30 (2026-09-01)

  • Single alt-image shows natural height

0.3.29 (2026-09-01)

  • Markdown image layout hints + AVIF assets

0.3.28 (2026-09-01)

  • Hero description renders inline markdown

0.3.27 (2026-09-01)

  • wordmark_invert: explicit, not inferred from .svg

0.3.26 (2026-09-01)

  • Select fields: inline static options

0.3.25 (2026-09-01)

  • Content-shipped stylesheet override (site.yaml stylesheet)

0.3.24 (2026-09-01)

  • Gateway submit-as-link loses the underline

0.3.23 (2026-09-01)

  • Chrome speaks the site's language: site.yaml lang + i18n table

0.3.22 (2026-09-01)

  • site.yaml wordmark_height; raster logos keep their colors

0.3.21 (2026-09-01)

  • Hero paragraph centers its measure box

0.3.20 (2026-09-01)

  • Sign-in becomes optional: KANIDM_URL unset disables auth cleanly

0.3.19 (2026-09-01)

  • Markdown images in descriptions, gated and framed

0.3.18 (2026-09-01)

  • Item cards render inline markdown descriptions
  • Convergence: ink converges onto the decoded key (WebGL glow)
  • Gesture results overlay the canvas - the page never jumps

0.3.16 (2026-08-30)

  • Announce sweeper: refresh open records from content

0.3.15 (2026-08-30)

  • Hidden fields: carrier value without a label row

0.3.14 (2026-08-30)

  • Feature cards: icon column, one text edge

0.3.13 (2026-08-30)

  • Voice field: nothing leaves the browser until Keep it here

0.3.12 (2026-08-30)

  • Voice preview stays hidden until there is something to play

0.3.11 (2026-08-30)

  • README: gesture and voice fields
  • Validate templated actions against the page pattern

0.3.10 (2026-08-30)

  • type: voice, Requirement.value, playable resource cards

0.3.9 (2026-08-30)

  • Templated actions; places are pickable in the gesture input

0.3.8 (2026-08-30)

  • Descriptions are inline markdown; Feature.link withdrawn

0.3.7 (2026-08-30)

  • Feature.link: a card's name may point elsewhere

0.3.6 (2026-08-30)

  • Announced pages: event windows, header announcements, summary tasks

0.3.5 (2026-08-30)

  • Gesture widget: stop drawing the decoded ghost path
  • Gesture widget: ghost path back, for v2 keys only

0.3.4 (2026-08-25)

  • Alternative.disabled: announced but not yet takeable

0.3.3 (2026-08-25)

  • Empty list says so before it can parse as zero answers

0.3.2 (2026-08-25)

  • README: hashed pkg assets in the release flow
  • Resource empty text: content-declared, and null counts as empty

0.3.1 (2026-08-25)

  • Content-hashed pkg assets (hash-files) so stale bundles can't pair with new wasm

0.3.0 (2026-08-25)

  • Hero becomes a content-owned module; site asset proxy; gesture growth fix

0.2.4 (2026-08-25)

  • Gates keep the question nav

0.2.3 (2026-08-25)

  • Attended-bucket lint rule; app-lifetime resources fix first-nav corruption

0.2.2 (2026-08-24)

  • One app-level Title fed by a shared site resource

0.2.1 (2026-08-24)

  • Docs: routing bullet + design doc marked implemented
  • Revalidating cache on app assets; site title survives SPA navigation

0.2.0 (2026-08-24)

  • Initial commit: content-driven onboarding portal
  • Load content from Gitea directly, drop the local clone; add deploy workflow
  • Share sccache between manual dev builds and CI
  • Give CI its own SCCACHE_SERVER_PORT
  • Erase view types at every list/component boundary, not just leaves
  • Redirect cargo-leptos's tool cache out of act-runner-bare's StateDirectory
  • Fix Ship release: site-root is project-relative, not CARGO_TARGET_DIR
  • Drop sudo from the deploy workflow - NoNewPrivileges blocks it outright
  • Caddy snippet: use multi-line log block
  • Fix static asset 404s and build-time SITE_NAME
  • Hot-reload content on a NATS trigger instead of requiring a restart
  • Add prosekit rich-text field, Gitea repo embeds, automation KV read endpoint; fix apex/www session-cookie mismatch on /auth/callback
  • Fix prosekit-editor.js: remove bare CSS imports that aborted the whole module
  • Redirect back to the originating page after sign-in, not always /
  • Fix hero-canvas navigation race; style the prosekit editor and add a toolbar
  • yes.js: guard against the canvas not being in the DOM yet
  • Fix get_resource/transition_answer: scope feature lookup to its own alternative
  • Add self-service transitions, authorized by item possession not group membership
  • Event-sourced applicant/subscriber/project aggregates, generalized resources
  • deploy.yml: write GITEA_API_TOKEN for the new GiteaStarred/OrgRepos resource sources
  • Cargo.toml: disambiguate bin-target for cargo-leptos
  • Add manually-triggered backfill workflow, no terminal/sudo needed
  • Trigger redeploy to pick up PORTAL_GITEA_API_TOKEN secret
  • Render generic resource lists as cards, not raw JSON dump
  • Fix recursion-limit build failure in the new item-card renderer
  • Resource-backed multi/single-select requirement
  • Add Organization aggregate (client-as-status), wired but inert
  • Fix favicon (real icon, not an unrelated orange circle) + stack encouragements with the submit button
  • Fix bucket-404 on empty resources, redesign review actions as select-then-confirm, CSS polish
  • Inline encouragements with the submit button, vertically centered
  • Use the real institutional logo for the header wordmark, not plain text
  • Use the actual UHHM-letters wordmark, not the institutional mark
  • Responsive base font size via svmin, not fixed 17px
  • Add plain-unit fallbacks for svmin/svh in case of unsupported engines
  • Size the YES canvas from its container, not window.innerHeight
  • Debounce the YES canvas resize handler and skip no-op resizes
  • Revert canvas sizing to window.innerWidth/innerHeight, gate resize on width change
  • Stop blocking native scroll on the YES canvas's touch handlers
  • Quicksand: font-display optional, not swap, to stop the text-jump on scroll
  • Use lvh/lvmin, not svh/svmin - svh was the wrong end of the viewport
  • Update style/main.css
  • Update style/main.css
  • YES canvas: size off its own container rect, not window.innerHeight
  • yes.js: freeze .hero-yes's height via inline style, don't trust svh alone
  • add responsive container width
  • deploy.yml: build and publish question_lint alongside the app binary
  • Make aggregate state graphs content-driven, not compiled Rust
  • One shared, content-labeled Confirm button per alternative instead of one per row
  • get_resource/get_requirement_options: #[server(default)] on params
  • Add optional Alternative.image and Feature.color/icon for richer layouts
  • Drop the feature list's left-padding
  • Drop question-report entirely, obfuscate the mailto link instead
  • Transition.from: state graphs deeper than one decision
  • Alternative.images: array of urls, rendered as a Swiper card deck
  • Reseed lost event history from the KV projection on transition
  • Lighten the comment load
  • Validate action targets; format timestamps client-side; clippy cleanup
  • Question nav + gateway alternatives
  • Responsible note under the title; followup pages out of the nav until a chain exists
  • README: what the engine provides
  • Feature icons: masked span painted by currentColor, not
  • Responsible note: one line, same hue and size as the hero description
  • Responsible note as : meta information, dimmer than the description
  • Responsible note back to the footer, above the question nav
  • Bound inputs: a field that loads its value from a sibling-parameterized resource
  • add some more width to our alternatives
  • Accent to a dusty press-cyan, a muted echo of the canvas's cyan ink
  • Editor type in rem: prosekit's px typography ignored the responsive root
  • Ban px from stylesheets: every length rem/em off the responsive root
  • No translucent input chrome: solid ink-dim placeholders and embed meta
  • Editor type scales for real: drop prosekit typography.css, fix selectors
  • Stable server fn endpoints: open tabs survive deploys
  • Drop stray local tool temp file, ignore .claude/
  • Noise-driven YES, sticky hero with frosted cards, full light theme
  • increase translucency of laternative cards
  • Showcase jq test tracks Gitea repo shape and website-first links
  • Gesture input type, redoal-relay client, gitea_releases, content-driven branding
  • Echo thumbnails fade in via timeout, not rAF
  • Trigger deploy: redoal OAuth2 credentials now configured
  • Deploy becomes publish: portal ships as a versioned release artifact
  • Semver releases cut with cargo-release; publish on v* tags only
  • Docs: release/rollout flow after the instance-ownership refactor
  • README: frame portal as a generic multi-site question engine
  • Design doc: filesystem routes, sections, dynamic segments
  • Filesystem routes, sections, dynamic segments; instant YES hero

What each site runs

Read from the hosts on 2026-09-23; a rollout is a pin bump in the site's content repo (PORTAL_RELEASE in its deploy.yml), or a manual tarball deploy on kasse.

Site Host Instance Version
uhhm.no ergo app@uhhm-portal v0.3.36
redoal.com ergo app@redoal-portal v0.3.36
westra.klingenbergbygg.no kasse app@westra-portal v0.3.41
portal.klingenbergbygg.no kasse app@klingenberg-portal v0.3.41
vel.klingenbergbygg.no kasse app@tomtervel-portal v0.3.41