event-driven-architecture
Generic Event-Driven Architecture patterns with Kafka, Dapr, and modern messaging systems. Provides reusable patterns for building scalable, resilient event-driven microservices. Framework-agnostic implementation supporting multiple message brokers, state stores, and event patterns. Follows 2025 best practices for distributed systems.
What this skill does
# Event-Driven Architecture with Modern Patterns
This skill provides comprehensive patterns for implementing event-driven microservices using modern messaging systems, distributed runtimes, and cloud-native patterns. It's designed to be framework-agnostic and applicable to any domain requiring event-driven capabilities.
## When to Use This Skill
Use this skill when you need to:
- Build event-driven microservices architecture
- Implement pub/sub patterns with Kafka, RabbitMQ, or cloud services
- Use Dapr for distributed application patterns
- Implement real-time notifications and workflows
- Build recurring task and reminder systems
- Create audit trails and activity logs
- Implement distributed state management
- Build serverless event workflows
- Handle event sourcing and CQRS patterns
## 1. Core Event Architecture
### Base Event Schema
```python
# events/core.py
from pydantic import BaseModel, Field, validator
from datetime import datetime
from typing import Optional, Dict, Any, Union, List
from enum import Enum
from abc import ABC, abstractmethod
import uuid
import json
class EventVersion(str, Enum):
"""Event versioning support"""
V1_0 = "1.0"
V1_1 = "1.1"
V2_0 = "2.0"
class EventPriority(str, Enum):
"""Event priority levels"""
LOW = "low"
NORMAL = "normal"
HIGH = "high"
CRITICAL = "critical"
class BaseEvent(BaseModel, ABC):
"""Base event schema with common fields"""
# Core identification
event_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
event_type: str = Field(..., description="Type of the event")
event_version: EventVersion = Field(default=EventVersion.V1_0)
# Metadata
timestamp: datetime = Field(default_factory=datetime.utcnow)
correlation_id: Optional[str] = None
causation_id: Optional[str] = None # Event that caused this one
source: str = Field(..., description="Source service/identifier")
# Context
user_id: Optional[str] = None
tenant_id: Optional[str] = None # Multi-tenant support
session_id: Optional[str] = None
# Processing metadata
priority: EventPriority = Field(default=EventPriority.NORMAL)
retry_count: int = Field(default=0)
max_retries: int = Field(default=3)
delay_until: Optional[datetime] = None # For delayed processing
# Schema versioning
schema_version: str = Field(default="1.0")
class Config:
# Allow additional fields for extensibility
extra = "allow"
# Use enum values
use_enum_values = True
@validator('event_type')
def validate_event_type(cls, v):
"""Validate event type format"""
if not v or '.' not in v:
raise ValueError('event_type must be in format: domain.event_name')
return v.lower()
@validator('correlation_id')
def validate_correlation_id(cls, v, values):
"""Set correlation_id from causation_id if not provided"""
if not v and 'causation_id' in values:
return values['causation_id']
return v
def to_dict(self) -> Dict[str, Any]:
"""Convert event to dictionary for serialization"""
return self.model_dump()
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'BaseEvent':
"""Create event from dictionary"""
return cls(**data)
def with_context(self, **context) -> 'BaseEvent':
"""Add context to event"""
for key, value in context.items():
if hasattr(self, key):
setattr(self, key, value)
return self
class DomainEvent(BaseEvent):
"""Domain-specific event"""
aggregate_id: str = Field(..., description="Aggregate root ID")
aggregate_type: str = Field(..., description="Aggregate type")
event_data: Dict[str, Any] = Field(default_factory=dict)
@validator('aggregate_type')
def validate_aggregate_type(cls, v):
"""Validate aggregate type"""
if not v:
raise ValueError('aggregate_type is required')
return v.lower()
class IntegrationEvent(BaseEvent):
"""Integration event for cross-service communication"""
target_services: List[str] = Field(default_factory=list)
routing_key: Optional[str] = None
message_format: str = Field(default="json")
@validator('routing_key')
def validate_routing_key(cls, v, values):
"""Generate routing key from event_type if not provided"""
if not v and 'event_type' in values:
return values['event_type'].replace('.', '/')
return v
class CommandEvent(BaseEvent):
"""Command event representing an intent"""
command_type: str = Field(..., description="Type of command")
command_data: Dict[str, Any] = Field(default_factory=dict)
expected_version: Optional[int] = None # For optimistic concurrency
@validator('command_type')
def validate_command_type(cls, v):
"""Validate command type"""
if not v.endswith('.command'):
v = f"{v}.command"
return v.lower()
class QueryEvent(BaseEvent):
"""Query event for data retrieval"""
query_type: str = Field(..., description="Type of query")
query_params: Dict[str, Any] = Field(default_factory=dict)
result_topic: Optional[str] = None # Where to send results
@validator('query_type')
def validate_query_type(cls, v):
"""Validate query type"""
if not v.endswith('.query'):
v = f"{v}.query"
return v.lower()
```
### Event Store Pattern
```python
# events/store.py
import asyncio
from abc import ABC, abstractmethod
from typing import List, Optional, Dict, Any, AsyncIterator
from datetime import datetime, timedelta
import json
import uuid
class EventStore(ABC):
"""Abstract event store interface"""
@abstractmethod
async def save_event(self, event: BaseEvent, stream_id: str) -> None:
"""Save event to a stream"""
pass
@abstractmethod
async def get_events(
self,
stream_id: str,
from_version: Optional[int] = None,
to_version: Optional[int] = None,
limit: Optional[int] = None
) -> AsyncIterator[BaseEvent]:
"""Get events from a stream"""
pass
@abstractmethod
async def get_event_by_id(self, event_id: str) -> Optional[BaseEvent]:
"""Get a specific event by ID"""
pass
@abstractmethod
async def get_events_by_type(
self,
event_type: str,
from_timestamp: Optional[datetime] = None,
to_timestamp: Optional[datetime] = None
) -> AsyncIterator[BaseEvent]:
"""Get events by type"""
pass
@abstractmethod
async def get_aggregate_snapshot(
self,
aggregate_id: str,
aggregate_type: str
) -> Optional[Dict[str, Any]]:
"""Get aggregate snapshot"""
pass
@abstractmethod
async def save_aggregate_snapshot(
self,
aggregate_id: str,
aggregate_type: str,
data: Dict[str, Any],
version: int
) -> None:
"""Save aggregate snapshot"""
pass
class InMemoryEventStore(EventStore):
"""In-memory event store for testing and development"""
def __init__(self):
self._events: Dict[str, List[BaseEvent]] = {}
self._snapshots: Dict[str, Dict[str, Any]] = {}
self._type_index: Dict[str, List[str]] = {}
async def save_event(self, event: BaseEvent, stream_id: str) -> None:
"""Save event to memory"""
if stream_id not in self._events:
self._events[stream_id] = []
self._events[stream_id].append(event)
# Update type index
if event.event_type not in self._type_index:
self._type_index[event.event_type] = []
self._type_index[event.event_type].append(event.event_id)
async def get_events(
self,
stream_id: str,
from_version: Optional[int] = None,
to_version: Optional[int] = None,
limit: OptiRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.