"What's deploying" feed
Vetrix exposes an instance-wide deployment-transition feed that powers a root-layout banner showing which deployments are in flight across every repo the viewer can see. The backend primitives — event shape, per-viewer ACL filter, per-socket rate limiter, banner-row renderer, auto-hide trigger — are available today. The WebSocket hub, React banner, Prometheus exporter, and Playwright coverage are tracked as focused follow-ups.
Event shape
type FeedEvent struct {
DeploymentID uuid.UUID
RepoID uuid.UUID
RepoSlug string
EnvironmentID uuid.UUID
Environment string
State string // queued | pending | in_progress | success | failure | error | inactive
Ref string
SHA string
ActorID uuid.UUID
At time.Time
}
The WebSocket layer at /ws/deployments (deferred) JSON-encodes this
verbatim. Field names match the deployments row payload so
receivers can reuse existing decoders.
Per-socket ACL filter
type ViewerAccess struct {
UserID uuid.UUID
Collaborator map[uuid.UUID]bool
PublicRepos map[uuid.UUID]bool
InstanceAdmin bool
}
CanSee(viewer, evt) bool
- Instance admin — always true.
- Viewer is a collaborator on
evt.RepoID— true. - Repo is in the public-visibility set — true.
- Otherwise — false. Private-repo events never reach non-collaborator sockets; this is an invariant of the filter.
Per-socket rate limiter
c := NewFeedCoalescer(20, time.Second) // 20 events / 1 s default
c.Offer(evt, now) bool
Non-terminal events past the cap are dropped; terminal events always
pass. IsTerminal(state) lists the four terminal states — success,
failure, error, inactive — so the client always sees the final
status of every deploy even under throttling.
Banner renderer
BuildBannerRows(active, cap)returns the topcapentries sorted byStartedAtdescending, plus a+N morecount for the overflow.ShouldAutoHide(lastActiveAt, now, 10*time.Second)returns true once the 10-second trailing window has elapsed since the last active deployment reached a terminal state.
Prometheus / OTLP naming (deferred)
Planned naming for the metrics layer:
- Counter:
vetrix_deployment_state_total{repo, env, state}— emit once per state transition (idempotency lives in the emitter). - Histogram:
vetrix_deployment_duration_seconds— recorded on terminal-state transition with labelsrepo,env,state. - OTLP span:
vetrix.deploymentwithrepo,env,state,ref,shaattributes.
Deferred follow-ups
- WebSocket hub + handler at
/ws/deployments— JWT gate, per-socket subscription, engine event-bus subscription. DeployingNowBanner.tsxReact component + root-layout mount.- Keyboard shortcut
g dregistered through the existing shortcut registry. - Prometheus + OTLP exporter wiring.
- Playwright two-browser sync end-to-end coverage.
The event shape + ACL filter + coalescer + banner-row + auto-hide helpers shipping today are the stable contract the deferred layers will consume.