Skip to content

ADR 0003 — BMO deploy history is a separate view, not a replacement for the legacy deploy-logs page#

Status Accepted
Date 2026-08-18
Authors Ruben Knuijver
Supersedes
Superseded by

Context#

BMO v2.3.0 added GET /api/logs/deploy/{environment}, described in its changelog as closing the "no operator-accessible deploy history" gap. The obvious follow-up in CommandCenter was to move the existing deploy-logs page (ClientApps/command-center/src/pages/deploy-logs/) off the legacy IIS API (/api/DeployLogsApi/*, via BFF cluster-legacy) and onto BMO, retiring one more legacy dependency.

That turns out not to be possible with the current BMO contract.

What BMO returnsBenefits.Contracts.Models.DeployLogEntry, six fields:

public record DeployLogEntry(
    int Key,
    DateTimeOffset CreateDate,
    string? Customer,
    string? Stage,
    string? OldVersion,
    string? NewVersion);

DeployLogService SELECTs exactly those six columns from TblDeployLog, resolving the customer, stage and version foreign keys via LEFT JOIN. It is a flat, newest-first history list.

What the legacy page rendersDeployLogModel, sixteen fields. The page is not a list; it is a state machine. getDeployLogs buckets every row into active / expired / failed / scheduledForRemoval / finished using finished, succeeded, expired, oldDatabase and oldDatabaseDeleted. On top of that it has:

  • a details drawer fetching log content via POST /api/DeployLogsApi/GetLog,
  • a SetDeleteDate mutation (POST /api/DeployLogsApi/SetDeleteDate),
  • a link to GET /v2/api/deploylogs/:key/database.

None of those fields or operations exist on the BMO side. A "migration" would therefore have meant silently deleting most of the page's function.

Decision#

Ship the BMO-backed history as a new, separate routepages/deploy-history/, registered at deploy-history — and leave pages/deploy-logs/ untouched on the legacy API.

The new view offers what BMO actually supports: environment selection, since / customer / limit filters, and a newest-first table of date, customer, stage and old → new version.

Consequences#

  • Two deploy-related pages coexist and will look redundant to operators. The new one is environment-scoped and read-only; the legacy one owns lifecycle state and old-database cleanup.
  • The legacy IIS dependency is not retired by this change.
  • useDeployLogQuery (BMO) and useDeployLogs (legacy) are different hooks over different contracts. The legacy hook stays page-scoped and out of the services/bmo barrel.
  • BMO's endpoint reads the environment's own database via a CommandCenter_{environment} connection string. Environments are offered from fleet installations, so an environment can be selectable but unqueryable — that fails with a 500 rather than an empty list, and the page shows an explicit error state saying so.

Alternatives considered#

Widen DeployLogEntry on the BMO side, then migrate. The preferred end state, and the only way to actually retire the legacy page. It needs BMO to project and expose Finished, Succeeded, Expired, OldDatabase, OldDatabaseDeleted, OldDatabaseDeleteDate, DeployStartDate and DeployEndDate, plus equivalents for log-content retrieval and SetDeleteDate. That is BMO-repo work and was out of scope here. This is the recommended follow-up.

Merge both sources in the SPA. Query BMO for history and the legacy API for lifecycle state, joining on Key. Rejected: it doubles the failure surface and couples the page to both backends while retiring neither.