Move product strategy documentation to .product-strategy directory
Organize all product strategy and domain modeling documentation into a dedicated .product-strategy directory for better separation from code. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
365
.product-strategy/CONTEXT_MAP_DIAGRAM.md
Normal file
365
.product-strategy/CONTEXT_MAP_DIAGRAM.md
Normal file
@@ -0,0 +1,365 @@
|
||||
# Aether Bounded Contexts - Visual Map
|
||||
|
||||
## Context Relationship Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ AETHER SYSTEM │
|
||||
│ │
|
||||
│ │
|
||||
│ ┌──────────────────────┐ │
|
||||
│ │ EVENT SOURCING │◄─────────────────┐ │
|
||||
│ │ (Source of Truth) │ │ │
|
||||
│ │ │ writes │ │
|
||||
│ │ • Events (immutable) │ events │ │
|
||||
│ │ • Versions │ │ Application │
|
||||
│ │ • Snapshots │ │ Business Logic │
|
||||
│ │ • Replay │ │ │
|
||||
│ └──────────┬───────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ publishes │ │
|
||||
│ │ events └──────────────────────────────┘
|
||||
│ │
|
||||
│ ▼
|
||||
│ ┌──────────────────────────────┐
|
||||
│ │ EVENT BUS │ ◄────────────┐
|
||||
│ │ (Pub/Sub Distribution) │ │
|
||||
│ │ │ uses │
|
||||
│ │ • Local subscriptions │ namespace │
|
||||
│ │ • NATS cross-node │ patterns │
|
||||
│ │ • Event filtering │ │
|
||||
│ │ • Non-blocking delivery │ │
|
||||
│ └──────────┬───────────────────┘ │
|
||||
│ │ ┌───────────┴──────────────┐
|
||||
│ │ │ NAMESPACE ISOLATION │
|
||||
│ ▼ distributes │ (Logical Boundaries) │
|
||||
│ to │ │
|
||||
│ ┌─────────────────┐ │ • Namespace patterns │
|
||||
│ │ Subscribers │ │ • Stream prefixing │
|
||||
│ │ (Listeners) │ │ • Wildcard matching │
|
||||
│ └─────────────────┘ │ • Storage isolation │
|
||||
│ └─────────────────────────┘
|
||||
│
|
||||
│
|
||||
│ ┌──────────────────────────────┐
|
||||
│ │ OPTIMISTIC CONCURRENCY │
|
||||
│ │ (Conflict Detection) │
|
||||
│ │ │
|
||||
│ │ • Version validation │
|
||||
│ │ • Conflict detection │
|
||||
│ │ • Detailed error info │
|
||||
│ │ • (App handles retry) │
|
||||
│ └──────────▲───────────────────┘
|
||||
│ │
|
||||
│ │ nested in
|
||||
│ │ EventStore.SaveEvent()
|
||||
│ │
|
||||
│ ┌──────────┴────────────────────┐
|
||||
│ │ CLUSTER COORDINATION │
|
||||
│ │ (Distributed Control) │
|
||||
│ │ │
|
||||
│ │ • Node discovery │
|
||||
│ │ • Leader election │
|
||||
│ │ • Consistent hash ring │
|
||||
│ │ • Shard assignment │
|
||||
│ │ • Rebalancing logic │
|
||||
│ │ │
|
||||
│ │ Coordinates via: │
|
||||
│ │ - LeaderElection (NATS KV) │
|
||||
│ │ - ShardManager (placement) │
|
||||
│ │ - EventBus (topology changes) │
|
||||
│ └───────────────────────────────┘
|
||||
│
|
||||
│
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Detailed Context Interactions
|
||||
|
||||
### Single-Node System (Testing/Development)
|
||||
|
||||
```
|
||||
Application
|
||||
│
|
||||
├─► SaveEvent() ──► InMemoryEventStore
|
||||
│ │
|
||||
│ └─► GetLatestVersion() [Optimistic Concurrency]
|
||||
│
|
||||
└─► Publish() ──► EventBus (local subscriptions)
|
||||
│
|
||||
└─► Subscriber 1 receives event
|
||||
```
|
||||
|
||||
### Multi-Node Cluster
|
||||
|
||||
```
|
||||
Node A Node B
|
||||
┌─────────────────────────┐ ┌─────────────────────────┐
|
||||
│ ClusterManager │ │ ClusterManager │
|
||||
│ - NodeInfo: A │◄─NATS──►│ - NodeInfo: B │
|
||||
│ - LeaderElection │ KV │ - LeaderElection │
|
||||
│ - ShardMap: {...} │ │ - ShardMap: {...} │
|
||||
│ │ │ │
|
||||
└─────────────────────────┘ └─────────────────────────┘
|
||||
│ │
|
||||
│ publishes to │ publishes to
|
||||
│ ShardAssigned event │ ShardAssigned event
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────────────┐ ┌─────────────────────────┐
|
||||
│ JetStreamEventStore │ │ JetStreamEventStore │
|
||||
│ - Stream: events │ │ - Stream: events │
|
||||
│ - GetEvents() │ │ - GetEvents() │
|
||||
│ - SaveEvent() │ │ - SaveEvent() │
|
||||
└─────────────────────────┘ └─────────────────────────┘
|
||||
│ │
|
||||
│ SaveEvent │ SaveEvent
|
||||
▼ triggers ▼ triggers
|
||||
┌─────────────────────────┐ ┌─────────────────────────┐
|
||||
│ NATSEventBus │ │ NATSEventBus │
|
||||
│ Publish(ns, event) │◄─NATS──►│ Subscribe(ns, filter) │
|
||||
│ │ subject │ │
|
||||
│ aether.events.{ns} │ routing │ │
|
||||
└─────────────────────────┘ └─────────────────────────┘
|
||||
|
||||
Shared (via NATS JetStream):
|
||||
- Event persistence (durable across nodes)
|
||||
- Leader election state (KV store)
|
||||
- Event distribution (NATS pub/sub)
|
||||
```
|
||||
|
||||
### Multi-Tenant Scenario
|
||||
|
||||
```
|
||||
Application manages multiple namespaces:
|
||||
|
||||
Tenant A Tenant B
|
||||
│ │
|
||||
├─ JetStreamEventStore ├─ JetStreamEventStore
|
||||
│ namespace: "tenant-a" │ namespace: "tenant-b"
|
||||
│ stream: "tenant-a_events" │ stream: "tenant-b_events"
|
||||
│ │
|
||||
└─► EventBus └─► EventBus
|
||||
Publish("tenant-a", event) Publish("tenant-b", event)
|
||||
│ │
|
||||
▼ ▼
|
||||
Subscribe("tenant-a") Subscribe("tenant-b")
|
||||
(sees only tenant-a events) (sees only tenant-b events)
|
||||
|
||||
Optional: Admin wildcard subscription receives both:
|
||||
Subscribe("*") or Subscribe(">")
|
||||
(sees tenant-a AND tenant-b events)
|
||||
⚠️ SECURITY: Only grant to trusted components
|
||||
```
|
||||
|
||||
## Context Ownership Matrix
|
||||
|
||||
| Context | Internal Owner | Data Owner | Responsibility |
|
||||
|---------|---|---|---|
|
||||
| **Event Sourcing** | EventStore | Application (writes events); Aether (persists) | Event persistence, versioning, replay |
|
||||
| **Optimistic Concurrency** | SaveEvent() | Version tracking | Conflict detection; app retries |
|
||||
| **Namespace Isolation** | EventBus + JetStreamEventStore | Application (defines semantics) | Isolation routing; wildcard warnings |
|
||||
| **Cluster Coordination** | ClusterManager + LeaderElection | ClusterManager | Discovery, election, shard assignment |
|
||||
| **Event Bus** | EventBus/NATSEventBus | Aether | Event distribution; filtering; delivery |
|
||||
|
||||
## Lifecycle Timelines
|
||||
|
||||
### Event Lifetime (per context)
|
||||
|
||||
```
|
||||
Event Sourcing Context:
|
||||
Create ──SaveEvent()─► Store ──Replay()─► Rebuild State ──Forever──► Retention Expires
|
||||
│ │
|
||||
│ └─► GetEvents() (available for subscribers)
|
||||
│ └─► GetLatestVersion() (for new writers)
|
||||
│
|
||||
Optimistic Concurrency (during SaveEvent):
|
||||
└─► Check version ──Conflict?── Yes ──► VersionConflictError (app retries)
|
||||
│
|
||||
No ──► Success
|
||||
|
||||
Event Bus Context (after SaveEvent succeeds):
|
||||
Event ──Publish(namespace, event)── Matched Subscribers ──► Each gets event
|
||||
│ │
|
||||
Namespace pattern match Filter match (EventType, ActorPattern)
|
||||
(exact or wildcard) │
|
||||
Non-blocking delivery
|
||||
```
|
||||
|
||||
### Shard Lifetime (per context)
|
||||
|
||||
```
|
||||
Cluster Coordination Context:
|
||||
|
||||
Cluster Formation:
|
||||
Node Joins ──LeaderElection()─► Leader Elected ──ShardAssignment()─► ShardMap Created
|
||||
│
|
||||
└─► LeadershipLease (TTL: 10s)
|
||||
│
|
||||
├─ Heartbeat every 3s (renew lease)
|
||||
│
|
||||
└─ Lease expires ──► New election
|
||||
|
||||
Node Failure:
|
||||
Node Fails ──Detection timeout──► ShardMap Updated ──Rebalancing─► NewShardMap
|
||||
(90s implied) │ │
|
||||
└─► ShardMigrated events ─► Actors replay on new nodes
|
||||
|
||||
Event Sourcing Integration (during shard migration):
|
||||
Source Node Destination Node
|
||||
│ │
|
||||
└─ Stop serving ◄───┘ Start accepting
|
||||
│ │
|
||||
└─ Events still in JetStream (durable)
|
||||
│
|
||||
└─► Replay from snapshot/event 1
|
||||
```
|
||||
|
||||
### Subscription Lifetime (per context)
|
||||
|
||||
```
|
||||
Event Bus Context:
|
||||
|
||||
Application calls Subscribe(namespace, filter):
|
||||
────────────────────────────────────────────
|
||||
Channel created (100-element buffer)
|
||||
│
|
||||
├─ Exact match: added to exactSubscribers[namespace]
|
||||
│
|
||||
└─ Wildcard: added to wildcardSubscribers
|
||||
|
||||
├─ If first subscriber for pattern:
|
||||
│ └─ NATSEventBus: create NATS subscription (aether.events.{pattern})
|
||||
│
|
||||
Return channel to caller
|
||||
|
||||
|
||||
Event arrives (via Publish or NATS):
|
||||
────────────────────────────────────────────
|
||||
EventBus.Publish(namespace, event)
|
||||
│
|
||||
├─ Deliver to exactSubscribers[namespace] (if matches filter)
|
||||
│
|
||||
└─ Deliver to wildcardSubscribers (if pattern matches; if filter matches)
|
||||
|
||||
├─ Non-blocking send (may drop if channel full)
|
||||
│
|
||||
└─ Metrics recorded (delivered or dropped)
|
||||
|
||||
|
||||
Application calls Unsubscribe(namespace, channel):
|
||||
────────────────────────────────────────────
|
||||
Remove from exactSubscribers or wildcardSubscribers
|
||||
│
|
||||
└─ If last subscriber for pattern:
|
||||
└─ NATSEventBus: unsubscribe from NATS
|
||||
|
||||
Close channel
|
||||
```
|
||||
|
||||
## Key Invariants per Context
|
||||
|
||||
| Context | Invariant | How Enforced | Verified |
|
||||
|---------|-----------|--------------|----------|
|
||||
| **Event Sourcing** | Version strictly monotonic per actor | SaveEvent checks version > current | Error if violated |
|
||||
| **Event Sourcing** | Event immutable after persist | Event struct only read after store | Code review |
|
||||
| **Namespace Isolation** | No cross-namespace reads | Separate JetStream streams | Integration test |
|
||||
| **Cluster Coordination** | Only one leader at a time | Lease-based election (NATS KV) | Lease expiry |
|
||||
| **Cluster Coordination** | All nodes have consistent shard map | Published via ShardAssigned event | Periodic sync |
|
||||
| **Event Bus** | Non-blocking delivery | Select with default (drop) | Code review |
|
||||
| **Optimistic Concurrency** | Conflict detected synchronously | Version check in SaveEvent | Fast-fail |
|
||||
|
||||
## Dependency Summary
|
||||
|
||||
```
|
||||
Aether Core (no dependencies between contexts; all dependencies are inbound):
|
||||
|
||||
├─ Application
|
||||
│ ├─ Writes to Event Sourcing (SaveEvent)
|
||||
│ ├─ Publishes to Event Bus (Publish)
|
||||
│ ├─ Subscribes to Event Bus (Subscribe)
|
||||
│ └─ Handles Optimistic Concurrency errors (retry logic)
|
||||
│
|
||||
├─ Event Sourcing
|
||||
│ ├─ Provides events to Event Bus
|
||||
│ ├─ Provides events to Cluster Coordination (on failover)
|
||||
│ └─ Implements Optimistic Concurrency (SaveEvent validation)
|
||||
│
|
||||
├─ Event Bus
|
||||
│ ├─ Routes events from Event Sourcing
|
||||
│ ├─ Routes events from Cluster Coordination
|
||||
│ ├─ Uses Namespace Isolation patterns
|
||||
│ └─ Delivers to all subscribers
|
||||
│
|
||||
├─ Namespace Isolation
|
||||
│ ├─ Scopes Event Sourcing (JetStreamConfig.Namespace)
|
||||
│ ├─ Scopes Event Bus (Subscribe pattern)
|
||||
│ └─ Optional; can be omitted (single global namespace)
|
||||
│
|
||||
├─ Cluster Coordination
|
||||
│ ├─ Reads from Event Sourcing (GetLatestVersion, replay on failover)
|
||||
│ ├─ Publishes to Event Bus (ShardAssigned, etc.)
|
||||
│ ├─ Can use Namespace Isolation (optional)
|
||||
│ └─ Independent election loop
|
||||
│
|
||||
└─ Optimistic Concurrency
|
||||
├─ Embedded in Event Sourcing (SaveEvent)
|
||||
├─ Errors drive Application retry logic
|
||||
└─ Version state managed by Event Sourcing
|
||||
```
|
||||
|
||||
## When Contexts Interact
|
||||
|
||||
| Interaction | Trigger | Duration | Frequency |
|
||||
|-------------|---------|----------|-----------|
|
||||
| App → Event Sourcing | Domain event occurs | Synchronous (ms) | Per business event |
|
||||
| Event Sourcing → Event Bus | SaveEvent succeeds | Async (app controls) | Per business event |
|
||||
| Optimistic Concurrency → App | Version conflict | Synchronous (us) | Per concurrent write |
|
||||
| Cluster → Event Sourcing | Node fails / rebalances | Async (minutes) | Per topology change |
|
||||
| Cluster → Event Bus | Shard assignment changes | Async (seconds) | Per election or failure |
|
||||
| Event Bus → Subscribers | Event published | Non-blocking (drops) | Per business event |
|
||||
| Namespace Isolation → All | Routing decision | Synchronous (us) | Per publish/subscribe |
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy by Context
|
||||
|
||||
### Event Sourcing (Unit + Integration)
|
||||
```
|
||||
Unit: SaveEvent with various versions, GetLatestVersion, GetEvents
|
||||
Integration: Snapshot + replay, corruption recovery, concurrent writes
|
||||
```
|
||||
|
||||
### Optimistic Concurrency (Unit)
|
||||
```
|
||||
Unit: Conflict detection, error details, version semantics
|
||||
Integration: Concurrent writers, contention metrics
|
||||
```
|
||||
|
||||
### Namespace Isolation (Integration)
|
||||
```
|
||||
Integration: Multi-tenant isolation, wildcard safety, cross-namespace verification
|
||||
```
|
||||
|
||||
### Cluster Coordination (Integration)
|
||||
```
|
||||
Integration: Node join/fail, leader election, shard rebalancing, split-brain prevention
|
||||
```
|
||||
|
||||
### Event Bus (Unit + Integration)
|
||||
```
|
||||
Unit: Subscribe/unsubscribe, filtering, exact vs wildcard
|
||||
Integration: NATS distribution, cross-node delivery, dropped event handling
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Non-Interactions (Important!)
|
||||
|
||||
The following are **NOT** direct dependencies (avoid creating them):
|
||||
|
||||
- **Namespace Isolation ↔ Cluster Coordination**: Cluster works across all namespaces; namespace is orthogonal
|
||||
- **Event Sourcing ↔ Cluster Coordination**: Cluster doesn't own event storage; queries it, doesn't manage it
|
||||
- **Optimistic Concurrency ↔ Event Bus**: Conflicts are events; not bus subscribers
|
||||
- **Application ↔ Cluster**: App doesn't directly manage cluster; uses ClusterManager API
|
||||
- **Event Bus ↔ Event Sourcing**: One-way (sourcing publishes; bus delivers); no feedback loop
|
||||
Reference in New Issue
Block a user