diff --git a/src/components/landing/code.astro b/src/components/landing/code.astro
index 5f62318..6552879 100644
--- a/src/components/landing/code.astro
+++ b/src/components/landing/code.astro
@@ -7,16 +7,17 @@ const files = [
title: "Command handler",
role: "decides",
code: `// app/domain/order/commands/place-order.ts
-import { DomainError } from "@bounda-dev/core";
import type { Command } from "./+types/place-order";
export const payload = ({ z }: Command.PayloadArgs) =>
z.object({ orderId: z.uuid(), customerId: z.string().min(1), total: z.number().positive() });
-export const handler = ({ command, state, events }: Command.HandlerArgs) => {
- if (state.status !== "new") {
- throw new DomainError(\`Order \${command.aggregateId} was already placed\`);
- }
+export const rejections = ({ command }: Command.RejectionsArgs) => ({
+ AlreadyPlaced: \`Order \${command.aggregateId} was already placed\`,
+});
+
+export const handler = ({ command, state, events, reject }: Command.HandlerArgs) => {
+ if (state.status !== undefined) return reject("AlreadyPlaced");
return [
events.orderPlaced({ customerId: command.payload.customerId, total: command.payload.total }),
];
@@ -24,15 +25,14 @@ export const handler = ({ command, state, events }: Command.HandlerArgs) => {
},
{
title: "Event",
- role: "applies",
+ role: "opens the order",
code: `// app/domain/order/order-placed.ts
import type { Event } from "./+types/order-placed";
export const payload = ({ z }: Event.PayloadArgs) =>
z.object({ customerId: z.string(), total: z.number().positive() });
-export const apply = ({ state, event }: Event.ApplyArgs) => ({
- ...state,
+export const begin = ({ event }: Event.BeginArgs) => ({
status: "placed" as const,
customerId: event.payload.customerId,
total: event.payload.total,
@@ -63,7 +63,7 @@ export const project = async ({ event, table }: Projection.Args) => {
The code
Three files. Their place and name are the declaration.
- A command handler decides, an event applies, a projection writes a row. bounda generate reads the folders and
+ A command handler decides, an event becomes the state, a projection writes a row. bounda generate reads the folders and
infers every type, so there is no registry to keep in sync.
app/
diff --git a/src/components/landing/facts.astro b/src/components/landing/facts.astro
index e45dbc6..2f37350 100644
--- a/src/components/landing/facts.astro
+++ b/src/components/landing/facts.astro
@@ -8,7 +8,7 @@ const facts = [
{
label: "bounda rebuild",
title: "Read models rebuild.",
- body: "Replay the global stream into a fresh read model without touching a single event.",
+ body: "A wrong dashboard is a fixed projection and a rebuild, not a migration script. The events are never touched.",
},
{
label: "Processes and policies",
@@ -18,7 +18,7 @@ const facts = [
{
label: "One database",
title: "Runs where you are.",
- body: "PostgreSQL, SQLite or libSQL, or a Cloudflare Durable Object per tenant. React Router integration and OpenTelemetry.",
+ body: "PostgreSQL, SQLite or libSQL. On Cloudflare, one Durable Object per tenant holds the whole domain, driven by its alarm. React Router integration and OpenTelemetry.",
},
];
---
diff --git a/src/components/landing/hero.astro b/src/components/landing/hero.astro
index eee110f..7127d6d 100644
--- a/src/components/landing/hero.astro
+++ b/src/components/landing/hero.astro
@@ -11,13 +11,13 @@ import Install from "../install.astro";
ceremony.
- Keep every change as an ordered fact. Rebuild any view from it, on one database.
+ Your tables keep the last write. Bounda keeps every change. Rebuild any view from it, on one database.