{"slug": "event-sourcing-building-an-application-fast-using-the-event-sourcing-pattern-dcb", "title": "[Event Sourcing] Building an Application Fast Using the Event Sourcing Pattern with Sekiban DCB and AI", "summary": "A developer built a library management application using the Sekiban DCB Decider template with event sourcing, completing the full implementation in under an hour with the help of Codex and GPT-6 Astra. The AI was instructed to follow existing Student, ClassRoom, and Enrollment sample implementations as the standard, and the resulting app supports registering, borrowing, and returning books with a Blazor UI, PostgreSQL storage, and concurrency verification.", "body_md": "In this article, we will build an event-sourced application using Sekiban DCB and AI. Along with implementing the UI and APIs, we will check whether the application maintains consistency when multiple operations happen at the same time.\n\nFor this project, I used **Codex × GPT-6 Astra**.\n\nThe Sekiban DCB Decider template includes sample implementations that we can use as references when giving instructions to AI.\n\nThese samples cover the full flow from the UI to APIs, business rules, and event persistence. We will explore how far we can take feature development and verification with AI by following these existing implementations.\n\nAs an example, we will build a simple library management application that supports registering, borrowing, and returning books. We will use PostgreSQL for storage and create a basic Blazor UI to try out the APIs.\n\nThe sample code is available here:\n\n[BookManagement sample on GitHub](https://github.com/kdaigo/SekibanSamples/tree/main/BookManagement)\n\nFirst, run the following commands to create a project from the template:\n\n```\ndotnet new install Sekiban.Dcb.Templates\ndotnet new sekiban-dcb-decider -n BookManagement\n```\n\nYou can also find instructions for getting started with the Decider template in the [Quick Start on the official website](https://www.sekiban.dev).\n\nFor this project, I used the .NET 10 SDK and Linux containers in Docker Desktop. The UI was built with Blazor.\n\nThe generated project already included samples for Student, ClassRoom, and Enrollment:\n\nWe will ask AI to implement new features using these samples as references.\n\nThe detailed business requirements, consistency rules, and verification scenarios are available in `docs/spec.md` in the sample code. Below is an excerpt from the instructions I gave AI to keep the implementation consistent with the existing samples:\n\n```\nBefore you start implementing, read the existing Student, ClassRoom, and\nEnrollment implementations from end to end, including the UI, APIs,\ncommands, Deciders, events, states, and queries.\n\nTreat these implementations as the standard for this project.\nRather than introducing a new design or coding style, implement the\nlibrary management features by adapting similar existing code.\n\nIf the existing code uses multiple approaches, choose the one closest\nto the business operation you are adding.\nDo not introduce custom helpers, new abstractions, or shorthand syntax.\nOnly if the existing approach cannot meet the requirements, explain why,\npropose a change, and ask for confirmation before proceeding.\n```\n\nThe entire implementation took less than an hour, including reviewing the existing code, implementing the features, building the project, running integration and concurrency tests against a real PostgreSQL database, and checking and fixing the UI.\n\nIn this template, business rules live in Deciders associated with events and states. Their main responsibilities are `Validate`, which checks whether an operation is allowed, and `Evolve`, which applies an event to a state.\n\nBelow is an excerpt from the borrowing logic we implemented. `Book` represents the book being borrowed, `User` represents the borrower, and `Loan` represents a single loan. If the book is already on loan, another borrowing attempt is rejected. When the borrowing event is applied, the resulting state stores the LoanId and UserId.\n\n```\npublic static class BookBorrowedDecider\n{\n    public static void Validate(this BorrowedBookState state)\n    {\n        throw new InvalidOperationException(\n            $\"Book {state.BookId} is already borrowed\");\n    }\n\n    public static BorrowedBookState Evolve(\n        this AvailableBookState state, BookBorrowed borrowed) =>\n        new(state.BookId, state.Name, borrowed.LoanId, borrowed.UserId);\n}\n```\n\nThe Handler coordinates state retrieval and validation, then returns an event if validation succeeds. The Decider itself does not need any code for connecting to PostgreSQL.\n\n``` php\nflowchart LR\n    UI[Blazor UI] --> API[API]\n    API --> H[Command Handler]\n    H --> V[State retrieval and Decider validation]\n    V --> E[Event creation]\n    E --> S[Conflict detection and persistence by Sekiban]\n    S --> P[Projector / List projection]\n    P --> Q[Query]\n    Q --> UI\n```\n\nIn this project, AI implemented the new business rules using the same Decider structure as the existing code. Keeping the code structure consistent as features are added also makes it easier for developers to know where to look for business rules. This is where I found the approach particularly useful for AI-assisted coding.\n\nChecking the current state alone does not solve concurrency problems. Two requests can read the same state before either updates it, and both can conclude that the operation is allowed.\n\nFor example, if two users try to borrow the same book at almost the same time, both requests might read its status as “available” before it changes. Similarly, if one user borrows different books at the same time, each request might appear to be within the borrowing limit, while the combined result exceeds it.\n\nThis is where DCB, or **Dynamic Consistency Boundary**, comes in. It uses tags to define which entities must remain consistent together for a particular operation. Sekiban DCB provides optimistic concurrency control based on these tags.\n\nOur borrowing event has the following structure:\n\n```\npublic record BookBorrowed(\n    Guid LoanId,\n    Guid BookId,\n    Guid UserId,\n    DateTime BorrowedAt) : IEventPayload\n{\n    public EventPayloadWithTags GetEventWithTags() =>\n        new(this,\n            new LoanTag(LoanId),\n            new BookTag(BookId),\n            new UserTag(UserId));\n}\n```\n\nWe attach three tags—Loan, Book, and User—to a single fact: a book was borrowed. Each is defined as a consistency tag, and the Handler reads and validates the corresponding state.\n\n| Entity to check | Rule to enforce | \n|---|---|\n| Book | Prevent the same book from being loaned out twice at the same time | \n| User | Keep the user within the borrowing limit, even when requests involve different books | \n| Loan | Identify each loan and check for duplicates and whether it has been returned | \n\nSekiban handles the concurrency checks that determine whether the events can be saved based on the state we read. The application returns an error for a request that encounters a conflict.\n\nThe key is deciding which business conditions to validate and which entities to include in the consistency boundary. Adding tags alone does not automatically enforce arbitrary business rules. We define those rules explicitly in the Deciders and Handlers, then let the framework detect conflicts when saving events.\n\nThe UI is a simple interface for trying out the APIs. The screenshots below show it with sample data prepared for this article (The UI was originally built in Japanese. The screenshots below have been edited to show the labels and sample data in English for this article.).\n\nThe book list shows each book’s status. The button for removing a book from the catalog is disabled while the book is on loan.\n\nOn the borrowing and returns screen, you can select a user and a book to create a loan. Loan records remain in the history after the books are returned, and the Return button is disabled for those records. The API’s business rules also check whether each operation is allowed.\n\nTo verify that consistency was maintained, we tested the following scenarios:\n\nFor every scenario, we sent multiple requests at almost the same time to an API connected to a real PostgreSQL database. We confirmed that operations violating the business rules were rejected and that the related states remained consistent.\n\nBy asking AI to add features that followed the existing samples, we were able to implement and verify the application in a short time. Letting Sekiban handle conflict detection and persistence also allowed us to focus on implementing the business rules.\n\nI hope this article encourages you to try building an event-sourced application with Sekiban DCB and AI.", "url": "https://wpnews.pro/news/event-sourcing-building-an-application-fast-using-the-event-sourcing-pattern-dcb", "canonical_source": "https://dev.to/kary_0009/event-sourcing-building-an-application-fast-using-the-event-sourcing-pattern-with-sekiban-dcb-and-1oa6", "published_at": "2026-09-17 08:15:43+00:00", "updated_at": "2026-09-17 08:23:28.205391+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-agents"], "entities": ["Sekiban", "Codex", "GPT-6 Astra", "PostgreSQL", "Blazor", ".NET", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/event-sourcing-building-an-application-fast-using-the-event-sourcing-pattern-dcb", "markdown": "https://wpnews.pro/news/event-sourcing-building-an-application-fast-using-the-event-sourcing-pattern-dcb.md", "text": "https://wpnews.pro/news/event-sourcing-building-an-application-fast-using-the-event-sourcing-pattern-dcb.txt", "jsonld": "https://wpnews.pro/news/event-sourcing-building-an-application-fast-using-the-event-sourcing-pattern-dcb.jsonld"}}