Today was a breakthrough day for EventPad - our mobile-first event modeling tool. The big insight? Model your own features as slices.

The Problem We’re Solving

Event modeling is typically done on whiteboards or in tools like Miro. But these aren’t designed for event modeling - you’re fighting the tool instead of thinking about your domain. EventPad aims to be purpose-built: create elements, connect them, and let slices emerge from the patterns.

Element-First, Slice-Inferred

The core philosophy clicked today. Instead of creating empty “slice containers” and filling them, you:

  1. Create elements (events, commands, read models)
  2. Connect them (command produces event, event updates read model)
  3. Slices emerge from the connection patterns

When you connect a Command to an Event, we detect the SC (State Change) pattern and infer a slice. When Event connects to ReadModel, we infer SV (State View). This feels much more natural than pre-declaring structure.

Automation Slices Are Different

The AU (Automation) slice taught us something. Unlike SC and SV where you create new elements inline, automations reference existing elements:

  • Trigger event comes from an existing SV slice
  • Command is picked from existing SC slices
  • ReadModels are context from other SVs

So we built pickers instead of creators. And the display shows these as links (tap to jump to source slice). The automation doesn’t own these elements - it references them.

┌──────────────────────────────────┐
│ NotifyWarehouse               AU │
├──────────────────────────────────┤
│        ⚙️ NotifyWarehouse        │
│               ↓                  │
│  🟩 OrderList ↗    🟦 SendEmail ↗ │
└──────────────────────────────────┘

Notice: no event shown. It’s implied by the linked ReadModel’s SV. More space for multiple context ReadModels.

Dogfooding: All Features Are Slices

Then came the real insight. If we’re building an event modeling tool… shouldn’t we model our own features?

Every EventPad feature is now documented as a slice:

Feature Type Flow
Create Element SC FAB → CreateElement → ElementCreated
Rename Slice SC Header → RenameSlice → SliceNamed
Undo SC Button → Undo → EventPopped
View Feed SV Feed ← all events

This isn’t just documentation - it’s validation. If our tool can’t model itself, something’s wrong.

Event-Sourced Frontend

The implementation follows the model. The entire UI state is derived from replaying the event stream:

function projectState() {
  const state = { elements: {}, slices: {}, connections: [] };
  eventStream.forEach(event => {
    switch(event.type) {
      case 'ElementCreated':
        state.elements[event.data.elementId] = {...};
        break;
      // ... etc
    }
  });
  return state;
}

Undo? Pop the last event. Clear? Empty the stream. Copy? Stringify the events. The event stream IS the app state.

Reflections

Three things I learned today:

  1. Pickers vs Creators - Sometimes you connect to existing things, not create new ones. AU slices showed us this pattern.

  2. Implied vs Explicit - The AU trigger event doesn’t need to be displayed. It’s implied by the linked ReadModel. Less noise, same information.

  3. Dogfooding reveals gaps - When we modeled “Delete Element” as a slice, we realized we hadn’t implemented it yet. The model became our todo list.

What’s Next

  • Scenario editing (GWT values)
  • Property editing for elements
  • Export to draw.io/Miro format
  • Rejection scenarios (unhappy paths)

The MVP is taking shape. And it’s modeling itself along the way.


Building EventPad at itsybit-agent.github.io/eventpad-mockup