Skip to content
Back to skills

Event Driven Design

ASecurity

When designing loosely coupled systems that react to state changes asynchronously.

  • 7 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added June 5, 2026
ai-agentsjavascriptgojavashellreactapidatabasesecurity

Works with

  • cursor
  • api

Security analysis

A100/100

Scanned June 5, 2026

npx -y skills add KraitDev/skiLL.Md --skill event-driven-design --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Event Driven Design?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Event Driven Design
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/kraitdev-event-driven-design/badge)](https://www.skillsdirectory.com/skills/kraitdev-event-driven-design)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: event-driven-design
description: When designing loosely coupled systems that react to state changes asynchronously.
version: 2.0.0
category: architecture
tags: [architecture, events, async]
skill_type: architecture
author: skiLLM
license: MIT
compatible_agents: [claude-code, cursor, copilot, codex]
estimated_context_tokens: 2000
dangerous: false
requires_review: true
security_level: review-required
dependencies: []
triggers: [event, async, decoupling, event bus, message broker]
permissions:
  filesystem: { read: true, write: true }
  network: { outbound: true }
  shell: { execute: false }
input_requirements: [microservices or monolithic architecture, message broker setup]
output_contract: [immutable events, idempotent consumers, dead letter queues]
failure_conditions: [event loss, duplicate processing, synchronous coupling]
last_updated: 2026-05-15
---

# Event-Driven Design

## Purpose
Tightly coupled systems break and scale poorly. Event-driven architectures decouple producers from consumers by using immutable, timestamped facts as the communication mechanism. This enables systems to evolve independently, scale horizontally, and handle distributed failures gracefully.

## When to use
- De-coupling monolithic microservices
- Implementing long-running asynchronous workflows (e.g., video processing, email sending)
- Triggering multiple side-effects across different domains from a single action
- Designing systems that need to replay history or audit changes

## When NOT to use
- Simple synchronous request-response flows (don't add unnecessary complexity)
- Real-time bidirectional communication (use WebSockets instead)
- Workflows requiring immediate response to action

## Inputs required
- Microservices or monolithic application with clear domain boundaries
- Message broker infrastructure (Kafka, RabbitMQ, EventBridge, etc.)
- Understanding of event sourcing concepts

## Workflow
1. **Define Events**: Identify state changes in the domain and model them as past-tense events (e.g., `OrderPlaced`, `UserRegistered`, `PaymentProcessed`)
2. **Design Event Payloads**: Include Event ID, Timestamp, Event Type, and minimal required data (avoid large nested objects)
3. **Publishing Mechanism**: Have the producer system emit the event to a Message Broker without caring who consumes it
4. **Idempotent Consumers**: Ensure consumer services can process the same event multiple times without adverse side effects
5. **Handle Failures**: Implement Dead Letter Queues (DLQ) for events that consumers repeatedly fail to process
6. **Track Processing**: Add idempotency keys or processed event IDs to detect duplicates
7. **Monitor**: Set up alerts for DLQ messages and processing delays

## Rules
- MUST model events as immutable facts (past tense: `OrderPlaced` not `PlaceOrder`)
- MUST NEVER modify or delete events once emitted (audit trail requirement)
- MUST make consumers idempotent (same event processed multiple times = same outcome)
- MUST avoid deeply nested, rapidly changing entity graphs in payloads
- MUST include Event ID, Timestamp, Event Type in all events
- MUST implement Dead Letter Queues for failed events
- MUST NOT use synchronous HTTP calls as part of event workflows

## Anti-patterns
- **Commands as Events**: Naming events like actions (`SendEmailEvent`) rather than facts (`UserCreated`)
- **Distributed Monolith**: Systems requiring synchronous HTTP calls *in response* to an event before completing their workflow
- **Huge Event Payloads**: Sending entire entity graphs; include only IDs and essential context
- **No Idempotency**: Processing events without tracking duplicate processing
- **Synchronous Dependencies**: Event handler blocks waiting for another service response
- **Event Loss**: Not persisting events to broker; memory-only event storage

## Failure conditions
- Events cannot be replayed (no persistence)
- Consumers not idempotent (duplicates cause data corruption)
- No Dead Letter Queue for failed events
- Synchronous dependencies between event producers and consumers
- Event payloads change format without versioning support

## Validation checklist
- [ ] All events named as past-tense facts (not commands)
- [ ] Events are immutable after emission
- [ ] Event payloads include ID, Timestamp, Type
- [ ] Consumers are idempotent (can process same event multiple times safely)
- [ ] Dead Letter Queue configured and monitored
- [ ] No synchronous HTTP dependencies in event handlers
- [ ] Event versioning strategy defined
- [ ] Idempotency keys tracked (to detect duplicates)
- [ ] Monitoring/alerting on DLQ messages
- [ ] Event processing latency within SLA

## Output format
- **Event schema**: Event ID, Timestamp, Type, Payload (minimal data)
- **Payload format**: JSON with primitive types, IDs, not full objects
- **Consumer pattern**: Read event, validate idempotency key, process, mark as processed
- **Infrastructure**: Message broker setup with persistence and DLQ
- **Monitoring**: Dashboards for event processing latency and DLQ depth

## Security considerations
- Event payloads MUST NOT contain credentials or PII
- Access control MUST be enforced at consumer (not all services can listen to all events)
- Event encryption MUST be used for sensitive domains
- Audit logging MUST track who published and consumed events
- Dead Letter Queues MUST be monitored (may contain sensitive data)

## Agent execution notes
- Agent MAY: Define events, create event handlers, implement idempotency, set up DLQ
- Agent MUST NEVER: Use commands instead of events, create synchronous dependencies, lose events
- Agent MUST ASK: Before adding new event types, before changing event schema, before removing DLQ
- Agent MUST VALIDATE: Events are facts not commands, consumers are idempotent, DLQ configured

## Example

**❌ Anti-pattern (Commands as events, synchronous coupling, no idempotency):**
```javascript
// WRONG: Command not event
publishEvent('SendEmail', { userId, subject });

// WRONG: Synchronous dependency
async function handleOrderPlaced(event) {
  const order = await orderService.fetch(event.orderId); // Blocks on external service
  await emailService.send(order.email); // Fails if service is down
}

// WRONG: No idempotency tracking - processes duplicate
async function handleUserCreated(event) {
  await database.createUser(event); // Processes same event twice = duplicate user
}
```

**✅ Correct pattern (Events, async, idempotent):**
```javascript
// CORRECT: Past-tense event with minimal payload
publishEvent({
  type: 'UserCreated',
  id: uuid(),
  timestamp: new Date(),
  payload: {
    userId: event.userId,
    email: event.email
  }
});

// CORRECT: Asynchronous, idempotent consumer
async function handleUserCreated(event) {
  // 1. Track processed events (idempotency)
  const alreadyProcessed = await cache.get(`processed:${event.id}`);
  if (alreadyProcessed) return; // Skip duplicate
  
  // 2. Process without waiting for external services
  await emailQueue.enqueue({
    email: event.payload.email,
    template: 'welcome'
  });
  
  // 3. Mark as processed
  await cache.set(`processed:${event.id}`, true, { ttl: 86400 });
}

// 4. Dead Letter Queue for failed events
async function handleFailedEvent(event, error) {
  await dlq.store({
    originalEvent: event,
    error: error.message,
    timestamp: new Date(),
    retryCount: 0
  });
}
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…