Event sourcing stands as one of the most powerful architectural patterns for modern applications. The promise is immense: a perfect, immutable audit log of every change, the ability to reconstruct state at any point in time, and a clear separation of concerns. But let's be honest—implementing it from scratch is notoriously complex. Developers often find themselves wrestling with boilerplate code, event schema versioning, and the intricacies of Command Query Responsibility Segregation (CQRS).
What if you could gain the core benefits of event sourcing—especially the bulletproof audit trail—without the traditional overhead? What if you could focus on your business logic, and the event log became an automatic, structured byproduct?
Enter Verbs.do. It’s a new approach that re-frames the problem. Instead of thinking about low-level events, you start thinking in terms of high-level actions. This is "Actions as Code," and it makes implementing a robust, event-sourced system surprisingly simple.
At its heart, event sourcing is a simple idea. Instead of storing the current state of your data, you store the sequence of events that led to that state.
Think of a bank account. A traditional approach might just store the current balance: $150.00. An event-sourced approach stores the full history:
The current balance is simply a projection of these events. The real power lies in the log itself—it’s a complete, unchangeable record of everything that happened. This is invaluable for auditing, debugging, and business intelligence.
While powerful, building and maintaining a custom event-sourcing system often involves significant challenges:
Verbs.do elegantly sidesteps these complexities by elevating the core concept. It provides an Action & Workflow Automation API built on a simple yet powerful primitive: the Verb.
A Verb isn't just an event record; it's a standardized, executable definition of a complete business action. It encapsulates the what, who, why, and what happens next.
This is "Business-as-Code." You define your business operations once, as code, and then execute them from anywhere. The auditable event log is generated for you automatically.
Let's break down the Define. Execute. Log. philosophy.
First, you define a Verb. This creates a single source of truth for what a specific business action means in your system. It’s an explicit contract.
Consider signing up a new user. The definition looks like this:
This definition is incredibly rich. It specifies the action's name (SignUp), the actor (User), the required data (email, password), and even declarative side-effects (CreateUserRecord, SendWelcomeEmail). The system now knows what a "Sign Up" is.
Once defined, you can trigger this action from anywhere in your application stack—your web server, a mobile app backend, or a background worker—with a simple call.
Notice you're not writing complex logic here. You're just invoking the standardized action you already defined. This keeps your application code clean and focused on intent.
This is where the magic happens. Every time .execute() is called, Verbs.do automatically creates a detailed, structured, and immutable log entry. This is your event source.
You didn't have to build an event bus, design a schema, or write a database record. You simply performed a business action, and the perfect audit trail was created as a result.
This log captures:
Let's apply this to another scenario. Imagine you need to add an invoicing feature to your SaaS product. Compliance and a clear audit trail are non-negotiable.
Step 1: Define the CreateInvoice Verb.
Step 2: Execute it in your billing service.
Step 3: Instantly Gain Auditing Superpowers.
Your event log now contains an unchangeable record of this action. When a customer asks, "Why was I charged this month?", you don't have to dig through disparate application logs. You can simply query the Verbs.do log:
For a security audit, you can answer questions with certainty:
You've implemented a robust, auditable system without the typical architectural complexity. You get the benefits of event sourcing by focusing on your a higher-level, more intuitive business logic.
A function call just executes code. A Verb represents a complete, observable business operation. It automatically handles the structured logging, permissions, and analytics that you would otherwise have to build yourself.
By shifting from implementing low-level event handlers to defining high-level business actions, Verbs.do provides a practical and powerful path to building more resilient, transparent, and auditable systems. It delivers on the promise of event sourcing, made simple.
Ready to transform your operations into code? Explore the Verbs.do API and start building a comprehensive system of record for everything that happens.
import { Verb } from 'verbs.do';
// Define a 'SignUp' action once
const signUp = new Verb({
name: 'SignUp',
description: 'A new user creates an account.',
subject: { type: 'User' },
properties: {
email: { type: 'string', format: 'email' },
password: { type: 'string', sensitive: true }
},
effects: [
{ name: 'CreateUserRecord' },
{ name: 'SendWelcomeEmail' }
]
});
// Execute it anywhere in your application
await signUp.execute({
subject: { id: 'user_123' },
properties: {
email: 'hello@example.com',
password: 'a-secure-password'
}
});
import { Verb } from 'verbs.do';
const createInvoice = new Verb({
name: 'CreateInvoice',
description: 'Generates a new invoice for a customer.',
subject: { type: 'System' }, // Can be triggered by the system or a specific admin
object: { type: 'Customer' },
properties: {
amount: { type: 'number' },
currency: { type: 'string', default: 'USD' },
dueDate: { type: 'string', format: 'date' }
},
effects: [
{ name: 'NotifyCustomerViaEmail' },
{ name: 'UpdateCustomerBalance' }
]
});
// Inside your monthly billing cron job...
await createInvoice.execute({
subject: { id: 'billing_service_v1' },
object: { id: 'customer_abc_789' },
properties: {
amount: 99.99,
dueDate: '2023-12-31'
}
});