feat(apps): per-workload deploy history, rollback, and resource metrics
Two additions to the app detail page, each backed by a per-workload
endpoint.
Deploy history + rollback:
- New deploy_history table — a structured, version-pinned ledger of every
dispatch (success AND failure), distinct from the free-text event_log.
Recorded at the single DispatchPlugin choke point so every source kind
is covered. The raw deploy error is never persisted (it can carry
registry-auth / compose-stdout secrets) — only a generic marker, with
detail going to slog. Pruned to the newest N per workload; cascade-
deleted with the workload.
- GET /api/workloads/{id}/deploys lists the ledger; POST .../rollback
(admin) replays a prior successful deploy's pinned reference as a
rollback-reason dispatch. Phase 1 is image-source only (RollbackCapable);
git-built sources need checkout-by-commit, a later phase.
- DeployHistoryPanel.svelte renders the ledger with confirm-gated rollback.
Per-workload metrics:
- ListContainerStatsSamplesByWorkload joins the existing container stats
samples through the containers index; GET /api/workloads/{id}/stats/history
aggregates CPU/memory per timestamp across the workload's containers.
- WorkloadMetricsPanel.svelte reuses ResourceChart (CPU% + memory MiB,
windowed, 15s poll).
en/ru i18n added with parity. Tests: store CRUD + cascade + workload-scoped
join, deployer recording (incl. secret-non-leak on failure), API rollback
guards, and per-timestamp aggregation. Plans under docs/plans/.
This commit is contained in:
@@ -507,3 +507,28 @@ type App struct {
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// DeployHistoryEntry is one row in the per-workload deploy ledger. Unlike
|
||||
// event_log (free-text human timeline), this is the structured, version-
|
||||
// pinned record the rollback action replays from. Reference is the
|
||||
// effective deployed artifact handle (image tag for image sources, commit
|
||||
// sha for git-built sources, "" when none applies). Error is NEVER the raw
|
||||
// source error — that can carry registry-auth bytes or compose stdout; it
|
||||
// holds only a fixed, secret-free marker. Raw detail goes to slog.
|
||||
type DeployHistoryEntry struct {
|
||||
ID int64 `json:"id"`
|
||||
WorkloadID string `json:"workload_id"`
|
||||
SourceKind string `json:"source_kind"`
|
||||
Reference string `json:"reference"` // effective tag | commit sha | ""
|
||||
Reason string `json:"reason"` // manual|registry-push|git-push|cron|rollback|promote
|
||||
TriggeredBy string `json:"triggered_by"`
|
||||
Note string `json:"note"`
|
||||
Outcome string `json:"outcome"` // success | failure
|
||||
Error string `json:"error"` // generic, secret-free marker on failure
|
||||
StartedAt string `json:"started_at"`
|
||||
FinishedAt string `json:"finished_at"`
|
||||
// Rollbackable is computed at the API layer (not persisted): a row is
|
||||
// rollbackable when it succeeded, has a non-empty Reference, and its
|
||||
// source kind supports reference-pinned redeploy.
|
||||
Rollbackable bool `json:"rollbackable"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user