Docs / ArchitectureKit / Quickstart / Quickstart

Quickstart

This quickstart gets a first command running with ArchitectureKit in a few minutes: you start EventSourcingDB with Docker, define a command, an event, and the state to decide on, and execute the command. It uses a temporary setup for development and testing – for everything else, see the links at the end.

Starting EventSourcingDB#

ArchitectureKit stores its events in EventSourcingDB. Start it with the following command. On the first start, Docker downloads the image:

docker run -it -p 3000:3000 \
  thenativeweb/eventsourcingdb run \
  --api-token=secret \
  --data-directory-temporary \
  --http-enabled \
  --https-enabled=false

This starts EventSourcingDB on port 3000, with the API token secret, a temporary data directory that is cleaned up on shutdown, and unencrypted HTTP.

For Development and Testing Only

These settings simplify the setup but are not secure for production. For production-ready configurations, see Running EventSourcingDB.

Creating a Module#

In a second terminal, create a Go module, and add ArchitectureKit and the client SDK for Go:

mkdir library
cd library
go mod init library
go get github.com/thenativeweb/architecturekit-golang github.com/thenativeweb/eventsourcingdb-client-golang

Defining a Command, an Event, and the State#

Create a file main.go. A command describes what someone wants to do, an event describes what has happened, and the state holds what a command needs to decide on. The example acquires a book for a library:

package main

import (
  "context"
  "fmt"
  "log"
  "net/url"

  "github.com/thenativeweb/architecturekit-golang/architecturekit"
  "github.com/thenativeweb/eventsourcingdb-client-golang/eventsourcingdb"
)

type AcquireBook struct {
  BookID string
  Title  string
  Author string
  ISBN   string
}

func (c AcquireBook) Subject() string {
  return "/books/" + c.BookID
}

type BookAcquired struct {
  Title  string `json:"title"`
  Author string `json:"author"`
  ISBN   string `json:"isbn"`
}

func (BookAcquired) EventType() string {
  return "io.eventsourcingdb.library.book-acquired"
}

type Book struct {
  IsAcquired bool
}

var bookState = architecturekit.NewState(Book{}).
  Evolve(func(book Book, event BookAcquired) Book {
    book.IsAcquired = true
    return book
  })

The command names the subject it acts on, the event names its event type, and the state evolves from every BookAcquired event. For details, see Defining Commands, Defining Events, and Defining State.

Deciding on the Command#

A decider connects the state with the decision made on it. It receives the command and the current state, and returns the events to write, or an error to reject the command. Add it to main.go:

var acquireBook = architecturekit.Decider[AcquireBook, Book]{
  State: bookState,
  Decide: func(ctx context.Context, cmd AcquireBook, book Book) ([]architecturekit.Event, error) {
    if book.IsAcquired {
      return nil, architecturekit.NewDomainError("book %s has already been acquired", cmd.BookID)
    }

    return []architecturekit.Event{
      BookAcquired{
        Title:  cmd.Title,
        Author: cmd.Author,
        ISBN:   cmd.ISBN,
      },
    }, nil
  },
}

For details, see Making Decisions.

Executing the Command#

Finally, create a client and a store, and execute the command. Add the main function to main.go:

func main() {
  baseURL, err := url.Parse("http://localhost:3000")
  if err != nil {
    log.Fatal(err)
  }

  client, err := eventsourcingdb.NewClient(baseURL, "secret")
  if err != nil {
    log.Fatal(err)
  }

  store := architecturekit.NewStore(client, "https://library.eventsourcingdb.io")

  writtenEvents, err := architecturekit.Execute(
    context.TODO(),
    store,
    acquireBook,
    AcquireBook{
      BookID: "42",
      Title:  "2001 – A Space Odyssey",
      Author: "Arthur C. Clarke",
      ISBN:   "978-0756906788",
    },
  )
  if err != nil {
    log.Fatal(err)
  }

  for _, event := range writtenEvents {
    fmt.Println(event.ID, event.Type, event.Subject)
  }
}

Execute reads the events of the book's subject, evolves the state from them, calls the decider, and writes the events it returns. Run the program:

go run .

It prints the ID, the type, and the subject of the written event:

0 io.eventsourcingdb.library.book-acquired /books/42

Run it again. This time, the state shows that the book has already been acquired, so the decider rejects the command, and nothing is written:

2026/09/26 15:11:37 book 42 has already been acquired
exit status 1

Shutting Down#

Press Ctrl+C in the first terminal to shut down EventSourcingDB. Since the data directory is temporary, the event is gone afterwards.

Next Steps#