# Product decisions are the code — Fluxzero

Source: https://fluxzero.io/product-code/

## Product decisions are the code.

You describe features in natural language. Your agent writes their business rules and follow-up actions; Fluxzero handles reliable execution, data protection, and scale underneath.

The examples below use Kotlin and Java: proven backend languages that agents know well. Your code stays focused on the product and easy to extend as it grows.

01 · Making changes

### Only product logic. Working at any scale.

You decide how a feature should work. Fluxzero keeps its rules intact when many customers act at once. The same logic continues to work as usage grows, without engineering work for your agent.

**You write**

Let's build a ticketing system for concerts. Make sure the same ticket can't be booked twice, even when lots of customers book at once.

**Your agent writes** One rule, two changes

```kotlin
data class ReserveTicket(
    @NotNull val reservationId: ReservationId,
    @NotNull val ticketId: TicketId
) {
    @AssertLegal
    fun assertAvailable(ticket: Ticket) {
        if (ticket.status != AVAILABLE) {
            throw TicketErrors.notAvailable
        }
    }

    @Apply
    fun reserve(ticket: Ticket) =
        ticket.copy(status = RESERVED)

    @Apply
    fun createReservation(user: User) =
        Reservation.awaitingPayment(
            reservationId, ticketId, user.id())
}
```

```java
record ReserveTicket(
    @NotNull ReservationId reservationId,
    @NotNull TicketId ticketId) {

    @AssertLegal
    void assertAvailable(Ticket ticket) {
        if (ticket.status() != AVAILABLE) {
            throw TicketErrors.notAvailable;
        }
    }

    @Apply
    Ticket reserve(Ticket ticket) {
        return ticket.withStatus(RESERVED);
    }

    @Apply
    Reservation createReservation(User user) {
        return Reservation.awaitingPayment(
            reservationId, ticketId, user.id());
    }
}
```

- **State loads automatically:** Fluxzero provides the product state and which customer is making the change.
- **Everything changes together:** If something changes while the rule runs, it runs again before the changes are saved.
- **Many people, one safe result:** Each decision is kept correct even when many customers act at once.

02 · Keeping track

### Your product changes. Its history stays.

Your agent models the parts of your product and how they fit together. Fluxzero keeps the information up to date and preserves its history. Your app can use that history directly in its features.

**You write**

I'd like to keep a history of our concerts and reservations.

**Your agent writes** Concerts, tickets & reservations

```kotlin
@Model
data class Show(
    @EntityId val showId: ShowId,
    val name: String,
    val status: ShowStatus
)
```

```kotlin
@Model(searchable = true)
data class Ticket(
    @EntityId val ticketId: TicketId,
    @Parent(pathInParent = "tickets")
    val showId: ShowId,
    val details: TicketDetails,
    val status: TicketStatus
)
```

```kotlin
@Model
data class Reservation(
    @EntityId val reservationId: ReservationId,
    @Parent(pathInParent = "reservations")
    val ticketId: TicketId,
    val customerId: String,
    val status: ReservationStatus,
    @ProtectData val contactEmail: String?
)
```

```java
@Model
record Show(
    @EntityId ShowId showId,
    String name,
    ShowStatus status) {}
```

```java
@Model(searchable = true)
record Ticket(
    @EntityId TicketId ticketId,
    @Parent(pathInParent = "tickets")
    ShowId showId,
    TicketDetails details,
    @With TicketStatus status) {}
```

```java
@Model
record Reservation(
    @EntityId ReservationId reservationId,
    @Parent(pathInParent = "reservations")
    TicketId ticketId,
    String customerId,
    @With ReservationStatus status,
    @With @ProtectData String contactEmail) {}
```

- **Keep track of everything:** Each part of the product is tracked along with its relationships.
- **Stored automatically:** Your agent’s code needs no storage logic. The information is loaded and saved automatically.
- **History preserved:** Fluxzero keeps every previous state of the product available.

03 · Testing behavior

### Know it works. Before customers use it.

Tests are part of every feature your agent builds. You describe the behavior; your agent writes the code and tests together. Fluxzero lets those tests run complete flows, including time passing, so they keep checking the feature as your product changes.

**You write**

A booking is only confirmed once the customer has paid.

**Your agent writes** Behavior tested end-to-end

```kotlin
@Test
fun reservationIsLostWhenPaymentIsLate() {
    fixture
        .whenPostByUser("customer-42",
            "/api/reservations", "/ticketing/reserve.json")
        .expectEvents(ReserveTicket::class)
        .andThen()
        .whenTimeElapses(Duration.ofMinutes(15))
        .expectEvents(ExpireReservation::class)
}

@Test
fun reservationIsConfirmedWhenPaymentIsOnTime() {
    fixture
        .givenCommandsByUser("customer-42",
            "/ticketing/reserve-ticket.json")
        .whenEvent("/payments/payment-succeeded.json")
        .expectEvents("/ticketing/confirm-reservation.json")
        .andThen()
        .whenTimeElapses(Duration.ofMinutes(15))
        .expectNoEvents()
}
```

