The front server's side of the React dashboard. The dashboard's pages now answer the React app's index.html with their data as JSON views, and the sign-in pages are React drawn on the server in a separate render child. A host operator can swap in their own dashboard package, chosen once at startup. The front server's Tera engine and its page rendering are gone.
AST-verified changes
- The settings helpers left
utils.rsfor lichen-site:read_settings_section,edit_settings_in_treeand their siblings went tosettings/edit.rs, andload_settings_for_site_with_overridestosettings.rs(PER-SITE-PROCESS P2c-2b commit 1c, 85a5e79e; the other half is in #37). Checked by the builder (run id not recorded): "10 moved, 3 visibility". The adversary's rerun got the same counts.utils.rsnow re-exports them. - The site settings page's context builder (
build_site_settings_context, nowSettingsContext) leftutils.rsfor lichen-site'ssettings/page.rs, and the page templates were renamed into the site crate (P2c-2b commit 5, 6c06675b; the other half is in #37). Checked by the builder (run id not recorded): "move 5 ok: 10 moved, 4 carried, 1 renamed, 4 vis". The adversary's rerun got the same counts. Allowed: fourpub(crate)→pubwidenings, as mapped. - The path rewrites of SECURITY-FOLDER-AND-PRINCIPALS units 1 and 2 in this PR's files (
crate::site_area→crate::admin_area,crate::access→crate::security::access, and the othersecurity::paths), which those checks cover (unit 1 notify-eebdd32e, unit 2 adversary notify-020eb199, both equal, errors 0), with the rustfmt rewraps after them (d6c25912, bdaa795b), proven bycargo fmt. - FULL-SITE-PROCESS 6a (deef05fc → 0b71076c, map
machine-docs/reports/fsp-6a/move-map.json):sign_in_render_specandSIGN_IN_RENDER_ADDRESS_SPACEleftsign_in_render.rsfor lichen-site'ssandbox/spawns.rs(#39), with seven other spawn items; the module imports them. Run notify-82fbca10: "equal=True: items 5581/5581: moved 9, stayed 5572; visibility_changes 8, every one listed; comments compared 4995"; adversary rerun equal=True, 5581/5581, plants caught (notify-ec60785b).
Roughly 193 of this PR's 1,904 changed lines are code these moves carried verbatim, nearly all of them the lines that left utils.rs. Everything else (the JSON views, the render child, the dashboard source) is new code to read; 6a's two items were written after 09-23, so they appear in no line here.
DASHBOARD-REACT replaced the Tera dashboard one page at a time:
- The pages
/,/settings/and/settings/{domain}answer the app'sindex.html(dashboard_app.rs, embedded). Each page's data comes from a JSON view indashboard.rs(dashboard_json,account_json,site_settings_json), so the page and the API show one thing. The app's files are served from a fixed list: a request names a file of the list, or nothing is looked up. - The sign-in pages are drawn on the server (
sign_in_render.rs, unit 4) in a render child: this executable started again aslichen render-child, underlichen sandboxwhere the sandbox is on. A sign-in page renders data a visitor sets, so its JavaScript runs where no secret is. One warm child serves renders one at a time and stops when idle. A render that outlives its limit, or an answer outside the protocol, has the child killed with everything it started. - Without JavaScript the dashboard is the same child's server-drawn sites list (U4b), with plain forms to create and delete a site. Deleting needs the domain typed again.
- A host operator can replace the dashboard (
dashboard_source.rs):[dashboard] sourceinlichen.tomlis apath:folder, an HTTPS archive or a git source, each with a pin, read through the site frontend loader's confined tree and fetchers. Only startup reads the configuration or the package; requests see validated, immutable bytes. A bad selection serves the built-in app with a bounded notice. A site cannot select it. - Tera is gone from the front server:
templates.rs(the dashboard engine) is deleted, andutils.rslosesrender_templateand the settings-page context. - The site's settings view shows the git remote and sync the site process's admin thread records, asked over
/hub/remote(FULL-SITE-PROCESS 6d), and a remote that is failing (remote_failure, SITE-FRONT-BOUNDARY units 6 and 7); a share guest is shown none of it. The sites list's usage and the hub's status come from the running processes (/hub/status).
Files (crates/lichen-server/src/)
dashboard.rs(+445/−207) — the JSON views, the edit-host links, the no-JavaScript page and its forms, the event stream. Read this first.sign_in_render.rs— new: the render child and its protocol; its sandbox spec is in lichen-site'ssandbox/spawns.rs(#39).dashboard_app.rs— new: the embedded app and its fixed file list.dashboard_source.rs— new: the host-selected dashboard, resolved at startup.utils.rs(+10/−356) — Tera rendering removed; the settings helpers re-exported from lichen-site.templates.rs— deleted.
Lives elsewhere
- The dashboard's JSON API (
api.rs) and the CLI: #32. The routes and their groups (server.rs): #30. - The site frontend loader the dashboard source reuses (
frontend/remote.rs,frontend/git.rs): #34. The settings page's values (settings/page.rs): #37. - The render child's loop,
lichen_site::ssr::serve_render_child: #26. - Not in any PR (base commit): the React app (
frontends/dashboard/,frontends/ui/), its built bundles (app.js,ssr/dashboard-ssr.js), the deleted Tera templates (crates/lichen-server/templates/*),static/lichen.toml.exampleand the tests.
Category: Dashboard: the React pages served, Tera removed, custom dashboards
Size: 6 files, +1,319/−585
Rounds: round 0 at stack ae42e3c0; round 1 at 6b650b2a (SECURITY-FOLDER-AND-PRINCIPALS): path rewrites in dashboard.rs. Read that round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/33/round/1/interdiff; round 2 at b66397c0 (FULL-SITE-PROCESS): sign_in_render.rs's sandbox spec and address-space cap moved to lichen-site's sandbox/spawns.rs (6a, AST-checked, #39); dashboard.rs asks the site process's admin thread for a site's remote and sync (/hub/remote) and its hub's status (/hub/status). Read this round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/33/round/2/interdiff
Plans and ledger: FULL-SITE-PROCESS-2026-10-25.md (6a, 6c, 6d); DASHBOARD-REACT-2026-10-07.md (C2; notes DASHBOARD-REACT-U3-DESIGN-2026-10-17.md, -U4-DESIGN-2026-10-17.md), REPLACE-TERA-WITH-SSR-REACT-2026-10-07.md (R0, R1 notes), PER-SITE-PROCESS-2026-10-09.md (P2c-2b commits 1c and 5), SITE-FRONT-BOUNDARY-2026-10-17.md (units 6, 7).
Inline #[cfg(test)] modules: none. 4 files point to a test file with #[path] (dashboard.rs, dashboard_source.rs, sign_in_render.rs, utils.rs).
Bucket moves: none from round 1. Round 1's dashboard PR also held the site's settings page, the frontend loader and api/html.rs; those are now in #37 and #34.
Round 1: #12 (Dashboard: React pages served, Tera removed, custom dashboards).