Files
kami 9734eec63c docs: add module documentation in AsciiDoc with PlantUML diagrams
Generated by per-group subagents covering all 52 modules across:
core (18), infrastructure (10), apps (5), interfaces (3),
plugins (7), testing (9)

Documentation format:
- AsciiDoc (.adoc) files in docs/modules/<group>/
- PlantUML (.puml) files in docs/diagrams/
- .adoc files reference diagrams via include:: directives

Each doc covers: purpose, responsibilities, non-responsibilities,
key types, event flow, integration points, invariants, PlantUML
diagram, known issues, and open questions.
2026-05-26 16:59:21 +04:00

85 lines
4.0 KiB
Plaintext

= infra-persistence
== purpose
Provides concrete `EventStore` implementations for persisting and replaying the event log. Supports in-memory storage (for testing and ephemeral sessions) and SQLite-backed durable storage. Also provides a live artifact repository that subscribes to events and maintains an up-to-date in-memory view of artifact state per session.
== responsibilities
* Implement the `EventStore` interface for both transient and durable storage
* Enforce duplicate event ID detection and sequence ordering
* Provide reactive subscriptions via `Flow<StoredEvent>` per session and globally
* Maintain an artifact state projection that stays current via event subscription
* Support transactional batch appends for atomic event persistence
== non-responsibilities
* Does not define event serialization — uses `JsonEventSerializer` from `core:events`
* Does not implement CAS content-addressable storage — that belongs to `infra:artifacts-cas`
* Does not handle event compaction or retention
* Does not implement cross-session querying beyond `allSessionIds()`
== key types
=== InMemoryEventStore
* **kind**: class
* **purpose**: Thread-safe, in-memory event store backed by `ConcurrentHashMap`. Supports duplicate detection via `seenEventIds` set and session-scoped sequence numbers.
* **fields**: `streams` (per-session event lists), `sequences` (per-session sequence counters), `globalSeq` (global counter), `seenEventIds` (dedup set)
=== SqliteEventStore
* **kind**: class
* **purpose**: Durable event store backed by a SQLite database with WAL mode. Uses JDBC directly. Emits events to reactive flows after append.
* **fields**: `connection` (JDBC SQLite connection), `jsonSerializer` (serialization bridge), `artifactStore` (used for `flushBefore` coordination)
=== LiveArtifactRepository
* **kind**: class
* **purpose**: Subscribes to an `EventStore` per session and maintains an up-to-date in-memory `ConcurrentHashMap` of `ArtifactState` values. Supports lookup by session, stage, and artifact ID.
* **fields**: `artifactCache` (session → artifactId → state), `stageIndex` (session → artifactId → stageId), `subscriptions` (session → coroutine Job), `projector` (reduces events to state)
=== JDBCHelper
* **kind**: object
* **purpose**: Utility providing `Connection.transaction()` inline helper with automatic commit/rollback.
== event flow
*Inbound:*
* `ArtifactCreatedEvent`, `ArtifactValidatingEvent`, `ArtifactValidatedEvent`, `ArtifactRejectedEvent`, `ArtifactSupersededEvent`, `ArtifactArchivedEvent`, `ArtifactRelationshipAddedEvent` — consumed by `LiveArtifactRepository` to maintain artifact projections
* `NewEvent` — appended to event stores via `append()` / `appendAll()`
*Outbound:*
* `StoredEvent` — emitted via `Flow<StoredEvent>` subscriptions after each append
== integration points
* `core:events` — `EventStore`, `StoredEvent`, `NewEvent`, all artifact event payloads, `EventId`, `SessionId`
* `core:artifacts` — `ArtifactProjector`, `ArtifactReducer`, `ArtifactState`, `ArtifactRepository`
* `core:artifactstore` — `ArtifactStore` (used by `SqliteEventStore` for flush coordination)
== invariants
* Duplicate `eventId` values are rejected with an error
* Session sequence numbers are strictly monotonic — violations throw `error()`
* `InMemoryEventStore.append()` is synchronized per session for thread safety
* `SqliteEventStore` wraps appends in a JDBC transaction and coordinates with `ArtifactStore.flushBefore()`
* `LiveArtifactRepository` lazily subscribes on first query and never unsubscribes
== PlantUML diagram
[plantuml, infra-persistence, "png"]
----
include::../../diagrams/infra-persistence.puml[]
----
== known issues
* `SqliteEventStore` holds an open JDBC `Connection` for the lifetime of the application
* No connection pooling or retry logic for SQLite busy conditions
== open questions
* Should event stores support snapshot-based recovery for long event streams?
* Should there be a read-replica event store for projections to avoid write-contention?