```java
@Test
void reservationIsLostWhenPaymentIsLate() {
    fixture
        .whenPostByUser("customer-42",
            "/api/reservations", "/ticketing/reserve.json")
        .expectEvents(ReserveTicket.class)
        .andThen()
        .whenTimeElapses(Duration.ofMinutes(15))
        .expectEvents(ExpireReservation.class);
}

@Test
void reservationIsConfirmedWhenPaymentIsOnTime() {
    fixture
        .givenCommandsByUser("customer-42",
            "/ticketing/reserve-ticket.json")
        .whenEvent("/payments/payment-succeeded.json")
        .expectEvents("/ticketing/confirm-reservation.json")
        .andThen()
        .whenTimeElapses(Duration.ofMinutes(15))
        .expectNoEvents();
}
```

- **Production behavior:** The scenario runs through the same rules as the real application.
- **Included with the feature:** Your agent adds the tests as it builds. You don’t need to ask for them separately.
- **Visible outcome:** Success and expected rejections are checked without infrastructure or mocks.

04 · Finding information

### Your data comes ready to search.

Tell your agent what information a feature needs and who may see it. Fluxzero keeps your data and its relationships searchable as the product changes, without a separate search system for your agent to build and maintain.

**You write**

I'd like to find available tickets by concert and section.

**Your agent writes** Query and search

```kotlin
data class FindAvailableTickets(
    @NotNull val showId: ShowId,
    @NotBlank val section: String
) {
    @HandleQuery
    fun handle(): List<Ticket> =
        Fluxzero.search(Ticket::class.java)
            .whereParent(showId)
            .match(AVAILABLE, "status")
            .match(section, "details/section")
            .sortBy("details/row")
            .fetch(50)
}
```

```java
record FindAvailableTickets(
    @NotNull ShowId showId,
    @NotBlank String section) {

    @HandleQuery
    List<Ticket> handle() {
        return Fluxzero.search(Ticket.class)
            .whereParent(showId)
            .match(AVAILABLE, "status")
            .match(section, "details/section")
            .sortBy("details/row")
            .fetch(50);
    }
}
```

- **Search maintained automatically:** Searchable data stays up to date as your product changes.
- **Relationships already known:** Fluxzero follows the connections in your product data to find what belongs together.
- **Work done in the cloud:** Filtering and sorting happen in the cloud. Your product receives the results it asked for.

05 · Set a schedule

### Your product follows up. Even after a restart.

Scheduling is part of almost every app. Fluxzero makes it easy to schedule and test what should happen later. Scheduled work survives restarts and deployments, with your rules checked when it runs.

**You write**

Give people 15 minutes to pay for their tickets.

**Your agent writes** Schedule, cancel and expire a reservation

```kotlin
@Component
class ReservationTimers {
    @HandleEvent
    fun start(event: ReserveTicket) {
        Fluxzero.scheduleCommand(
            ExpireReservation(event.reservationId),
            ScheduleId.of("expire", event.reservationId),
            Duration.ofMinutes(15))
    }

    @HandleEvent
    fun stop(event: ConfirmReservation) {
        Fluxzero.cancelSchedule(
            ScheduleId.of("expire", event.reservationId))
    }
}
```

```kotlin
data class ExpireReservation(
    @NotNull val reservationId: ReservationId
) {
    @AssertLegal
    fun assertAwaitingPayment(reservation: Reservation) {
        if (reservation.status != AWAITING_PAYMENT) {
            throw ReservationErrors.notAwaitingPayment
        }
    }

    @Apply
    fun remove(reservation: Reservation): Reservation? = null

    @Apply
    fun release(ticket: Ticket) =
        ticket.copy(status = AVAILABLE)
}
```

```java
@Component
class ReservationTimers {
    @HandleEvent
    void start(ReserveTicket event) {
        Fluxzero.scheduleCommand(
            new ExpireReservation(event.reservationId()),
            ScheduleId.of("expire", event.reservationId()),
            Duration.ofMinutes(15));
    }

    @HandleEvent
    void stop(ConfirmReservation event) {
        Fluxzero.cancelSchedule(
            ScheduleId.of("expire", event.reservationId()));
    }
}
```

```java
record ExpireReservation(@NotNull ReservationId reservationId) {

    @AssertLegal
    void assertAwaitingPayment(Reservation reservation) {
        if (reservation.status() != AWAITING_PAYMENT) {
            throw ReservationErrors.notAwaitingPayment;
        }
    }

    @Apply
    Reservation remove(Reservation reservation) {
        return null;
    }

    @Apply
    Ticket release(Ticket ticket) {
        return ticket.withStatus(AVAILABLE);
    }
}
```

