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
This commit is contained in:
@@ -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<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. 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
|
||||
Reference in New Issue
Block a user