### Run the example on any OS Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/components-showcase/README.md Start the server manually using the Java classpath. ```bash cd zerozstack-examples/components-showcase/showcase-server java -cp "target/classes;target/libs/*" com.zeroz4j.example.server.ExampleServer ``` -------------------------------- ### Run Example Server Source: https://github.com/zeroz4j/zerozstack/blob/main/AGENTS.md The required command to launch an example server, ensuring the classpath includes all necessary dependencies. ```bash cd zerozstack-examples/todo-signals/todo-signals-server java -cp "target/classes;target/libs/*" com.zeroz4j.example.server.ExampleServer # ';' on Windows, ':' on POSIX ``` -------------------------------- ### Run Example Server Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/examples/index.md Commands to launch the example server on different operating systems. ```bat cd zerozstack-examples\todo-signals run.bat ``` ```bash cd zerozstack-examples/todo-signals/todo-signals-server java -cp "target/classes;target/libs/*" com.zeroz4j.example.server.ExampleServer ``` -------------------------------- ### Build ZeroZStack Examples Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/examples/index.md Compile the project from the repository root before running any examples. ```bash mvn clean install -DskipTests ``` -------------------------------- ### Run the example on Windows Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/components-showcase/README.md Execute the run script from the components-showcase directory. ```bat cd zerozstack-examples\components-showcase run.bat ``` -------------------------------- ### Project structure overview Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/components-showcase/README.md Directory layout of the components-showcase example. ```text components-showcase/ ├─ showcase-shared/ models and @RmiService interfaces ├─ showcase-client/ │ └─ .../client/ │ ├─ ExampleClientApp.java entry point — Zeroz4jClient.connect(...) │ ├─ MainLayout.java navigation, theme toggle, signal-driven view swapping │ ├─ ShowcaseView.java hosts the selected component showcase │ ├─ DashboardView.java landing view │ ├─ ProfileView.java Binder-based data binding │ ├─ AdminView.java role-gated view │ ├─ HtmlExampleView.java HTML-template alternative │ └─ showcase/ ComponentShowcase base class, ShowcaseRegistry, 54 panels └─ showcase-server/ Helidon server, EclipseStore boilerplate ``` -------------------------------- ### Launch the Server Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/form-signup/README.md Commands to build the project and start the server application. ```bash mvn install -DskipTests cd zerozstack-examples/form-signup/form-signup-server mvn exec:java -Dexec.mainClass="com.zeroz4j.example.server.ExampleServer" ``` -------------------------------- ### Clone and build the project Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/start/quickstart.md Downloads the repository and compiles the framework and examples using Maven. ```bash git clone https://github.com/ZeroZ4j/zerozstack.git cd zeroz4j mvn clean install -DskipTests ``` -------------------------------- ### Build and run the project Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/GETTING_STARTED.md Commands to compile the project and start the Helidon-based server. ```bash cd myapp mvn clean install ``` ```bash java -jar myapp-server/target/myapp-server-1.0.0-SNAPSHOT.jar ``` -------------------------------- ### Run Backend Server Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/inventory-crud/README.md Command to start the Helidon-based backend server. ```bash cd zerozstack-examples/inventory-crud/inventory-crud-server java -jar target/inventory-crud-server-1.0.0-SNAPSHOT.jar ``` -------------------------------- ### ZeroZ DB server configuration properties Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/store-modes.md Example configuration file defining network settings, storage paths, and security credentials. ```properties port = 5150 bindAddress = 0.0.0.0 secret = ${DB_SECRET} schemaId = myapp-v3 durability = SYNC store.acme.dir = /data/acme store.acme.root = com.example.Catalog console.port = 8090 console.password = ${CONSOLE_PASSWORD} ``` -------------------------------- ### Metrics-Live Task Specification Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/AGENT_PROMPTS.md The specification for the metrics-live example, detailing the data model, RMI service, server-side ticker, and client-side rendering requirements. ```text TASK: Build the example "metrics-live" under zerozstack-examples/metrics-live. Reference example to copy: zerozstack-examples/chat-livesync. A live server-metrics dashboard, fed by a fake metrics source: - Shared model LiveMetrics (@LiveSync @DataModel): cpuPercent (int), requestsPerSecond (int), activeUsers (int), lastUpdated (long), plus a List of the last 30 cpu samples for a sparkline. - @RmiService MetricsService { LiveMetrics getMetrics(); }. - Server: an @ApplicationScoped MetricsTicker that starts a virtual thread on first use (or eagerly) and every 2 seconds writes plausible drifting fake values into the LiveMetrics instance held in the DataRoot, appends the cpu sample (cap the list at 30), then calls syncEngine.notifyChanged(metrics) — exactly the pattern chat-livesync's ChatServiceImpl uses after mutations. - Client: fetch LiveMetrics once via RMI, keep the reference, and render it into KpiTile/Stat components, a RadialProgress for cpu, and a Sparkline for the history. The framework updates the OBJECT'S FIELDS IN PLACE when the server notifies — there is no callback hook in this example, so re-render on a simple client-side interval (a background thread loop with Thread.sleep(1000) that re-reads the fields and updates the components). Note this honestly in the README: LiveSync moves the DATA automatically; re-rendering is the app's job. - Two browser windows must show the same numbers changing in step. ACCEPTANCE: - mvn install passes from the root. - Numbers and sparkline update continuously in the browser with NO RMI calls after the initial getMetrics() (verify: network tab shows only WebSocket frames). - README contrasts this style with job-monitor's explicit events in 2–3 sentences. ``` -------------------------------- ### Resolve Maven module resolution failures Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/guides/troubleshooting.md Install the project locally before running tests to ensure annotation processors and shared APIs are available. ```bash mvn clean install -DskipTests mvn test ``` -------------------------------- ### Interact with shared signals Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/decide/events-vs-signals-vs-livesync.md Use set() on the server to broadcast updates and get() on the client to react to changes. ```java // server — the entire propagation story JobSignals.STATUS.set(new JobStatus(percent, step)); ``` ```java // client — indistinguishable from a local signal Effect.create(() -> progressBar.setValue(JobSignals.STATUS.get().getPercent())); ``` -------------------------------- ### Build documentation locally Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/contribute/docs-style-guide.md Commands to set up a virtual environment and serve the documentation site. ```bash python -m venv .venv .venv/Scripts/activate # or: source .venv/bin/activate pip install -r docs/requirements.txt mkdocs serve ``` -------------------------------- ### Build the project Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/job-monitor/README.md Build the reactor from the repository root before running the server. ```bash mvn install ``` -------------------------------- ### Build Project Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/inventory-crud/README.md Command to compile the entire project from the repository root. ```bash mvn clean install ``` -------------------------------- ### Application Initialization Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/chat-events/chat-events-client/src/main/resources/public/index.html Invokes the main application entry point. ```javascript main(); ``` -------------------------------- ### Build and run the generated application Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/start/quickstart.md Compiles the project and executes the server application class. ```bash cd myapp mvn clean install cd myapp-server java -cp "target/classes;target/libs/*" com.example.myapp.server.ServerApp ``` -------------------------------- ### Inventory CRUD Task Specification Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/AGENT_PROMPTS.md Defines the functional requirements and architecture for the inventory-crud example, including data models, RMI service definitions, and UI layout expectations. ```text TASK: Build the example "inventory-crud" under zerozstack-examples/inventory-crud. Reference example to copy: zerozstack-examples/todo-signals. A small warehouse inventory manager: - Shared model Product (@DataModel): id (long), name, category (String), quantity (int), unitPrice (double). Server assigns ids from a counter stored in the DataRoot (persist the counter too). - @RmiService ProductService { List list(); Product save(Product p); void delete(long id); } — save() creates when id == 0, else updates; every mutation persists via storage.store(...). - Client, master-detail layout (HorizontalLayout or SplitPane): * master: a Table of products (name, category, quantity, price) plus a TextField filter; hold products and the filter in ValueSignals, derive the filtered rows and a Stat/KpiTile header (product count, total stock value) via Computed, render via Effects; * detail: an edit form (TextFields, Select for category from a fixed list) that fills when a row is selected; New / Save / Delete buttons calling the service on background threads, then refreshing the products signal from the server's return value. - Show an EmptyState component when the (filtered) list is empty. ACCEPTANCE: - mvn install passes from the root. - Create, edit, delete round-trips update the table and the header stats without any manual "refresh" beyond re-setting the products signal. - Data survives a server restart. The same Product class is used in storage, on the wire, and in the UI — verify no mapping code exists anywhere. ``` -------------------------------- ### Run the ZeroZ DB server Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/store-modes.md Execute the server using the specified classpath and configuration file. ```bash java -cp zeroz4j-db.jar:my-app.jar org.zeroz4j.db.server.ZeroZDbServerMain server.properties ``` -------------------------------- ### Run the server Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/job-monitor/README.md Execute the server application from the job-monitor-server directory. ```bash cd zerozstack-examples/job-monitor/job-monitor-server mvn exec:java -Dexec.mainClass="com.zeroz4j.example.server.ExampleServer" ``` -------------------------------- ### Build and Run Todo Signals Server Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/todo-signals/README.md Commands to build the project and execute the server application from the terminal. ```bash mvn install -DskipTests cd zerozstack-examples/todo-signals/todo-signals-server mvn exec:java -Dexec.mainClass="com.zeroz4j.example.server.ExampleServer" ``` -------------------------------- ### Build and Run Chat Events Server Source: https://github.com/zeroz4j/zerozstack/blob/main/zerozstack-examples/chat-events/README.md Commands to build the project and execute the server application from the command line. ```bash mvn install -DskipTests cd zerozstack-examples/chat-events/chat-events-server mvn exec:java -Dexec.mainClass="com.zeroz4j.example.server.ExampleServer" ``` -------------------------------- ### Scaffold a new project with Maven Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/GETTING_STARTED.md Use the provided Maven archetype to generate a multi-module project structure. ```bash mvn archetype:generate \ -DarchetypeGroupId=com.zeroz4j \ -DarchetypeArtifactId=zerozstack-archetype \ -DarchetypeVersion=1.0.0-SNAPSHOT \ -DgroupId=com.mycompany \ -DartifactId=myapp \ -Dversion=1.0.0-SNAPSHOT ``` -------------------------------- ### Constructing Basic Layouts in Java Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/UI_COMPONENTS.md Demonstrates nesting components and sub-layouts within a main VerticalLayout container. ```java // Create a main vertical layout VerticalLayout mainLayout = new VerticalLayout(); // Create a title and add it to the main layout CardTitle title = new CardTitle("User Registration"); mainLayout.add(title); // Create a form layout for inputs FormLayout formLayout = new FormLayout(); TextField nameField = new TextField("Name"); TextField emailField = new TextField("Email"); // Add components to the form layout formLayout.add(nameField, emailField); // Create a horizontal layout for actions HorizontalLayout actionsLayout = new HorizontalLayout(); Button submitButton = new Button("Submit"); Button cancelButton = new Button("Cancel"); // Add buttons to the horizontal layout actionsLayout.add(submitButton, cancelButton); // Attach the nested layouts to the main layout mainLayout.add(formLayout, actionsLayout); ``` -------------------------------- ### Implement the client UI Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/GETTING_STARTED.md Invoke backend services directly from UI components using binary WebSockets. ```java import com.zeroz4j.ui.components.Button; import com.zeroz4j.ui.components.Div; public class ChatView extends Div { public ChatView(ChatService chatService) { Button sendBtn = new Button("Send Hello"); sendBtn.onClick(event -> { // Suspends cooperatively, calls backend over binary WebSocket chatService.sendMessage(new ChatMessage("Alice", "Hello World!")); }); add(sendBtn); } } ``` -------------------------------- ### Scaffold a new project with Maven Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/start/quickstart.md Generates a three-module project layout including TeaVM, annotation processor, and Helidon. ```bash mvn archetype:generate \ -DarchetypeGroupId=com.zeroz4j \ -DarchetypeArtifactId=zerozstack-archetype \ -DarchetypeVersion=0.4.0 \ -DgroupId=com.example \ -DartifactId=myapp \ -Dversion=1.0.0-SNAPSHOT ``` -------------------------------- ### Implement the server backend Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/GETTING_STARTED.md Implement the service interface using CDI annotations to handle incoming requests. ```java import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import com.zeroz4j.db.net.ZeroZDbNode; @ApplicationScoped public class ChatServiceImpl implements ChatService { @Inject private ZeroZDbNode db; @Override public void sendMessage(ChatMessage msg) { // Automatically persist or broadcast! System.out.println("Received: " + msg.getText()); // Example: save to your data root graph, atomically // db.localDb().write(ctx -> { ctx.edit(root.getMessages()); root.getMessages().add(msg); }); // root.getMessages().add(msg); // storage.store(root.getMessages()); } } ``` -------------------------------- ### Build and Test Commands Source: https://github.com/zeroz4j/zerozstack/blob/main/AGENTS.md Standard Maven commands for building and testing the project. Always use clean to avoid duplicate bean errors from accumulated dependencies. ```bash mvn clean install -DskipTests # from the repository root mvn test # then tests ``` -------------------------------- ### Implement Client-Side Application Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/CODE_WALKTHROUGH.md Initialize the WebSocket connection and use generated stubs to perform RMI calls. Note that this specific bootstrap pattern is considered obsolete in newer versions. ```java import com.zeroz4j.client.WasmRmiClient; import com.zeroz4j.client.WasmRmiClientChannel; import com.zeroz4j.generated.BinaryPackableRegistrar; public class ClientApplication { public static void main(String[] args) { // 1. Register generated serializers BinaryPackableRegistrar.registerAll(); // 2. Open WebSocket Channel WasmRmiClientChannel channel = new WasmRmiClientChannel("ws://localhost:8080/wasm-rmi", () -> { System.out.println("Connection opened!"); }); WasmRmiClient.initialize(channel); // 3. Obtain Service Stub UserService service = new UserService_Stub(); // Generated implementation // 4. Invoke RMI calls seamlessly UserInfo profile = service.getUserInfo("franz"); System.out.println("User Profile: " + profile); } } ``` -------------------------------- ### zeroboard Task Specification Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/AGENT_PROMPTS.md The formal task requirements for implementing the zeroboard capstone project. ```text TASK: Build the capstone example "zeroboard" under zerozstack-examples/zeroboard. Reference examples: copy zerozstack-examples/chat-events for structure; study todo-signals for the client state model before writing the UI. A multi-user kanban board ("zeroboard") with three fixed columns: Backlog, In Progress, Done. Shared module: - CardItem (@DataModel): id, title, column (String), createdBy, createdAt. Value-based equals/hashCode. - BoardEvents: EventTopic CARD_UPSERTED ("board.cardUpserted"), EventTopic CARD_DELETED ("board.cardDeleted") — deleting broadcasts the id. - @RmiService @Secured BoardService: * List getBoard(); * CardItem addCard(String title); // into Backlog, server ids * CardItem moveCard(long id, String targetColumn); // validate target column * @RolesAllowed("admin") void deleteCard(long id); Server (single BoardServiceImpl): - EclipseStore persistence via the DataRoot pattern; server-assigned ids from a persisted counter; createdBy from RmiRequestContext.getPrincipal(). - After every successful mutation, persist, then publish the matching event via the injected EventPublisher. Reject moves to unknown columns. Client (this is where the composition shows — follow it exactly): - State: ONE ValueSignal> cards is the single source of truth, plus ValueSignal searchText. - Events feed the state: subscribe to CARD_UPSERTED (reduce: replace-by-id or append, immutably) and CARD_DELETED (reduce: remove-by-id) BEFORE calling getBoard(), then merge the snapshot (dedupe by id, keep the newer of duplicates). Own mutations do NOT update state directly — the echoed event is the single update path, so every window (including your own) renders identically. - Derived state: Computed per column (filtered by column + searchText match) and a Computed count per column shown as a Badge in the column header. - Rendering: three columns (GridLayout or HorizontalLayout of Cards); each card shows title + createdBy and Buttons to move left/right (no drag & drop); an add-card TextField+Button; a search TextField bound to searchText; admins additionally see a delete Button per card (RmiSecurityContext.hasAnyRole). - All rendering via Effects; full dispose() for subscriptions, effects, computeds. ACCEPTANCE: - mvn install passes from the root. - Two browser windows: adding/moving a card in one appears in the other (and in the acting window itself) via the event echo — there is no direct local-state write in any button handler. - Search filters all three columns live; column counts always match visible cards. - Non-admins see no delete buttons, and a forced deleteCard() is rejected server-side. - README explains the event-echo pattern and why it guarantees convergence. ``` -------------------------------- ### Verify Release Build Source: https://github.com/zeroz4j/zerozstack/blob/main/RELEASING.md Performs a full build and signing process without uploading to the repository, useful for pre-deployment verification. ```bash mvn clean verify -Prelease -DskipTests ``` -------------------------------- ### Implement service using ZeroZDbNode Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/store-modes.md Inject ZeroZDbNode to execute commands and queries, ensuring code compatibility across different storage modes. ```java @ApplicationScoped public class ProductService { @Inject ZeroZDbNode db; public long add(String name) { return db.execute(new AddProduct(name)); } public int count() { return db.query(new CountProducts()); } } ``` -------------------------------- ### Configure context7.json for ZeroZ4j Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/contribute/documentation-plan.md Defines the project scope, file exclusions, and architectural rules for the Context7 documentation crawler. Ensure the rules array remains synchronized with the human-readable agents/rules.md file. ```json { "$schema": "https://context7.com/schema/context7.json", "projectTitle": "ZeroZ4j", "description": "Pure-Java full-stack framework: Java UI compiled to WebAssembly via TeaVM, binary RPC over WebSocket, and EclipseStore object-graph persistence. No JavaScript, JSON, REST or ORM.", "folders": ["docs/**", "zerozstack-examples/**"], "excludeFolders": ["target", ".idea", ".github", "zerozstack-archetype/target"], "excludeFiles": ["CHANGELOG.md", "CODE_OF_CONDUCT.md", "LICENSE", "NOTICE"], "rules": [ "Requires JDK 21 or later. Client code compiles to WebAssembly with TeaVM; only TeaVM-supported JDK APIs are available on the client.", "Every type crossing the wire must be annotated @DataModel and have a public no-arg constructor plus getters and setters.", "Declare RMI contracts as @RmiService interfaces in the shared module; implement them as @ApplicationScoped CDI beans in the server module.", "Choose the propagation mechanism deliberately: local ValueSignal for client-only state, RMI for named operations and request/response, EventTopic for discrete occurrences with no retained value, Signals.shared for one current value that late joiners must see, @LiveSync for an identified object edited field by field.", "Never carry state in server events: events have no retained value and no replay, so a client connecting later sees nothing. Use Signals.shared instead.", "Never mutate a signal's value in place. ValueSignal.set skips notification when the new value equals the old one; use update() and return a new instance.", "Client writes are denied by default. Opt in explicitly with Signals.sharedWritable or @ClientWritable; the server stays authoritative and re-validates every mutation.", "Model operations such as approve, checkout or delete as RMI methods, not as LiveSync field edits. State edits sync, operations call.", "Dispose what you create: Effect.create and ServerEvents.on return a Disposable that a view must release when it is removed.", "Events and shared signals broadcast to every connected session with no principal or tenant filter, so never push per-user or sensitive data through them. Only LiveSync can scope a push, via SyncEngine.notifyChanged(obj, SyncScope.SESSION or USER, target).", "SyncEngine.notifyChanged does nothing unless the object has already been serialized to a client, so return it from an RMI call at least once before relying on sync.", "LiveSync updates an object's fields in place but does not notify the view. Copy the object into a signal on a timer, or bridge via an event, to trigger re-rendering.", "Client-side UI code runs on a cooperative scheduler. Never create a java.lang.Thread in client code; RMI calls suspend and resume on their own.", "Do not mutate a shared or live object in place through a collection getter. Setters are the tracking boundary; reassign via the setter or call LiveMutationTracker.touch(obj).", "ZeroZ4j is an experimental proof-of-concept, currently version 0.3.0." ] } ``` -------------------------------- ### Execute commands and queries via ZeroZDbNode Source: https://github.com/zeroz4j/zerozstack/blob/main/AGENTS.md Use execute and query methods on the injected ZeroZDbNode to perform operations that run where the data resides. ```java @Inject ZeroZDbNode db; long id = db.execute(new AddProduct("Laptop stand")); int total = db.query(new CountProducts()); ``` -------------------------------- ### Common Context Prompt for AI Agents Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/AGENT_PROMPTS.md Paste this block into an AI agent before providing a specific task to establish the Zeroz4j development environment and architectural constraints. ```text You are implementing a new example application for Zeroz4j, a zero-impedance Java web framework: one language (Java 21) end-to-end — the client UI compiles to Wasm/JS via TeaVM, the server runs on Helidon with CDI, and the SAME POJOs travel from EclipseStore persistence through RMI to the browser. No REST, no JSON, no DTOs, no JavaScript, no SQL. Before writing any code, read these files in the repository: - docs/decide/index.md (WHICH construct to use — read this first) - docs/decide/antipatterns.md (named failure modes to avoid) - docs/SIGNALS.md (reactive state: local and shared) - docs/SERVER_EVENTS.md (typed server-to-client events) - docs/VALIDATION.md (model annotations enforced on both tiers) - docs/guides/troubleshooting.md (this framework fails silently — know how) - the README.md and full source of the REFERENCE EXAMPLE named in the task Method — follow it exactly: 1. Copy the reference example's directory tree under zerozstack-examples/ to the new example name given in the task (copy the pom.xml files as-is, then rename the artifactIds and module names consistently). Do NOT write poms from scratch. 2. Register the new module in zerozstack-examples/pom.xml. 3. Keep the copied structure: -shared (models + @RmiService interfaces), -client (Wasm UI), -server (Helidon server, EclipseStore boilerplate under .../server/store/). 4. Replace the domain code with the task's spec. Package conventions: com.zeroz4j.example.model / .api / .client / .server 5. Update the in both index.html files (client resources and server webapp). 6. Write a README.md for the example: what it demonstrates, how to run it. ``` -------------------------------- ### Implementing a form with Binder Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/guides/ui-forms-and-validation.md Uses a Binder to manage POJO state and validation, while tracking form dirty state via a ValueSignal. ```java Binder<Product> binder = new Binder<>(); // the entity being edited ValueSignal<Boolean> dirty = new ValueSignal<>(false); // view state others react to binder.forField(nameField) .withRule(Product_Rules.name()) .bind(Product::getName, Product::setName); binder.readBean(selected); // buffered nameField.addValueChangeListener(e -> dirty.set(binder.hasChanges())); Effect.create(() -> saveButton.setEnabled(dirty.get())); ``` -------------------------------- ### Scaffold Project with Maven Archetype Source: https://github.com/zeroz4j/zerozstack/blob/main/README.md Generate a new multi-module project structure using the zerozstack-archetype. ```bash mvn archetype:generate -DarchetypeGroupId=com.zeroz4j -DarchetypeArtifactId=zerozstack-archetype -DarchetypeVersion=0.4.0 ``` -------------------------------- ### Invoke Service from Client Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/index.md Demonstrates calling the service from the client-side code. The call is non-blocking and compiled to JavaScript via TeaVM. ```java // client — Java, compiled by TeaVM. The call suspends; it does not block. ChatService chat = new ChatService_Stub(); sendButton.addClickListener(e -> chat.sendMessage(new ChatMessage(author, text))); ``` -------------------------------- ### Publish to Maven Central Source: https://github.com/zeroz4j/zerozstack/blob/main/RELEASING.md Executes the release profile to build, sign, and upload artifacts to the Maven Central portal. ```bash mvn clean deploy -Prelease ``` -------------------------------- ### Implement a DbCommand Source: https://github.com/zeroz4j/zerozstack/blob/main/AGENTS.md Define a command class by implementing DbCommand, ensuring a no-arg constructor exists for deserialization and using WriteContext to enlist objects before mutation. ```java public class AddProduct implements DbCommand<Long> { public String name; public AddProduct() { } // needed for deserialisation public AddProduct(String name) { this.name = name; } @Override public Long execute(WriteContext ctx, Object root) { Catalog catalog = (Catalog) root; ctx.edit(catalog); // the counter is about to change ctx.edit(catalog.getProducts()); // and so is the list long id = catalog.getNextId(); catalog.setNextId(id + 1); catalog.getProducts().add(new Product(id, name)); return id; // both land in ONE commit } } ``` -------------------------------- ### Configure client storage mode Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/store-modes.md Set the storage mode to CLIENT and provide connection details for a remote database server. ```properties zeroz4j.store.mode = CLIENT zeroz4j.store.server.host = db.internal zeroz4j.store.server.port = 5150 zeroz4j.store.server.secret = ${DB_SECRET} zeroz4j.store.schemaId = myapp-v3 ``` -------------------------------- ### Initialize LiveSync via RMI Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/decide/rmi-vs-state-sync.md Establish an object handle for LiveSync by calling an RMI getter, which allows the server to track and notify the client of changes. ```java liveState = chatService.getState(); // RMI — establishes the handle // from here, syncEngine.notifyChanged(state) on the server reaches this client ``` -------------------------------- ### Register the AuthenticationProvider Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/guides/security-auth.md Register the custom provider implementation in the META-INF/services directory to enable it via ServiceLoader. ```text com.example.auth.JwtAuthProvider ``` -------------------------------- ### Attach a click listener with synchronous server call Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/UI_COMPONENTS.md Demonstrates how to perform a blocking RPC call within a button click listener without manual threading or callbacks. ```java Button saveButton = new Button("Save Profile"); saveButton.addClickListener(event -> { // 1. DOM Event listener triggered on click. // This is already running inside a TeaVM virtual thread! saveButton.setEnabled(false); saveButton.setText("Saving..."); try { // 2. Call server method synchronously via an RPC stub. // The virtual thread will safely suspend here without freezing the UI! boolean success = userService.saveUserProfile(profile); // 3. Resumes execution here once the server responds if (success) { saveButton.setText("Saved Successfully!"); } else { saveButton.setText("Save Failed"); } } catch (Exception e) { // Handle network or server errors saveButton.setText("Error Occurred"); } finally { saveButton.setEnabled(true); } }); ``` -------------------------------- ### Implement Server-Side Service Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/index.md Implements the service contract as a CDI bean on the server. Uses dependency injection for event publishing. ```java // server — an ordinary CDI bean @ApplicationScoped public class ChatServiceImpl implements ChatService { @Inject private EventPublisher events; @Override public void sendMessage(ChatMessage msg) { events.publish(ChatEvents.MESSAGE_POSTED, msg); } } ``` -------------------------------- ### Initialize a shared signal Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/decide/local-vs-shared-signal.md Use Signals.shared for state that must be consistent across all clients. ```java public final class JobSignals { public static final ValueSignal<JobStatus> STATUS = Signals.shared(JobStatus.idle()); } ``` -------------------------------- ### Use shared signals across tiers Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/SIGNALS.md Shows how to set a shared signal value on the server and observe it on the client. ```java // server — the whole propagation story: JobSignals.STATUS.set(next); // client — indistinguishable from a local signal: Effect.create(() -> progressBar.setValue(JobSignals.STATUS.get().getPercent())); ``` -------------------------------- ### Implement Server Persistence with EclipseStore Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/CODE_WALKTHROUGH.md Use ZeroZDbNode to interact with the object graph directly via Java streams and explicitly persist changes using the storage manager. ```java import jakarta.enterprise.context.ApplicationScoped; import com.zeroz4j.db.net.ZeroZDbNode; import jakarta.inject.Inject; @ApplicationScoped public class UserServiceImpl implements UserService { @Inject private ZeroZDbNode db; private DataRoot getRoot() { return (DataRoot) db.localDb().root(); } @Override public UserInfo getUserInfo(String username) { // Querying is just Java stream operations over the stored object graph return getRoot().getUsers().stream() .filter(u -> u.getName().equals(username)) .findFirst() .orElse(null); } @Override public void updateScore(String username, int newScore) { UserInfo user = getRoot().getUsers().stream() .filter(u -> u.getName().equals(username)) .findFirst().orElseThrow(); user.setScore(newScore); // Persist the delta directly! No UPDATE statements. // Saves are explicitly controlled by the developer. storage.store(user); } } ``` -------------------------------- ### Implement a custom AuthenticationProvider Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/guides/security-auth.md Implement the AuthenticationProvider interface to handle handshake credentials and return an AuthenticatedPrincipal. Returning null allows anonymous access, while throwing an exception also results in an anonymous connection. ```java package com.example.auth; import com.zeroz4j.server.AuthenticatedPrincipal; import com.zeroz4j.server.AuthenticationProvider; import com.zeroz4j.server.HandshakeCredentials; public final class JwtAuthProvider implements AuthenticationProvider { @Override public AuthenticatedPrincipal authenticate(HandshakeCredentials credentials) { String token = credentials.parameter("token"); if (token == null) { return null; // no credentials: stay anonymous } Claims claims = verifyOrThrow(token); // your own verification return new AuthenticatedPrincipal(claims.subject(), claims.roles(), claims.tenant()); } } ``` -------------------------------- ### Perform Independent Storage Commits Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/design/persistence-transactions.md Demonstrates the current pattern of calling store() multiple times, which risks data inconsistency if a crash occurs between calls. ```java storage.store(root.getProducts()); storage.store(root); ``` -------------------------------- ### Initialize local signals Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/decide/local-vs-shared-signal.md Use ValueSignal for UI state that should not be shared across sessions. ```java ValueSignal<String> filter = new ValueSignal<>("all"); ValueSignal<Boolean> darkTheme = new ValueSignal<>(true); ``` -------------------------------- ### Subscribing to Server Events on Client Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/SERVER_EVENTS.md Use ServerEvents.on to register a callback for specific events, returning a Disposable to manage the subscription lifecycle. ```java Disposable sub = ServerEvents.on(ChatEvents.MESSAGE_POSTED, msg -> { messages.add(msg); render(); }); ``` -------------------------------- ### Implement LiveMutationListener Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/decide/events-vs-signals-vs-livesync.md Define a persistence layer to handle storage of mutated objects on the server. ```java import com.zeroz4j.server.LiveMutationListener; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager; import java.security.Principal; @ApplicationScoped public class ProfilePersistence implements LiveMutationListener { @Inject EmbeddedStorageManager storage; @Override public void onMutated(Object model, Principal principal) { storage.store(model); } } ``` -------------------------------- ### Initialize Tenant Storage Manager Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/design/persistence-transactions.md Retrieves or creates an EmbeddedStorageManager for a specific tenant using a ConcurrentHashMap. ```java return storageManagers.computeIfAbsent(tenantId, tid -> { Object root = null; if (!dataRootProvider.isUnsatisfied()) { root = dataRootProvider.get().createDefaultRoot(tid); } if (root == null) { root = new Object(); } // Fallback EmbeddedStorageManager manager = EmbeddedStorage.start(root, Paths.get(basePath, tid)); ``` -------------------------------- ### Registering an Object Handle Source: https://github.com/zeroz4j/zerozstack/blob/main/docs/guides/troubleshooting.md Ensure an object is registered by returning it from an RMI method before attempting synchronization. ```java LiveChatState state = chatService.getState(); // this is what registers the handle ```