- **Scheduled work preserved:** Scheduled actions survive application restarts and deployments.
- **Current rules checked:** Fluxzero loads the latest data and checks whether the scheduled change is still allowed.
- **Cancellation handled:** When payment is confirmed, your app cancels the scheduled expiry so the reservation will no longer time out.

06 · Run a workflow

### Workflows pick up where they left off.

A booking may need to wait for a payment provider before issuing tickets. Your agent defines what happens when payment is confirmed. Fluxzero preserves progress and connects each response to the right process, even after a restart.

**You write**

Let's add payments. They might take a while to come through.

**Your agent writes** Wait for a payment response

```kotlin
@Stateful
data class PaymentProcess(
    @EntityId val reservationId: ReservationId,
    @Association val pspReference: String
) {
    companion object {
        @JvmStatic
        @HandleEvent
        fun start(event: ReserveTicket): PaymentProcess {
            val pspReference = Fluxzero.sendCommandAndWait<String>(
                StartPayment(event.reservationId))
            return PaymentProcess(event.reservationId, pspReference)
        }
    }

    @HandleEvent
    fun complete(event: PaymentSucceeded): PaymentProcess? {
        Fluxzero.sendCommandAndWait<Any>(
            ConfirmReservation(reservationId))
        return null
    }
}
```

```java
@Stateful
record PaymentProcess(
    @EntityId ReservationId reservationId,
    @Association String pspReference) {

    @HandleEvent
    static PaymentProcess start(ReserveTicket event) {
        String pspReference = Fluxzero.sendCommandAndWait(
            new StartPayment(event.reservationId()));
        return new PaymentProcess(
            event.reservationId(), pspReference);
    }

    @HandleEvent
    PaymentProcess complete(PaymentSucceeded event) {
        Fluxzero.sendCommandAndWait(
            new ConfirmReservation(reservationId));
        return null;
    }
}
```

- **Progress preserved:** Each workflow’s progress is preserved, including after a restart.
- **Responses connected:** The reference on an incoming response connects it to the right waiting process.
- **Ready to continue:** Fluxzero loads that process and runs the next step with its saved state.

07 · Access and privacy

### You decide who may do what. Fluxzero enforces it.

You decide which personal details need protection; your agent marks them as private and removable. Fluxzero stores protected values separately, so they can be erased without losing the surrounding history. Your access rules control who can view or change them.

**You write**

We need to be able to erase customers' personal details.

**Your agent writes** Ownership and protected data

```kotlin
@RequiresUser
data class UpdateContactEmail(
    @NotNull val reservationId: ReservationId,
    @NotBlank @Email @ProtectData
    val contactEmail: String
) {
    @AssertLegal
    fun assertOwner(reservation: Reservation, user: User) {
        if (reservation.customerId != user.id()) {
            throw ReservationErrors.notOwner
        }
    }

    @Apply
    fun update(reservation: Reservation) =
        reservation.copy(contactEmail = contactEmail)
}
```

```java
@RequiresUser
record UpdateContactEmail(
    @NotNull ReservationId reservationId,
    @NotBlank @Email @ProtectData
    String contactEmail) {

    @AssertLegal
    void assertOwner(Reservation reservation, User user) {
        if (!reservation.customerId()
                .equals(user.id())) {
            throw ReservationErrors.notOwner;
        }
    }

    @Apply
    Reservation update(Reservation reservation) {
        return reservation.withContactEmail(contactEmail);
    }
}
```

- **Identity supplied:** Your rule receives the authenticated customer making the change.
- **Access checked first:** When sign-in is required, unauthenticated requests are rejected before the feature runs.
- **Private data stays erasable:** Fluxzero stores protected values separately, so they can be erased while the surrounding history remains.

08 · Reach in through the web

### Public web endpoints. Private applications.

Your web endpoints live in Fluxzero. Your application has no public endpoint of its own and securely pulls requests when it can handle them. This keeps it out of reach of direct network attacks. Excess traffic waits in Fluxzero instead of flooding the application.

**You write**

Let's make it possible to book from our website.

**Your agent writes** Web request to command

```kotlin
@Component
@Path("/api/reservations")
class ReservationApi {
    @HandlePost
    fun reserve(@Valid request: ReservationRequest): ReservationId {
        val reservationId = Fluxzero.generateId(
            ReservationId::class.java)

        Fluxzero.sendCommandAndWait<Any>(
            ReserveTicket(reservationId, request.ticketId))
        return reservationId
    }
}
```

