From cb92803db40e03db407464b45ca8283df0bd6471 Mon Sep 17 00:00:00 2001 From: slhx agent Date: Fri, 5 Jun 2026 08:40:40 +0200 Subject: [PATCH] docs(hemx): document v1 product path Add the root v1 product/onboarding playbook: normal authoring path, mental model, production boundaries, escape hatches, versioning/deploy compatibility, example hierarchy, and local checks. This is intentionally documentation-only; the production SaaS tutorial app remains future work. req: pitch/001 req: canonical_authoring/001 req: public_api/005 req: auth/001 req: abi/001 --- README.md | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..aeb75d7 --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# hemx + +hemx is checked hypermedia for Rust: write hemplate templates, write typed Rust +handlers, and return generated UI commands. The browser receives checked UI +commands; ordinary server-first apps do not need a frontend framework, +handwritten UI JavaScript, selector targeting, or raw runtime primitives. req: pitch/001 req: canonical_authoring/001 + +Status: the repository currently has a strong v0 example/API path, an advanced +Kanban milestone sketch, and a full techdemo. The polished v1 production SaaS +tutorial app is still a goal, not a completed artifact. + +## The normal path + +For beginner and production-shaped app code, stay on this path. req: public_api/001 req: public_api/005 + +1. **Templates declare the surface.** `.heml` files declare roots, slots, + forms, handles, keys, page targets, optional pending states, and explicit + leaf islands with `data-hemx-*` attributes. +2. **Build generates typed helpers.** `hemx_build::app().run()` consumes the + hemplate Surface and emits generated Rust helpers for slots, forms, handles, + page targets, classes, and events. req: ceremony/003 req: build/001 +3. **Handlers are plain Rust.** App code uses `#[hemx::handler]` functions with + ordinary domain types, framework extractors, generated `Form` inputs, and + `impl IntoEffect` or `Result` returns. req: derive_handler/004 +4. **Handlers return generated commands.** Common handlers return helpers such + as `todos.append(todo)`, `todo_row.replace(row)`, `new_todo.error("title", + "Required")`, `new_todo.clear()`, `page.replace(view)`, or tuples of those + commands. req: dx/006 req: dx/007 +5. **The runtime only applies effects.** The JavaScript runtime is a small, + root-scoped effect interpreter: no VDOM, no hydration framework, no client + expression engine, no selector retargeting, and no app state store. req: runtime/003 req: invariant/002 + +## Mental model: render → slot/key → effect → runtime + +- **Render:** hemplate renders Rust view structs into checked HTML. App code + normally reaches rendering through generated helpers or `hemx::page(...)` at a + server page boundary, not raw HTML construction. req: html_safety/002 req: view/001 +- **Slot/key:** a generated slot names the target, and a generated keyed slot + also carries the stable row key. A list target inside `h-for` must have a + stable `h-key`, so row updates are addressable without CSS selectors. req: list/001 +- **Effect:** handlers return typed commands that become a checked effect + response. Tuple composition is the normal batch syntax. +- **Runtime:** the browser checks the build fingerprint, resolves targets within + the current `data-hemx-root`, and applies compatible batches. Mismatched + server/runtime builds fail closed instead of silently mutating the wrong DOM. + req: abi/002 req: check/004 req: failure/005 + +## Forms and errors + +Forms remain HTML forms. hemx checks the generated form contract against a +user-authored Rust form type, so domain newtypes such as `Email`, `TodoId`, and +`Title` parse through ordinary Rust traits rather than generated DTOs. req: form/001 + +Use validation effects for expected user mistakes, and `Result` for fallible domain, database, or infrastructure work. Integration crates map +`E` to generated UI effects, redirects, events, or HTTP responses; the canonical +app code still uses the same handler shape for plain and fallible handlers. req: failure/004 req: derive_handler/004 + +## Pages, push, CSS, and islands + +- Page navigation is a specialized generated page/slot effect around real + anchors and ordinary HTTP routes. hemx does not own routing. req: modes/002 req: axum_integration/002 +- Server push streams send checked effect responses over framework-managed + transports such as SSE; auth and connection policy stay in the server + integration. req: wire/004 req: push/002 +- Appearance is plain CSS. Generated class tokens can make dynamic classes + checked, but hemx does not introduce a styling runtime. +- Custom JavaScript belongs at explicit opaque leaf boundaries: charts, maps, + editors, Web Components, or similar widgets. Islands communicate through + generated handles/events and do not create a second UI model. req: canonical_authoring/007 req: interop/003 + +## Production boundary + +hemx is not a SaaS platform. Production concerns stay in normal Rust/web crates +and integrate at explicit boundaries. req: laws/002 req: auth/001 + +- **Persistence:** use SQLx or another storage adapter in your application + state/handlers. hemx should see ordinary domain values and generated UI + commands, not own the database layer. +- **Auth/session:** use Axum/Tower extractors and middleware. Handlers may accept + typed auth/session context and return ordinary HTTP failures or generated UI + failures. req: auth/002 +- **CSRF:** keep CSRF policy in middleware/extractors with hidden form fields, + cookies, and normal SameSite/browser semantics. hemx preserves submitted form + fields and credentials semantics. req: auth/004 req: auth/005 +- **Observability, feature flags, killswitches, deploy:** use explicit platform + integrations around handlers, routes, and runtime assets. Core hemx must not + vendor providers or add framework-specific magic. +- **PWA/offline/sync:** optional adapters may reuse generated targets/effects, + but core hemx must not gain a mandatory client state graph or local app + runtime. req: canonical_authoring/008 + +## Escape hatches + +Advanced APIs are named and isolated. Raw effects, low-level ids, manual +registries, raw HTML/render/target construction, runtime hooks, SSE internals, +and island internals are for integration crates, tests, migrations, or explicit +leaf boundaries. They should not appear in beginner examples or ordinary handler +docs. req: public_api/002 req: public_api/005 + +## Versioning and deploy compatibility + +The generated API, symbols, effect wire schema, and JavaScript runtime carry +schema/ABI versions. Deploy a matching server, generated output, and runtime +asset together. Build fingerprints are derived from the generated surface and ABI +parts; the runtime refuses incompatible effect responses and integrations should +fall back to a full page reload when possible. req: abi/001 req: abi/002 req: failure/005 + +Before a v1 release, the semver policy and upgrade notes should explicitly state +which surfaces are stable: beginner generated helpers and handler shapes; the +wire/runtime ABI; and advanced escape hatches that may remain integration-level. + +## Examples + +- `examples/v0`: canonical beginner path covering counter, typed todo CRUD, + form wizard, auth action, page swaps, SSE notifications, and keyed list + updates. Start here. +- `examples/kanban`: advanced / north-star milestone boundary sketch. It may + expose manual registry or render escape hatches while exploring product limits. +- `examples/techdemo`: advanced integration demo with a leaf island and broader + product interactions. + +## Local checks + +```sh +cargo run -p hemx-xtask -- test +cargo check --workspace +redgate health --strict +``` + +Use `cargo run -p hemx-xtask -- test` for the full local verification path so +jobs stay capped for local CPU and memory. req: test/004