Add persisted Event audit-stream foundation (read path)
Summary
First step toward Octopus-parity deployment history: a persisted, append-only Event audit stream to replace today's client-synthesized history (which can only derive release-created / deployment-started / deployment-completed from existing fields, with no provenance/snapshot). Read foundation only — no emission wiring yet (additive; nothing changes for users until later PRs).
-
Evententity — append-only (deliberately NOTIAuditable), lean: smallint-backedCategory+EstablishedWithenums, jsonb structuredReferences(the UI renders + linkifies the category template against these, so English text isn't duplicated per row), and first-class indexed document columns (project/release/deployment/environment/machine/server_task) for the known history access paths — faster + smaller than a jsonb relation blob, matchingServerTaskLog's existing index pattern. -
EventCategoryRegistry— the 12 categories (3 document-audit + 9 deployment-lifecycle), each with display name + message template; drift-pinned by tests. -
DbUp migration — lean
eventtable + partial composite indexes (keyset-paginated byid) + anoccurredindex for time-based retention; plus a lazyevent_document_snapshotside table (snapshots stay out of the hot feed). -
IEventService—RecordAsync(provenance fromICurrentUser) +GetEventsAsync(per-document filter, newest-first keyset pagination, clamped page size). ThinGetEventsRequesthandler → service (Rule 16/17). - Distinct from existing logs (no conflict):
ServerTaskLog= raw output,ActivityLog= execution tree,DeploymentInterruption/Completion= detail. Event is a thin audit pointer.
Deferred to planned follow-ups
PR-2 deployment-lifecycle emission · PR-3 document-audit interceptor + snapshot writes · PR-4 established-with/user-agent provenance polish · PR-5 frontend reads the real feed (+ diff) · RANGE partitioning (table is partition-ready — occurred is the future key; event has zero data so the conversion is clean before emission lands).
Test plan
-
Unit (8): EventCategoryRegistrydrift guard (every category has a descriptor) + display names + persisted enum-value pins -
Integration on real Postgres (3): RecordAsyncpersists + jsonb References round-trip; keyset pagination newest-first across pages; space + document isolation -
Squid.Api(Core + Message + Api), unit, and integration projects all build clean; purely additive (no existing files edited) -
CI: full unit + integration suites green