```java
@Component
@Path("/api/reservations")
class ReservationApi {
    @HandlePost
    ReservationId reserve(@Valid ReservationRequest request) {
        var reservationId = Fluxzero.generateId(
            ReservationId.class);

        Fluxzero.sendCommandAndWait(
            new ReserveTicket(
                reservationId, request.ticketId()));
        return reservationId;
    }
}
```

- **Input checked:** Fluxzero checks the submitted data against your requirements before running the feature.
- **Identity carried through:** The feature receives the customer making the request without extra code to pass that identity along.
- **Response handled:** The result is sent back to the interface, with errors turned into the appropriate web response.

09 · Connect your features

### The same code. Wherever the work runs.

Your agent connects features without writing code to locate the application that handles each request. Fluxzero delivers it and returns the result. Whether the handler runs in your own app or another one, the calling code stays the same.

**You write**

Can our other apps use the same ticket search?

**Your agent writes** Requests without routing code

```kotlin
@Component
@Path("/api/tickets")
class TicketApi {
    @HandleGet
    fun available(
        @QueryParam showId: ShowId,
        @QueryParam section: String
    ): List<Ticket> =
        Fluxzero.queryAndWait(FindAvailableTickets(showId, section))
}
```

```java
@Component
@Path("/api/tickets")
class TicketApi {
    @HandleGet
    List<Ticket> available(
            @QueryParam ShowId showId,
            @QueryParam String section) {
        return Fluxzero.queryAndWait(
            new FindAvailableTickets(showId, section));
    }
}
```

- **Web handlers anywhere:** The web handler can run in any connected application. The public endpoint stays the same.
- **Queries across applications:** The query handler can run alongside it or in another app. The call stays the same.
- **One request, more uses:** Other apps can observe the same web request for analytics while the endpoint handler returns the response.

10 · Scale independently

### Each part can scale independently.

Not every part of your application is equally busy. Your agent can give busy parts their own capacity without changing how the rest of the product calls them. Fluxzero keeps their progress separate and distributes the work, so capacity can grow where it is needed.

**You write**

Let's add fraud checks without slowing down ticket sales.

**Your agent writes** Fraud checks with their own capacity

```kotlin
@Component
@Consumer(name = "fraud-detection", threads = 4)
class FraudDetection {
    @HandleEvent
    fun check(event: ConfirmReservation) {
        val assessment = Fluxzero.queryAndWait<FraudAssessment>(
            CheckForFraud(event.reservationId))

        if (assessment.requiresReview) {
            Fluxzero.sendAndForgetCommand(
                ReviewReservation(event.reservationId, assessment))
        }
    }
}
```

```java
@Component
@Consumer(name = "fraud-detection", threads = 4)
class FraudDetection {
    @HandleEvent
    void check(ConfirmReservation event) {
        FraudAssessment assessment = Fluxzero.queryAndWait(
            new CheckForFraud(event.reservationId()));

        if (assessment.requiresReview()) {
            Fluxzero.sendAndForgetCommand(
                new ReviewReservation(
                    event.reservationId(), assessment));
        }
    }
}
```

- **Capacity where it counts:** Give demanding work its own consumer. Add threads or app instances as demand grows.
- **Independent progress:** Each consumer keeps its own place. Slower work does not hold up other consumers.
- **Work shared automatically:** Fluxzero distributes the work across instances of the same consumer.

11 · Using the past

### New features can be built from historical data.

Fluxzero preserves your product’s history. Your agent can use it to add features retroactively, with the information as it was at the time. The same code processes earlier activity and continues with new activity.

**You write**

Let's add a rewards program. Can we include earlier purchases?

**Your agent writes** Retroactive event handler

```kotlin
@Component
@Consumer(name = "customer-rewards", minIndex = 0)
class CustomerRewards {
    @HandleEvent
    fun reward(
        event: ConfirmReservation,
        reservation: Reservation
    ) {
        Fluxzero.assertAndApply(
            GrantReward(event.reservationId,
                reservation.customerId, 100))
    }
}
```

```java
@Component
@Consumer(name = "customer-rewards", minIndex = 0)
class CustomerRewards {
    @HandleEvent
    void reward(
            ConfirmReservation event,
            Reservation reservation) {
        Fluxzero.assertAndApply(new GrantReward(
            event.reservationId(), reservation.customerId(), 100));
    }
}
```

- **History supplied:** Your new feature receives recorded activity from the point you choose.
- **Earlier state reconstructed:** Fluxzero supplies the data as it was then, without your code having to rebuild it.
- **Progress remembered:** Progress is tracked, and processing resumes after interruptions.

### Your product grows. Your agent’s code stays focused.

Keep adding features, rules and workflows. Your agent builds on the product code already there, while Fluxzero handles the foundation as your product grows.

[Get started](https://fluxzero.io/#get-started) [Read the docs](https://fluxzero.io/docs/)
