1fbeeb52b8
Add a compact semver and upgrade policy for v1: stable beginner APIs, stable wire/runtime compatibility, advanced escape-hatch tier, breaking-change rules, upgrade-note template, and release checklist. req: abi/001 req: abi/002 req: abi/003 req: abi/004 req: abi/005 req: public_api/001 req: public_api/002 req: public_api/005 req: runtime/003 req: runtime/004
141 lines
7.7 KiB
Markdown
141 lines
7.7 KiB
Markdown
# 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<T>` inputs, and
|
|
`impl IntoEffect` or `Result<impl IntoEffect, E>` 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<impl IntoEffect,
|
|
E>` 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. See
|
|
`docs/diagnostics.md` for common compile/build/runtime mistakes and fixes.
|
|
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. See `docs/recipes/sqlx-persistence.md`.
|
|
- **Auth/session:** use Axum/Tower extractors and middleware. Handlers may accept
|
|
typed auth/session context and return ordinary HTTP failures or generated UI
|
|
failures. See `docs/recipes/auth-session-csrf.md`. 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. See `docs/recipes/auth-session-csrf.md`. 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. See `docs/recipes/deploy-versioning.md`.
|
|
- **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. See `docs/recipes/deploy-versioning.md`. 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.
|
|
See `docs/versioning.md`.
|
|
|
|
## 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/saas`: compile-tested v1 tutorial skeleton covering auth/session,
|
|
CSRF-safe mutation, local persistence, generated swaps, page/push shape, plain
|
|
CSS, and one explicit island without provider-heavy platform scope. The SQLx
|
|
persistence recipe in `docs/recipes/sqlx-persistence.md` shows the provider
|
|
boundary without moving SQL into core.
|
|
- `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
|