[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FSZ0E9C3AXP0CCVRSN6AET":3,"skill-same:01M6FSZ0E9C3AXP0CCVRSN6AET":76},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":48,"commitSha":49,"skillDirectory":50,"forksCount":14,"repositoryHtmlUrl":51,"repositoryHomepageUrl":6,"ownerHtmlUrl":52,"ownerBlogUrl":53,"ownerDescription":54,"updatedAt":55,"install":56,"resources":69},"01M6FSZ0E9C3AXP0CCVRSN6AET","event-store-design",null,"Design and implement event stores for event-sourced systems. Use when building event sourcing infrastructure, choosing event store technologies, or implementing event persistence patterns.","reikiplanet\u002Fdaoskills","reikiplanet","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F96377599?v=4","01M6CVWCMD740YHQDK7E9QYBW4","Reiki Planet","01M6CVWCS4KXVA2CWFVJ43EAXK",0,"MIT","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fcreative\u002Fevent-store-design\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41],"design","event store design","event store","store","event","implement","infrastructure","event sourcing","persistence","use","community","patterns","systems","2026-11-10 10:12:30",false,"---\nname: event-store-design\ndescription: \"Design and implement event stores for event-sourced systems. Use when building event sourcing infrastructure, choosing event store technologies, or implementing event persistence patterns.\"\nrisk: unknown\nsource: community\n---\n\n# Event Store Design\n\nComprehensive guide to designing event stores for event-sourced applications.\n\n## Do not use this skill when\n\n- The task is unrelated to event store design\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources\u002Fimplementation-playbook.md`.\n\n## Use this skill when\n\n- Designing event sourcing infrastructure\n- Choosing between event store technologies\n- Implementing custom event stores\n- Optimizing event storage and retrieval\n- Setting up event store schemas\n- Planning for event store scaling\n\n## Core Concepts\n\n### 1. Event Store Architecture\n\n```\n┌─────────────────────────────────────────────────────┐\n│                    Event Store                       │\n├─────────────────────────────────────────────────────┤\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐ │\n│  │   Stream 1   │  │   Stream 2   │  │   Stream 3   │ │\n│  │ (Aggregate)  │  │ (Aggregate)  │  │ (Aggregate)  │ │\n│  ├─────────────┤  ├─────────────┤  ├─────────────┤ │\n│  │ Event 1     │  │ Event 1     │  │ Event 1     │ │\n│  │ Event 2     │  │ Event 2     │  │ Event 2     │ │\n│  │ Event 3     │  │ ...         │  │ Event 3     │ │\n│  │ ...         │  │             │  │ Event 4     │ │\n│  └─────────────┘  └─────────────┘  └─────────────┘ │\n├─────────────────────────────────────────────────────┤\n│  Global Position: 1 → 2 → 3 → 4 → 5 → 6 → ...     │\n└─────────────────────────────────────────────────────┘\n```\n\n### 2. Event Store Requirements\n\n| Requirement       | Description                        |\n| ----------------- | ---------------------------------- |\n| **Append-only**   | Events are immutable, only appends |\n| **Ordered**       | Per-stream and global ordering     |\n| **Versioned**     | Optimistic concurrency control     |\n| **Subscriptions** | Real-time event notifications      |\n| **Idempotent**    | Handle duplicate writes safely     |\n\n## Technology Comparison\n\n| Technology       | Best For                  | Limitations                      |\n| ---------------- | ------------------------- | -------------------------------- |\n| **EventStoreDB** | Pure event sourcing       | Single-purpose                   |\n| **PostgreSQL**   | Existing Postgres stack   | Manual implementation            |\n| **Kafka**        | High-throughput streaming | Not ideal for per-stream queries |\n| **DynamoDB**     | Serverless, AWS-native    | Query limitations                |\n| **Marten**       | .NET ecosystems           | .NET specific                    |\n\n## Templates\n\n### Template 1: PostgreSQL Event Store Schema\n\n```sql\n-- Events table\nCREATE TABLE events (\n    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    stream_id VARCHAR(255) NOT NULL,\n    stream_type VARCHAR(255) NOT NULL,\n    event_type VARCHAR(255) NOT NULL,\n    event_data JSONB NOT NULL,\n    metadata JSONB DEFAULT '{}',\n    version BIGINT NOT NULL,\n    global_position BIGSERIAL,\n    created_at TIMESTAMPTZ DEFAULT NOW(),\n\n    CONSTRAINT unique_stream_version UNIQUE (stream_id, version)\n);\n\n-- Index for stream queries\nCREATE INDEX idx_events_stream_id ON events(stream_id, version);\n\n-- Index for global subscription\nCREATE INDEX idx_events_global_position ON events(global_position);\n\n-- Index for event type queries\nCREATE INDEX idx_events_event_type ON events(event_type);\n\n-- Index for time-based queries\nCREATE INDEX idx_events_created_at ON events(created_at);\n\n-- Snapshots table\nCREATE TABLE snapshots (\n    stream_id VARCHAR(255) PRIMARY KEY,\n    stream_type VARCHAR(255) NOT NULL,\n    snapshot_data JSONB NOT NULL,\n    version BIGINT NOT NULL,\n    created_at TIMESTAMPTZ DEFAULT NOW()\n);\n\n-- Subscriptions checkpoint table\nCREATE TABLE subscription_checkpoints (\n    subscription_id VARCHAR(255) PRIMARY KEY,\n    last_position BIGINT NOT NULL DEFAULT 0,\n    updated_at TIMESTAMPTZ DEFAULT NOW()\n);\n```\n\n### Template 2: Python Event Store Implementation\n\n```python\nfrom dataclasses import dataclass, field\nfrom datetime import datetime\nfrom typing import Any, Optional, List\nfrom uuid import UUID, uuid4\nimport json\nimport asyncpg\n\n@dataclass\nclass Event:\n    stream_id: str\n    event_type: str\n    data: dict\n    metadata: dict = field(default_factory=dict)\n    event_id: UUID = field(default_factory=uuid4)\n    version: Optional[int] = None\n    global_position: Optional[int] = None\n    created_at: datetime = field(default_factory=datetime.utcnow)\n\n\nclass EventStore:\n    def __init__(self, pool: asyncpg.Pool):\n        self.pool = pool\n\n    async def append_events(\n        self,\n        stream_id: str,\n        stream_type: str,\n        events: List[Event],\n        expected_version: Optional[int] = None\n    ) -> List[Event]:\n        \"\"\"Append events to a stream with optimistic concurrency.\"\"\"\n        async with self.pool.acquire() as conn:\n            async with conn.transaction():\n                # Check expected version\n                if expected_version is not None:\n                    current = await conn.fetchval(\n                        \"SELECT MAX(version) FROM events WHERE stream_id = $1\",\n                        stream_id\n                    )\n                    current = current or 0\n                    if current != expected_version:\n                        raise ConcurrencyError(\n                            f\"Expected version {expected_version}, got {current}\"\n                        )\n\n                # Get starting version\n                start_version = await conn.fetchval(\n                    \"SELECT COALESCE(MAX(version), 0) + 1 FROM events WHERE stream_id = $1\",\n                    stream_id\n                )\n\n                # Insert events\n                saved_events = []\n                for i, event in enumerate(events):\n                    event.version = start_version + i\n                    row = await conn.fetchrow(\n                        \"\"\"\n                        INSERT INTO events (id, stream_id, stream_type, event_type,\n                                          event_data, metadata, version, created_at)\n                        VALUES ($1, $2, $3, $4, $5, $6, $7, $8)\n                        RETURNING global_position\n                        \"\"\",\n                        event.event_id,\n                        stream_id,\n                        stream_type,\n                        event.event_type,\n                        json.dumps(event.data),\n                        json.dumps(event.metadata),\n                        event.version,\n                        event.created_at\n                    )\n                    event.global_position = row['global_position']\n                    saved_events.append(event)\n\n                return saved_events\n\n    async def read_stream(\n        self,\n        stream_id: str,\n        from_version: int = 0,\n        limit: int = 1000\n    ) -> List[Event]:\n        \"\"\"Read events from a stream.\"\"\"\n        async with self.pool.acquire() as conn:\n            rows = await conn.fetch(\n                \"\"\"\n                SELECT id, stream_id, event_type, event_data, metadata,\n                       version, global_position, created_at\n                FROM events\n                WHERE stream_id = $1 AND version >= $2\n                ORDER BY version\n                LIMIT $3\n                \"\"\",\n                stream_id, from_version, limit\n            )\n            return [self._row_to_event(row) for row in rows]\n\n    async def read_all(\n        self,\n        from_position: int = 0,\n        limit: int = 1000\n    ) -> List[Event]:\n        \"\"\"Read all events globally.\"\"\"\n        async with self.pool.acquire() as conn:\n            rows = await conn.fetch(\n                \"\"\"\n                SELECT id, stream_id, event_type, event_data, metadata,\n                       version, global_position, created_at\n                FROM events\n                WHERE global_position > $1\n                ORDER BY global_position\n                LIMIT $2\n                \"\"\",\n                from_position, limit\n            )\n            return [self._row_to_event(row) for row in rows]\n\n    async def subscribe(\n        self,\n        subscription_id: str,\n        handler,\n        from_position: int = 0,\n        batch_size: int = 100\n    ):\n        \"\"\"Subscribe to all events from a position.\"\"\"\n        # Get checkpoint\n        async with self.pool.acquire() as conn:\n            checkpoint = await conn.fetchval(\n                \"\"\"\n                SELECT last_position FROM subscription_checkpoints\n                WHERE subscription_id = $1\n                \"\"\",\n                subscription_id\n            )\n            position = checkpoint or from_position\n\n        while True:\n            events = await self.read_all(position, batch_size)\n            if not events:\n                await asyncio.sleep(1)  # Poll interval\n                continue\n\n            for event in events:\n                await handler(event)\n                position = event.global_position\n\n            # Save checkpoint\n            async with self.pool.acquire() as conn:\n                await conn.execute(\n                    \"\"\"\n                    INSERT INTO subscription_checkpoints (subscription_id, last_position)\n                    VALUES ($1, $2)\n                    ON CONFLICT (subscription_id)\n                    DO UPDATE SET last_position = $2, updated_at = NOW()\n                    \"\"\",\n                    subscription_id, position\n                )\n\n    def _row_to_event(self, row) -> Event:\n        return Event(\n            event_id=row['id'],\n            stream_id=row['stream_id'],\n            event_type=row['event_type'],\n            data=json.loads(row['event_data']),\n            metadata=json.loads(row['metadata']),\n            version=row['version'],\n            global_position=row['global_position'],\n            created_at=row['created_at']\n        )\n\n\nclass ConcurrencyError(Exception):\n    \"\"\"Raised when optimistic concurrency check fails.\"\"\"\n    pass\n```\n\n### Template 3: EventStoreDB Usage\n\n```python\nfrom esdbclient import EventStoreDBClient, NewEvent, StreamState\nimport json\n\n# Connect\nclient = EventStoreDBClient(uri=\"esdb:\u002F\u002Flocalhost:2113?tls=false\")\n\n# Append events\ndef append_events(stream_name: str, events: list, expected_revision=None):\n    new_events = [\n        NewEvent(\n            type=event['type'],\n            data=json.dumps(event['data']).encode(),\n            metadata=json.dumps(event.get('metadata', {})).encode()\n        )\n        for event in events\n    ]\n\n    if expected_revision is None:\n        state = StreamState.ANY\n    elif expected_revision == -1:\n        state = StreamState.NO_STREAM\n    else:\n        state = expected_revision\n\n    return client.append_to_stream(\n        stream_name=stream_name,\n        events=new_events,\n        current_version=state\n    )\n\n# Read stream\ndef read_stream(stream_name: str, from_revision: int = 0):\n    events = client.get_stream(\n        stream_name=stream_name,\n        stream_position=from_revision\n    )\n    return [\n        {\n            'type': event.type,\n            'data': json.loads(event.data),\n            'metadata': json.loads(event.metadata) if event.metadata else {},\n            'stream_position': event.stream_position,\n            'commit_position': event.commit_position\n        }\n        for event in events\n    ]\n\n# Subscribe to all\nasync def subscribe_to_all(handler, from_position: int = 0):\n    subscription = client.subscribe_to_all(commit_position=from_position)\n    async for event in subscription:\n        await handler({\n            'type': event.type,\n            'data': json.loads(event.data),\n            'stream_id': event.stream_name,\n            'position': event.commit_position\n        })\n\n# Category projection ($ce-Category)\ndef read_category(category: str):\n    \"\"\"Read all events for a category using system projection.\"\"\"\n    return read_stream(f\"$ce-{category}\")\n```\n\n### Template 4: DynamoDB Event Store\n\n```python\nimport boto3\nfrom boto3.dynamodb.conditions import Key\nfrom datetime import datetime\nimport json\nimport uuid\n\nclass DynamoEventStore:\n    def __init__(self, table_name: str):\n        self.dynamodb = boto3.resource('dynamodb')\n        self.table = self.dynamodb.Table(table_name)\n\n    def append_events(self, stream_id: str, events: list, expected_version: int = None):\n        \"\"\"Append events with conditional write for concurrency.\"\"\"\n        with self.table.batch_writer() as batch:\n            for i, event in enumerate(events):\n                version = (expected_version or 0) + i + 1\n                item = {\n                    'PK': f\"STREAM#{stream_id}\",\n                    'SK': f\"VERSION#{version:020d}\",\n                    'GSI1PK': 'EVENTS',\n                    'GSI1SK': datetime.utcnow().isoformat(),\n                    'event_id': str(uuid.uuid4()),\n                    'stream_id': stream_id,\n                    'event_type': event['type'],\n                    'event_data': json.dumps(event['data']),\n                    'version': version,\n                    'created_at': datetime.utcnow().isoformat()\n                }\n                batch.put_item(Item=item)\n        return events\n\n    def read_stream(self, stream_id: str, from_version: int = 0):\n        \"\"\"Read events from a stream.\"\"\"\n        response = self.table.query(\n            KeyConditionExpression=Key('PK').eq(f\"STREAM#{stream_id}\") &\n                                  Key('SK').gte(f\"VERSION#{from_version:020d}\")\n        )\n        return [\n            {\n                'event_type': item['event_type'],\n                'data': json.loads(item['event_data']),\n                'version': item['version']\n            }\n            for item in response['Items']\n        ]\n\n# Table definition (CloudFormation\u002FTerraform)\n\"\"\"\nDynamoDB Table:\n  - PK (Partition Key): String\n  - SK (Sort Key): String\n  - GSI1PK, GSI1SK for global ordering\n\nCapacity: On-demand or provisioned based on throughput needs\n\"\"\"\n```\n\n## Best Practices\n\n### Do's\n\n- **Use stream IDs that include aggregate type** - `Order-{uuid}`\n- **Include correlation\u002Fcausation IDs** - For tracing\n- **Version events from day one** - Plan for schema evolution\n- **Implement idempotency** - Use event IDs for deduplication\n- **Index appropriately** - For your query patterns\n\n### Don'ts\n\n- **Don't update or delete events** - They're immutable facts\n- **Don't store large payloads** - Keep events small\n- **Don't skip optimistic concurrency** - Prevents data corruption\n- **Don't ignore backpressure** - Handle slow consumers\n\n## Resources\n\n- [EventStoreDB](https:\u002F\u002Fwww.eventstore.com\u002F)\n- [Marten Events](https:\u002F\u002Fmartendb.io\u002Fevents\u002F)\n- [Event Sourcing Pattern](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Farchitecture\u002Fpatterns\u002Fevent-sourcing)\n","# Event Store Design\n\nComprehensive guide to designing event stores for event-sourced applications.\n\n## Do not use this skill when\n\n- The task is unrelated to event store design\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources\u002Fimplementation-playbook.md`.\n\n## Use this skill when\n\n- Designing event sourcing infrastructure\n- Choosing between event store technologies\n- Implementing custom event stores\n- Optimizing event storage and retrieval\n- Setting up event store schemas\n- Planning for event store scaling\n\n## Core Concepts\n\n### 1. Event Store Architecture\n\n```\n┌─────────────────────────────────────────────────────┐\n│                    Event Store                       │\n├─────────────────────────────────────────────────────┤\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐ │\n│  │   Stream 1   │  │   Stream 2   │  │   Stream 3   │ │\n│  │ (Aggregate)  │  │ (Aggregate)  │  │ (Aggregate)  │ │\n│  ├─────────────┤  ├─────────────┤  ├─────────────┤ │\n│  │ Event 1     │  │ Event 1     │  │ Event 1     │ │\n│  │ Event 2     │  │ Event 2     │  │ Event 2     │ │\n│  │ Event 3     │  │ ...         │  │ Event 3     │ │\n│  │ ...         │  │             │  │ Event 4     │ │\n│  └─────────────┘  └─────────────┘  └─────────────┘ │\n├─────────────────────────────────────────────────────┤\n│  Global Position: 1 → 2 → 3 → 4 → 5 → 6 → ...     │\n└─────────────────────────────────────────────────────┘\n```\n\n### 2. Event Store Requirements\n\n| Requirement       | Description                        |\n| ----------------- | ---------------------------------- |\n| **Append-only**   | Events are immutable, only appends |\n| **Ordered**       | Per-stream and global ordering     |\n| **Versioned**     | Optimistic concurrency control     |\n| **Subscriptions** | Real-time event notifications      |\n| **Idempotent**    | Handle duplicate writes safely     |\n\n## Technology Comparison\n\n| Technology       | Best For                  | Limitations                      |\n| ---------------- | ------------------------- | -------------------------------- |\n| **EventStoreDB** | Pure event sourcing       | Single-purpose                   |\n| **PostgreSQL**   | Existing Postgres stack   | Manual implementation            |\n| **Kafka**        | High-throughput streaming | Not ideal for per-stream queries |\n| **DynamoDB**     | Serverless, AWS-native    | Query limitations                |\n| **Marten**       | .NET ecosystems           | .NET specific                    |\n\n## Templates\n\n### Template 1: PostgreSQL Event Store Schema\n\n```sql\n-- Events table\nCREATE TABLE events (\n    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    stream_id VARCHAR(255) NOT NULL,\n    stream_type VARCHAR(255) NOT NULL,\n    event_type VARCHAR(255) NOT NULL,\n    event_data JSONB NOT NULL,\n    metadata JSONB DEFAULT '{}',\n    version BIGINT NOT NULL,\n    global_position BIGSERIAL,\n    created_at TIMESTAMPTZ DEFAULT NOW(),\n\n    CONSTRAINT unique_stream_version UNIQUE (stream_id, version)\n);\n\n-- Index for stream queries\nCREATE INDEX idx_events_stream_id ON events(stream_id, version);\n\n-- Index for global subscription\nCREATE INDEX idx_events_global_position ON events(global_position);\n\n-- Index for event type queries\nCREATE INDEX idx_events_event_type ON events(event_type);\n\n-- Index for time-based queries\nCREATE INDEX idx_events_created_at ON events(created_at);\n\n-- Snapshots table\nCREATE TABLE snapshots (\n    stream_id VARCHAR(255) PRIMARY KEY,\n    stream_type VARCHAR(255) NOT NULL,\n    snapshot_data JSONB NOT NULL,\n    version BIGINT NOT NULL,\n    created_at TIMESTAMPTZ DEFAULT NOW()\n);\n\n-- Subscriptions checkpoint table\nCREATE TABLE subscription_checkpoints (\n    subscription_id VARCHAR(255) PRIMARY KEY,\n    last_position BIGINT NOT NULL DEFAULT 0,\n    updated_at TIMESTAMPTZ DEFAULT NOW()\n);\n```\n\n### Template 2: Python Event Store Implementation\n\n```python\nfrom dataclasses import dataclass, field\nfrom datetime import datetime\nfrom typing import Any, Optional, List\nfrom uuid import UUID, uuid4\nimport json\nimport asyncpg\n\n@dataclass\nclass Event:\n    stream_id: str\n    event_type: str\n    data: dict\n    metadata: dict = field(default_factory=dict)\n    event_id: UUID = field(default_factory=uuid4)\n    version: Optional[int] = None\n    global_position: Optional[int] = None\n    created_at: datetime = field(default_factory=datetime.utcnow)\n\n\nclass EventStore:\n    def __init__(self, pool: asyncpg.Pool):\n        self.pool = pool\n\n    async def append_events(\n        self,\n        stream_id: str,\n        stream_type: str,\n        events: List[Event],\n        expected_version: Optional[int] = None\n    ) -> List[Event]:\n        \"\"\"Append events to a stream with optimistic concurrency.\"\"\"\n        async with self.pool.acquire() as conn:\n            async with conn.transaction():\n                # Check expected version\n                if expected_version is not None:\n                    current = await conn.fetchval(\n                        \"SELECT MAX(version) FROM events WHERE stream_id = $1\",\n                        stream_id\n                    )\n                    current = current or 0\n                    if current != expected_version:\n                        raise ConcurrencyError(\n                            f\"Expected version {expected_version}, got {current}\"\n                        )\n\n                # Get starting version\n                start_version = await conn.fetchval(\n                    \"SELECT COALESCE(MAX(version), 0) + 1 FROM events WHERE stream_id = $1\",\n                    stream_id\n                )\n\n                # Insert events\n                saved_events = []\n                for i, event in enumerate(events):\n                    event.version = start_version + i\n                    row = await conn.fetchrow(\n                        \"\"\"\n                        INSERT INTO events (id, stream_id, stream_type, event_type,\n                                          event_data, metadata, version, created_at)\n                        VALUES ($1, $2, $3, $4, $5, $6, $7, $8)\n                        RETURNING global_position\n                        \"\"\",\n                        event.event_id,\n                        stream_id,\n                        stream_type,\n                        event.event_type,\n                        json.dumps(event.data),\n                        json.dumps(event.metadata),\n                        event.version,\n                        event.created_at\n                    )\n                    event.global_position = row['global_position']\n                    saved_events.append(event)\n\n                return saved_events\n\n    async def read_stream(\n        self,\n        stream_id: str,\n        from_version: int = 0,\n        limit: int = 1000\n    ) -> List[Event]:\n        \"\"\"Read events from a stream.\"\"\"\n        async with self.pool.acquire() as conn:\n            rows = await conn.fetch(\n                \"\"\"\n                SELECT id, stream_id, event_type, event_data, metadata,\n                       version, global_position, created_at\n                FROM events\n                WHERE stream_id = $1 AND version >= $2\n                ORDER BY version\n                LIMIT $3\n                \"\"\",\n                stream_id, from_version, limit\n            )\n            return [self._row_to_event(row) for row in rows]\n\n    async def read_all(\n        self,\n        from_position: int = 0,\n        limit: int = 1000\n    ) -> List[Event]:\n        \"\"\"Read all events globally.\"\"\"\n        async with self.pool.acquire() as conn:\n            rows = await conn.fetch(\n                \"\"\"\n                SELECT id, stream_id, event_type, event_data, metadata,\n                       version, global_position, created_at\n                FROM events\n                WHERE global_position > $1\n                ORDER BY global_position\n                LIMIT $2\n                \"\"\",\n                from_position, limit\n            )\n            return [self._row_to_event(row) for row in rows]\n\n    async def subscribe(\n        self,\n        subscription_id: str,\n        handler,\n        from_position: int = 0,\n        batch_size: int = 100\n    ):\n        \"\"\"Subscribe to all events from a position.\"\"\"\n        # Get checkpoint\n        async with self.pool.acquire() as conn:\n            checkpoint = await conn.fetchval(\n                \"\"\"\n                SELECT last_position FROM subscription_checkpoints\n                WHERE subscription_id = $1\n                \"\"\",\n                subscription_id\n            )\n            position = checkpoint or from_position\n\n        while True:\n            events = await self.read_all(position, batch_size)\n            if not events:\n                await asyncio.sleep(1)  # Poll interval\n                continue\n\n            for event in events:\n                await handler(event)\n                position = event.global_position\n\n            # Save checkpoint\n            async with self.pool.acquire() as conn:\n                await conn.execute(\n                    \"\"\"\n                    INSERT INTO subscription_checkpoints (subscription_id, last_position)\n                    VALUES ($1, $2)\n                    ON CONFLICT (subscription_id)\n                    DO UPDATE SET last_position = $2, updated_at = NOW()\n                    \"\"\",\n                    subscription_id, position\n                )\n\n    def _row_to_event(self, row) -> Event:\n        return Event(\n            event_id=row['id'],\n            stream_id=row['stream_id'],\n            event_type=row['event_type'],\n            data=json.loads(row['event_data']),\n            metadata=json.loads(row['metadata']),\n            version=row['version'],\n            global_position=row['global_position'],\n            created_at=row['created_at']\n        )\n\n\nclass ConcurrencyError(Exception):\n    \"\"\"Raised when optimistic concurrency check fails.\"\"\"\n    pass\n```\n\n### Template 3: EventStoreDB Usage\n\n```python\nfrom esdbclient import EventStoreDBClient, NewEvent, StreamState\nimport json\n\n# Connect\nclient = EventStoreDBClient(uri=\"esdb:\u002F\u002Flocalhost:2113?tls=false\")\n\n# Append events\ndef append_events(stream_name: str, events: list, expected_revision=None):\n    new_events = [\n        NewEvent(\n            type=event['type'],\n            data=json.dumps(event['data']).encode(),\n            metadata=json.dumps(event.get('metadata', {})).encode()\n        )\n        for event in events\n    ]\n\n    if expected_revision is None:\n        state = StreamState.ANY\n    elif expected_revision == -1:\n        state = StreamState.NO_STREAM\n    else:\n        state = expected_revision\n\n    return client.append_to_stream(\n        stream_name=stream_name,\n        events=new_events,\n        current_version=state\n    )\n\n# Read stream\ndef read_stream(stream_name: str, from_revision: int = 0):\n    events = client.get_stream(\n        stream_name=stream_name,\n        stream_position=from_revision\n    )\n    return [\n        {\n            'type': event.type,\n            'data': json.loads(event.data),\n            'metadata': json.loads(event.metadata) if event.metadata else {},\n            'stream_position': event.stream_position,\n            'commit_position': event.commit_position\n        }\n        for event in events\n    ]\n\n# Subscribe to all\nasync def subscribe_to_all(handler, from_position: int = 0):\n    subscription = client.subscribe_to_all(commit_position=from_position)\n    async for event in subscription:\n        await handler({\n            'type': event.type,\n            'data': json.loads(event.data),\n            'stream_id': event.stream_name,\n            'position': event.commit_position\n        })\n\n# Category projection ($ce-Category)\ndef read_category(category: str):\n    \"\"\"Read all events for a category using system projection.\"\"\"\n    return read_stream(f\"$ce-{category}\")\n```\n\n### Template 4: DynamoDB Event Store\n\n```python\nimport boto3\nfrom boto3.dynamodb.conditions import Key\nfrom datetime import datetime\nimport json\nimport uuid\n\nclass DynamoEventStore:\n    def __init__(self, table_name: str):\n        self.dynamodb = boto3.resource('dynamodb')\n        self.table = self.dynamodb.Table(table_name)\n\n    def append_events(self, stream_id: str, events: list, expected_version: int = None):\n        \"\"\"Append events with conditional write for concurrency.\"\"\"\n        with self.table.batch_writer() as batch:\n            for i, event in enumerate(events):\n                version = (expected_version or 0) + i + 1\n                item = {\n                    'PK': f\"STREAM#{stream_id}\",\n                    'SK': f\"VERSION#{version:020d}\",\n                    'GSI1PK': 'EVENTS',\n                    'GSI1SK': datetime.utcnow().isoformat(),\n                    'event_id': str(uuid.uuid4()),\n                    'stream_id': stream_id,\n                    'event_type': event['type'],\n                    'event_data': json.dumps(event['data']),\n                    'version': version,\n                    'created_at': datetime.utcnow().isoformat()\n                }\n                batch.put_item(Item=item)\n        return events\n\n    def read_stream(self, stream_id: str, from_version: int = 0):\n        \"\"\"Read events from a stream.\"\"\"\n        response = self.table.query(\n            KeyConditionExpression=Key('PK').eq(f\"STREAM#{stream_id}\") &\n                                  Key('SK').gte(f\"VERSION#{from_version:020d}\")\n        )\n        return [\n            {\n                'event_type': item['event_type'],\n                'data': json.loads(item['event_data']),\n                'version': item['version']\n            }\n            for item in response['Items']\n        ]\n\n# Table definition (CloudFormation\u002FTerraform)\n\"\"\"\nDynamoDB Table:\n  - PK (Partition Key): String\n  - SK (Sort Key): String\n  - GSI1PK, GSI1SK for global ordering\n\nCapacity: On-demand or provisioned based on throughput needs\n\"\"\"\n```\n\n## Best Practices\n\n### Do's\n\n- **Use stream IDs that include aggregate type** - `Order-{uuid}`\n- **Include correlation\u002Fcausation IDs** - For tracing\n- **Version events from day one** - Plan for schema evolution\n- **Implement idempotency** - Use event IDs for deduplication\n- **Index appropriately** - For your query patterns\n\n### Don'ts\n\n- **Don't update or delete events** - They're immutable facts\n- **Don't store large payloads** - Keep events small\n- **Don't skip optimistic concurrency** - Prevents data corruption\n- **Don't ignore backpressure** - Handle slow consumers\n\n## Resources\n\n- [EventStoreDB](https:\u002F\u002Fwww.eventstore.com\u002F)\n- [Marten Events](https:\u002F\u002Fmartendb.io\u002Fevents\u002F)\n- [Event Sourcing Pattern](https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Farchitecture\u002Fpatterns\u002Fevent-sourcing)\n",{"name":5,"risk":47,"source":39,"description":7},"unknown","master","dff58085da947e81e8418c922055644bf0082b1b","creative\u002Fevent-store-design","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills","https:\u002F\u002Fgithub.com\u002Freikiplanet","https:\u002F\u002Fwww.reiki-planet.com","Reiki Planet Game","2026-03-29 06:02:29",{"source":8,"skillName":5,"commands":57,"prompt":67,"zipAvailable":68},[58,61,64],{"tool":59,"command":60},"npx","npx skills add reikiplanet\u002Fdaoskills --skill event-store-design",{"tool":62,"command":63},"bunx","bunx skills add reikiplanet\u002Fdaoskills --skill event-store-design",{"tool":65,"command":66},"pnpm","pnpm dlx skills add reikiplanet\u002Fdaoskills --skill event-store-design","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fcreative\u002Fevent-store-design\u002FSKILL.md",true,[70],{"path":71,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":74,"sourceHtmlUrl":75},"resources\u002Fimplementation-playbook.md","REFERENCE","参考文档",746,"https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fcreative\u002Fevent-store-design\u002Fresources\u002Fimplementation-playbook.md",[77,103,115,129,148,171],{"skillNo":78,"name":79,"nameZh":6,"description":80,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":42},"01M6G614JTEQJHPT8AKK3YQ18S","web-games","Web browser game development principles. Framework selection, WebGPU, optimization, PWA.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fweb-games\u002FSKILL.md",[],[84,85,86,87,88,89,39,90,91,92,93,94,95,96,97,98,99,100,101,102],"games","web games","web","grep","principles","selection","framework selection","edit","write","read","pwa","game","web browser","game development","Optimization","framework","browser","development","webgpu",{"skillNo":104,"name":105,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":109,"publishedAt":42},"01M6G611H2YGV0GZFP90D38ZMJ","vr-ar","VR\u002FAR development principles. Comfort, interaction, performance requirements.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fvr-ar\u002FSKILL.md",[],[110,111,101,112,113,39,91,92,93,87,114,88],"ar","vr ar","interaction","requirements","performance",{"skillNo":116,"name":117,"nameZh":6,"description":118,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":121,"publishedAt":42},"01M6G60XNMHAMV1SV0EJ1CX0AY","templates","Project scaffolding templates for new applications. Use when creating new projects from scratch. Contains 12 templates for various tech stacks.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Ftemplates\u002FSKILL.md",[],[117,122,123,124,125,126,39,38,93,127,128,87],"project scaffolding","From Scratch","tech","project","scaffolding","projects","applications",{"skillNo":130,"name":131,"nameZh":6,"description":132,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":133,"categories":134,"keywords":135,"publishedAt":42},"01M6G60T0GATMK3Q5H8GDC1Z8S","wcag-audit-patterns","Conduct WCAG 2.2 accessibility audits with automated testing, manual verification, and remediation guidance. Use when auditing websites for accessibility, fixing WCAG violations, or implementing ac...","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fwcag-audit-patterns\u002FSKILL.md",[],[136,137,40,138,139,39,140,141,142,143,38,144,145,146,147],"wcag audit patterns","wcag audit","WCAG","audit","manual","with","automated testing","guidance","remediation","verification","accessibility","testing",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":154,"publishedAt":42},"01M6G60PMCHW1FRZ63F931QK3R","vulnerability-scanner","Advanced vulnerability analysis principles. OWASP 2025, Supply Chain Security, attack surface mapping, risk prioritization.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fvulnerability-scanner\u002FSKILL.md",[],[155,156,157,158,159,160,161,162,39,93,87,163,88,164,165,166,167,168,169,170],"scanner","vulnerability scanner","vulnerability","prioritization","2025","mapping","chain","supply chain","Bash","analysis","risk","owasp","supply chain security","security","supply","advanced",{"skillNo":172,"name":173,"nameZh":6,"description":174,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":42},"01M6G60JZBB8DK0W3DSG1WNMZK","threat-modeling-expert","Expert in threat modeling methodologies, security architecture review, and risk assessment. Masters STRIDE, PASTA, attack trees, and security requirement extraction. Use for security architecture r...","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fthreat-modeling-expert\u002FSKILL.md",[],[178,179,180,181,182,183,184,185,168,38,186,187,188,39,189,190,191,165,192,193],"modeling","threat modeling expert","threat modeling","expert","threat","risk assessment","architecture review","architecture","security architecture review","trees","security architecture","security requirement extraction","assessment","extraction","review","stride"]