Examples¶
Twelve runnable applications under zerozstack-examples/. Each isolates one part of the framework, and CI
builds all of them on every push — so the code in them is always current, which is not true of every
page in this documentation.
Running any of them¶
Build once from the repository root, then start an example. Every example has a port of its own (0.8.0+), so you can leave several running at the same time. None of them uses 8080: on a working machine that number is usually taken by something else already.
The seven original examples share the main class com.zeroz4j.example.server.ExampleServer. The four
added in 0.6.0 have their own, and so does payments-datamodels, which is in a package of its own:
| Example | Main class | Port |
|---|---|---|
routing-tour |
com.zeroz4j.example.routing.server.RoutingTourServer |
8091 |
oidc-login |
com.zeroz4j.example.oidclogin.server.OidcLoginServer |
8081 |
scoped-signals |
com.zeroz4j.example.scopedsignals.server.ScopedSignalsServer |
8082 |
pwa-install |
com.zeroz4j.example.pwa.server.PwaInstallServer |
8083 |
todo-signals |
com.zeroz4j.example.server.ExampleServer |
8084 |
chat-events |
com.zeroz4j.example.server.ExampleServer |
8085 |
chat-livesync |
com.zeroz4j.example.server.ExampleServer |
8086 |
job-monitor |
com.zeroz4j.example.server.ExampleServer |
8087 |
form-signup |
com.zeroz4j.example.server.ExampleServer |
8088 |
inventory-crud |
com.zeroz4j.example.server.ExampleServer |
8089 |
components-showcase |
com.zeroz4j.example.server.ExampleServer |
8090 |
payments-datamodels |
com.zeroz4j.example.payments.server.ExampleServer |
8092 |
Moving one somewhere else¶
If a number is already taken on your machine, say so on the command line. Every example understands the same two ways of being told:
java -cp "target/classes;target/libs/*" com.zeroz4j.example.server.ExampleServer --port 9000
java -Dzeroz.port=9000 -cp "target/classes;target/libs/*" com.zeroz4j.example.server.ExampleServer
The run.bat scripts take the port as their first argument, and print the address they are using:
The four added in 0.6.0 also build a runnable jar, so
java -jar <example>-server/target/<example>-server-0.9.0.jar works for those without a
classpath. The rest do not; use the classpath command, which is what run.bat does.
Six examples need a sign-in, and the only accounts they have are the framework's development ones.
Starting a server does not switch those on — pass --dev-login on the command line, which the
run.bat scripts already do. Then sign in as demo / demo, or admin / admin for
admin-restricted operations. chat-events, chat-livesync, job-monitor and components-showcase
present a Login component; routing-tour and scoped-signals take credentials from the URL
(?user=admin&password=admin), which is how you open two of them side by side as different users.
todo-signals, form-signup, inventory-crud, pwa-install and payments-datamodels connect
anonymously.
oidc-login is the exception: it needs a running Keycloak. Its
README has the
setup commands.
See Quickstart for prerequisites and why clean matters.
What each one demonstrates¶
| Example | Mechanism | Why that one |
|---|---|---|
todo-signals |
Local signals | The reactive model in isolation, with no network involved: ValueSignal sources, Computed for the visible list and the remaining count, Effect for rendering. Start here. |
form-signup |
Validation + local signals | Constraints declared once on the model and enforced on both tiers, with a Computed driving form validity. |
inventory-crud |
Local signals + RMI | Master-detail CRUD. Derived KPIs as Computed values; save and delete as named RMI operations. |
chat-events |
Server events | Discrete occurrences. Written deliberately without signals, to show that a plain handler and one render path is sometimes the simpler choice. Also shows the subscribe-then-fetch ordering that avoids the snapshot race. |
job-monitor |
Shared signal | One current value that every client must agree on, driven from a server-side virtual thread. A client opening the page mid-job immediately sees the retained progress — the thing events cannot do. |
chat-livesync |
LiveSync | An object kept alive on both tiers, updated in place, in both directions. The view reads its getter inside an Effect, so an inbound sync re-renders automatically — no polling, no subscription. The topic box goes the other way: it is @ClientWritable, so typing in it changes the server's object and every other window follows, with no service call. |
components-showcase |
UI components | The gallery for the component library. The place to look for how a given component is constructed and styled. |
routing-tour |
Routing | Every routing feature in one application: nested layouts, path and query parameters, a literal beating a parameter, @RequiresRole guards, and not-found/forbidden fallbacks. Each route loads its data before anything renders. |
scoped-signals |
Scoped signals | The three reaches side by side — global, per-browser, per-user. Open it twice in one browser as two different users and watch the basket stay shared while the personal notice does not. |
oidc-login |
OIDC authentication | A real Keycloak login with PKCE, then three RMI calls showing what that identity is worth server-side. Its README carries the realm setup and the two Keycloak defaults that otherwise cost an afternoon. |
pwa-install |
PWA | Installability, a per-request manifest built with PwaManifest, an install button bound to Pwa.installable(), and web push. Stop the server and reload to see the one thing installing does not buy you. |
payments-datamodels |
The shapes a wire type can take | A till: a basket, four kinds of payment, and a ledger. Money and LineItem are records; the way somebody paid is a sealed interface with a record per kind; a payment and a refund share a base class. All three travel nested inside each other and inside collections, in both directions, and both the server log and the screen say what actually arrived. |
The three propagation examples — chat-events, job-monitor and chat-livesync — are best read
together, alongside Events, signals or LiveSync?. The
differences between them are the point.
Reading them as reference¶
The examples are the most reliable specification of current usage in the repository. When a document and an example disagree, trust the example — it compiles.
Two caveats:
chat-livesyncis the only example that writes back. Its topic box is@ClientWritable, and it is also where a refused edit is shown to the person, throughLiveMutationRefusals.onRefused(...). Type more than eighty characters into that box to watch a refusal happen — the model caps it there, the server puts the box back, and the reason appears above it.components-showcaseusesBinder; everything else usesbindValue. These are two different tools, not rivals — see Forms and binding.components-showcasebroadcasts to topics nothing subscribes to. It uses the low-levelWasmRmiServerEngine.broadcastPush(String, Object)rather than a typedEventTopic, and no client registers a listener. Do not copy that pattern; useEventTopicandServerEvents.onaschat-eventsdoes.