lichen.page.review from the reviewed point 0b92cb61 to stack eb5a1653, as one PR per subsystem (review set)

product: 11 Front server: state, the dashboard API, CLI and desktop #58

targeting oct/10-front-auth from oct/11-front-state
Closed opened by and assigned to notplants-bot.bsky.social
targeting oct/10-front-auth from oct/11-front-state

superseded by the full set from 09-23, #17–#37

description: Review set for lichen.page.review, 0b92cb61 (reviewed) → eb5a1653 (stack). PR 11 of 16. 17 files, +4043/−769. One commit, a85be6aff884, which sets these files to their content at eb5a1653. Targets #10 (oct/10-front-auth). #12 stacks on this one. Tests and generated files are not in any PR; they are in main.

The front server's state, its settings and the dashboard's JSON API, plus the CLI and the desktop app's entry points.

  • The dashboard API is a contract. contract/dashboard-api.json lists every route the dashboard router serves on the dashboard host, each classified (provisional, internal, page) with its responses and permission group, and a test fails when the router and the contract differ. Every /api error is in one error shape, and ?format=html on an /api route is refused with 406 inside the route's group. A custom dashboard may use the provisional routes through lichen-ts/dashboard (#14).
  • api.rs, the dashboard API, puts every route in its permission group and does the site acts through the new front-server code: create and delete (shared with the no-JavaScript forms), backup status (STC-BACKUP1), POST /api/auto-pull (a GET never acts, ADMIN-EDIT-HOST-SPLIT H3), compact, compact-all, force-pull, force push (#6), trigger-publish (#7), and the edit-host handoff (#10).
  • state.rs gains what the front server now owns: each site's publish lock and asks, each site's iroh transport, the dashboard's per-owner event stream (created, deleted, publish finished), the password sign-in limit, the PDS import into the hub (SITE-FRONT-BOUNDARY unit 10a: settings read from the hub by git, not from a checkout), and recycling an owner's site processes when the owner's public facts change (N8).
  • A single-site server keeps its own state beside the site, not in it (SINGLE-STATE1, STC-CLAIM1): users, tokens, keys and its own lichen.toml move once into .<site>.lichen/ (or LM_STATE_DIR), mode 0700, and server keys left in the site's settings.toml are then ignored, with a warning.
  • New settings: use_shortcodes_cache, trusted_proxies; hot_reload_templates is gone with Tera. confined() and site_processes() say how sites run in each mode.
  • CLI and desktop: lichen dispatches the hub's pre-receive check and --build-id before anything else, starts site processes from its own inode on Linux, and loses ssh-relay. The desktop app can serve a site process too.

info: Plans: DASHBOARD-REACT-2026-10-07.md (unit 1: the API and its contract; design note DASHBOARD-REACT-U1-DESIGN-2026-10-17.md §5–§7), SITE-FRONT-BOUNDARY-2026-10-17.md (units 8, 9a, 10a, 11d, 11e), ADMIN-EDIT-HOST-SPLIT-2026-10-13.md (H1e, H2a, H3), OPERATOR-REVIEW-REVISIONS-2026-10-13.md (N8), and the single-site fixes SINGLE-STATE1 and STC-CLAIM1.

Files

  • contract/dashboard-api.json — new (2024 lines): the dashboard API contract. Hand-written (route notes and design references), and read by product code (dashboard_source.rs includes it), so it is reviewed here rather than treated as generated.
  • crates/lichen-server/src/api.rs (+576/−358) — the dashboard API. Read first.
  • crates/lichen-server/src/state.rs (+798/−210) — what the server holds; the PDS import; site events; owner-fact recycles.
  • crates/lichen-server/src/server_settings.rs (+449) — SINGLE-STATE1's state directory and migration; new settings; confined, site_processes.
  • crates/lichen-server/src/owner.rs — the owner's public facts only; the session moved to credentials.rs.
  • crates/lichen-server/src/features.rs — mostly its inline test module: the site-runtime iroh sync test goes with the site's iroh runtime (#9).
  • crates/lichen-server/src/index.rs — two folders whose names differ only in case are one host; the second is not served.
  • crates/lichen-server/src/lib.rs, site_settings.rs, site_host.rs, desktop/server.rs — module list, re-exports, the storage question removed, desktop defaults.
  • crates/lichen-server/Cargo.toml — iroh and iroh-blobs (the transport moved here), lichen-sandbox, flate2; tera removed; test-only zip, syn, quote, sha2.
  • crates/lichen-cli/src/main.rs, client.rs, oauth_server.rs, server.rs — the dispatches above; error text from the API's error shape; the OAuth callback's route in a group.
  • crates/lichen-tauri/src/main.rs — serves a site process when launched as one.

Moved in: contract/dashboard-api.json (the starting map called it generated; it is hand-written and product code reads it).

Lives elsewhere

  • The dashboard's pages, its custom-dashboard loader and the Tera removal: #12. The dashboard frontend itself: #14.
  • Host routing and sign-in: #10. Permission groups and access.rs: #2.
  • Tests (tests/dashboard_api.rs, tests/state.rs, tests/server.rs, the boundary guard and its tables, workspace_structure.rs, the CLI's tests) are in main.
Commits 0