Files
aether/.product-strategy/STRATEGY_CHAIN.md
Hugo Nijhuis 271f5db444
Some checks failed
CI / build (push) Successful in 21s
CI / integration (push) Failing after 2m1s
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>
2026-01-12 23:57:20 +01:00

12 KiB

Aether Product Strategy Chain

This directory contains the complete product strategy chain for Aether, from organizational values to executable work.

The Chain (Product Strategy Framework)

Manifesto (Flowmade values)
    ↓ (constraints + outcomes)
vision.md (what Aether does)
    ↓ (events + decisions)
PROBLEM_MAP.md (problem space)
    ↓ (boundaries)
BOUNDED_CONTEXT_MAP.md (domain boundaries)
    ↓ (invariants)
Domain Models (not yet; next step)
    ↓ (system abilities)
Capabilities (not yet; next step)
    ↓ (user value)
Features (not yet; next step)
    ↓ (executable)
Issues (not yet; generated from features)

Documents in This Repository

1. vision.md

What: Product vision statement Answers:

  • Who is Aether for? (Go teams building event-sourced systems; Flowmade internally)
  • What pain does it solve? (Distributed event sourcing without heavyweight frameworks)
  • What won't we do? (No opinionated multi-tenancy, no domain modeling, no UI)

Output: 1-page product promise


2. PROBLEM_MAP.md

What: Problem space analysis through developer journeys Covers:

  • 4 developer journeys (single-node, scaling, namespace isolation, concurrency)
  • 25+ business events across domains
  • 6 decision points with trade-offs
  • 6 risk areas with expensive mistakes
  • Code observations (intended vs actual implementation)

Key Insight: Don't start with DDD; first understand the problem from users' perspective

Output: Timeline of events, decisions, risks (no entities yet)


3. BOUNDED_CONTEXT_MAP.md

What: Domain boundaries identified from problem space Contains:

  • 5 bounded contexts (Event Sourcing, Optimistic Concurrency, Namespace Isolation, Cluster Coordination, Event Bus)
  • For each context:
    • Purpose & core responsibility
    • Ubiquitous language (domain vocabulary)
    • Key entities & events
    • Interfaces to other contexts
    • Lifecycle patterns
    • Current code locations
    • Alignment with vision
    • Gaps & observations
  • Context relationships (producer/consumer, dependencies, orthogonal patterns)
  • Boundary rules (language, lifecycle, ownership, scaling)
  • Code alignment analysis (intended vs actual)
  • Refactoring backlog

Key Insight: Boundaries cut by language differences, lifecycle differences, ownership, and scaling needs

Output: Clear domain boundaries; ready for aggregates & invariants


4. CONTEXT_MAP_DIAGRAM.md

What: Visual representation of bounded contexts Contains:

  • ASCII diagram of 5 contexts
  • Single-node system interaction
  • Multi-node cluster interaction
  • Multi-tenant scenario
  • Ownership matrix
  • Lifecycle timelines (events, shards, subscriptions)
  • Invariants per context
  • Dependency summary
  • Testing strategy

Output: Visual clarity; communication tool for team discussions


Next Steps in Strategy Chain

Step 4: Domain Models (per context)

Goal: Capture business invariants and define aggregates

For each bounded context:

  1. Identify invariants ("what must never break?")
  2. Define aggregates (clusters of entities that must be consistent)
  3. Define commands (intent to change state)
  4. Define events (facts that happened)
  5. Define value objects (immutable, identity-less concepts)
  6. Define read models (views optimized for queries)

Example for Event Sourcing context:

  • Aggregate: ActorEventLog (root); contains Events
  • Invariant: "Version must be strictly monotonic"
  • Commands: SaveEvent (internal), ApplySnapshot
  • Events: EventStored, VersionConflict, SnapshotCreated
  • Value Objects: Version, EventType, Timestamp

Deliverable: Domain models document per context


Step 5: Capabilities (system abilities)

Goal: Bridge domain thinking to roadmap thinking

For each domain model:

  • "Store events durably with conflict detection" (Event Sourcing)
  • "Detect concurrent writes and fail fast" (Optimistic Concurrency)
  • "Isolate logical domains using namespace patterns" (Namespace Isolation)
  • "Distribute actors across cluster nodes" (Cluster Coordination)
  • "Route events to subscribers with filtering" (Event Bus)

Rule: Capabilities survive UI rewrites; they're about what the system CAN DO

Deliverable: Capability map


Step 6: Features

Goal: Define user-visible value slices

Process:

  1. What capability does this feature enable?
  2. Who needs it? (user persona)
  3. Why now? (market/business reason)
  4. How do you demo it?

Example features:

  • "Developer can save events to in-memory store for fast iteration"
  • "Developer can scale single-node system to cluster without rewriting"
  • "Operator can configure namespace prefixes for multi-tenant isolation"
  • "Leader automatically elected on cluster formation"
  • "Subscriber can filter events by type and actor pattern"

Deliverable: Feature list with business context


Step 7: Issues (executable work)

Goal: Decompose features into implementable tasks

Structure per issue:

  • User story: "As a [who], I want [what], so that [why]"
  • Acceptance criteria: "Given [context], when [action], then [outcome]"
  • Domain reference: Link to bounded context, aggregate, invariant
  • Technical approach: What commands/events/queries involved

Example issue:

User Story: As a developer, I want to save events with automatic version conflict detection,
so that concurrent writes don't silently lose data.

Acceptance Criteria:
1. SaveEvent validates version > current latest
2. Returns VersionConflictError with ActorID, attempted, current versions
3. GetLatestVersion returns 0 for new actors
4. Conflict detection is fast (<1ms per write)

