Skip to main content

Asset Compatibility Backfill

Summary

Source-backed account of the transitional ETL that reads asset records from the monolith and upserts them into the Asset Service database while preserving the legacy identity space. It reads the source read-only, never deletes, and raises no domain events.

Audience

Backend engineers, database reviewers, architects, QA, support, operations, security reviewers, and product owners.

Overview

The backfill is a transitional command-line mode (not a web host) that copies monolith asset records into the Asset Service as Asset aggregates. It preserves the monolith record id as the compatibility identity, scopes work per tenant, handles duplicates and unusable rows deterministically, and supports a dry run. It exists to bridge the monolith and the service during cutover; the plan for retiring it is out of source.

Confirmed persistence behavior

  • Purpose. Populate the Asset Service Assets data from the monolith's asset records during migration.
  • Source system. The monolith database is read strictly read-only: every source statement is a SELECT, executed paged, ordered by id, with the assignee's labor id resolved through a left join. The backfill never writes to the source.
  • Target aggregate. Rows are materialized as Asset aggregates in the Asset Service database.
  • Identity mapping. The compatibility identity is set equal to the monolith record id and inserted verbatim. A dedicated backfill DbContext overrides the runtime identity behavior so the numeric compatibility column is treated as value-generated-never, and the aggregate's Guid id is derived deterministically so re-runs address the same row.
  • Tenant scoping. Work runs per tenant with an explicit tenant predicate; a null tenant context is used so the standard query filters are bypassed while the explicit predicate does the scoping.
  • Duplicate handling. Duplicate source ids are grouped with a last-wins rule; existing targets are loaded by compatibility id (filters ignored) and then inserted if missing, updated if changed, or skipped if identical. Rows lacking a usable code or name are skipped.
  • Dry run. A dry-run mode reads and compares only and never calls save, so it reports intended changes without writing.
  • Batch behavior and retry. Processing is batched; a failed batch is retried before being marked failed.
  • Persistence boundary. The backfill is upsert-only and performs no deletes. The rehydrate/set-monolith-state path builds aggregate state without raising domain events, so the backfill emits nothing to the outbox.
  • Audit and resume marker. On tenant completion the runner writes a completion marker row into the audit log (no schema change), which lets a resumable run skip already-completed tenants; a dry run only logs.
  • Failure evidence. Batch failures are retried and then recorded as failed rather than silently dropped.
  • Parity validation. A validator checks asset counts, assigned counts, per-status totals under the monolith-to-service status map, code-uniqueness (distinct equals total), missing-labor rows, and per-type totals.

Classification

Implemented transitional, idempotent, upsert-only ETL with read-only source access and no event emission.

Requires confirmation

  • Operational ownership of running the backfill in each environment.
  • The retirement plan for the backfill and the monolith source once cutover completes.

Diagram

See Also

Keywords

  • Asset backfill
  • Compatibility identity
  • Draft database documentation

Source References

  • microservices/src/asset-service/Backfill/AssetRecordBackfill.cs
  • microservices/src/asset-service/Backfill/AssetBackfillRunner.cs
  • microservices/src/asset-service/Backfill/AssetBackfillValidator.cs
  • microservices/src/asset-service/Backfill/AssetMonolithSourceReader.cs

Revision Information

  • Status: Draft
  • Last reviewed: 2026-07-17
  • Review cycle: Quarterly