Linked to: Bounded Context: Event Sourcing
           Aggregate: ActorEventLog
           Invariant: Monotonic versions
           Event: VersionConflict

Deliverable: GitHub issues with domain language


How to Use This Chain

For Technical Decisions

  1. Read vision.md - What are we building? Why?
  2. Read PROBLEM_MAP.md - What are users trying to do?
  3. Read BOUNDED_CONTEXT_MAP.md - What are the boundaries?
  4. Identify which context your decision touches
  5. Check: Does it violate a context invariant?

For New Contributors

  1. Start with vision.md (2 min read)
  2. Read the 4 journeys in PROBLEM_MAP.md (10 min)
  3. Focus on relevant context in BOUNDED_CONTEXT_MAP.md (10 min)
  4. Refer to CONTEXT_MAP_DIAGRAM.md when confused about interactions

For Roadmap Planning

  1. Current state: BOUNDED_CONTEXT_MAP.md identifies gaps
  2. Define domain models per context (Step 4)
  3. List capabilities (Step 5)
  4. Prioritize features (Step 6)
  5. Break into issues (Step 7)

For Code Review

  1. Does this code touch multiple bounded contexts?
    • If yes: Are boundaries clear? Is translation happening at seam?
  2. Does this change a context's invariant?
    • If yes: Is new invariant documented?
  3. Does this add new language (terms)?
    • If yes: In which context? Is it consistent?

Key Principles (from Vision)

Primitives Over Frameworks

  • Aether provides composition points (interfaces), not opinions
  • Each context has clear boundaries; app wires them together
  • Example: SaveEvent returns error; app decides retry strategy

NATS-Native

  • Built for JetStream from the start
  • Event distribution, durability, and clustering all via NATS
  • Not a bolted-on abstraction

Resource Conscious

  • Efficient on modest hardware
  • ARM64 friendly
  • No heavy dependencies

Events as Complete History

  • Events are source of truth
  • State is derived by replay
  • Audit trail is native

Boundary Rules (Summary)

Language Boundaries

Different terms → Different contexts. Example:

  • "Event" in Event Sourcing = immutable fact
  • "Event" in CQRS read models = notification of change
  • These are different concepts; keep separate

Lifecycle Boundaries

Different timescales → Different contexts. Example:

  • Event lifetime: Create → Persist → Replay forever
  • Shard lifetime: Assign → Migrate → Reassign
  • These have different operations; different contexts

Ownership Boundaries

Different owners → Different contexts. Example:

  • Event Sourcing: App writes events; Library stores
  • Cluster Coordination: Library manages; App doesn't directly control
  • Each context has clear ownership

Scaling Boundaries

Different performance needs → Different contexts. Example:

  • Event Bus: Must be fast (us); non-blocking
  • Cluster Coordination: Can be slow (seconds); eventual consistency OK
  • Different scaling strategies

How Bounded Contexts Emerged

From Problem Space

  1. Event Sourcing journey → Events are facts, versions matter, replay needed
  2. Scaling journey → Cluster leadership, shard distribution needed
  3. Namespace journey → Isolation patterns, wildcard risks
  4. Concurrency journey → Version conflicts, retry strategy needed
  5. Distribution journey → Event bus, cross-node routing needed

Cut by Boundaries

  • Language: Each journey uses different terms
  • Lifecycle: Events persist forever; leases expire; subscriptions created/destroyed
  • Ownership: App writes events; Library coordinates cluster; App filters subscriptions
  • Scaling: Single actor scales by snapshots; cluster scales by shards; bus scales by subscribers

Validated Against Code

  • Each context has dedicated module(s)
  • Code structure aligns with intended boundaries
  • Gaps identified (actor migration, snapshot strategy, namespace validation)

Anti-Patterns Avoided

Anti-Pattern What Aether Does Instead Why
One big event model Generic Event struct; domain language in strings Primitives approach
Automatic retry on conflict Return error to app App owns retry strategy
Opinionated multi-tenancy Namespace primitives; app defines semantics Avoid framework opinions
Wildcard subscriptions default Explicit namespace; wildcard opt-in with warnings Security-first
Shared state across contexts Events flow between contexts; each owns its data Clean boundaries

Decision Gates

After vision: Can you crisply answer who/what/why?

  • ✓ Aether: For Go teams; removes distributed complexity; no framework opinions

After problem space: Do you see events, not just CRUD?

  • ✓ Aether: 25+ business events across 4 journeys; clear decisions and risks

After contexts: Are boundaries clear?

  • ✓ Aether: 5 contexts with distinct language, lifecycle, ownership, scaling

After domain models: Does each aggregate enforce an invariant?

  • → Next step (not yet done)

After capabilities: Can each capability be demoed?

  • → Next step (not yet done)

After features: Does each feature move a capability?

  • → Next step (not yet done)


Summary

Aether is at Step 3 of the strategy chain: Bounded Contexts Identified.

What's done:

  • Vision: Clear product promise (primitives for distributed event sourcing)
  • Problem space: 4 journeys, 25+ events, 6 decisions, 6 risks
  • Bounded contexts: 5 contexts with clear boundaries; code aligns

What's next:

  • Domain models: Define aggregates and invariants per context
  • Capabilities: System abilities (what can developers do?)
  • Features: User value slices (what's on the roadmap?)
  • Issues: Executable work (what's the next sprint?)

Team alignment: Use BOUNDED_CONTEXT_MAP.md + CONTEXT_MAP_DIAGRAM.md to verify all stakeholders understand the domain boundaries before diving into implementation.