Skip to main content

Asset Data Integrity

Summary

Source-backed map of the integrity controls protecting Asset data — domain invariants on the aggregate, application-layer checks, database constraints and indexes, and expectations that are not enforced anywhere — presented as a classification matrix.

Audience

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

Overview

Asset integrity is layered. The Asset aggregate enforces lifecycle and assignment invariants in domain code; application commands enforce tenant presence, code-duplication, and workflow guards; the database enforces primary keys, two foreign keys, three unique indexes, and NOT NULL / length constraints. Several business expectations — serial uniqueness, one active assignment, and cross-service reference validity — are not enforced at the database level.

Confirmed persistence behavior

Integrity matrix

RuleDomain-enforcedApplication-enforcedDatabase-enforcedUI-onlyUnenforced expectation
Valid lifecycle transition (bad transition throws DomainValidationException)Yes
Assignable status / assignee required to assignYes
Only Issued may returnYes
Only Requested may approve / reject; rejection reason requiredYesReject-reason also checked
Retired is terminal (already-retired throws; retired cannot be edited)Yes
Deletion eligibility (IsDeletable = Available / Requested / Rejected)YesGate before delete
Document-reference ownership (children owned by aggregate)YesFK AssetId → Assets (cascade, required)
Tenant context required for writes (RequireTenantId)Factory rejects tenantId ≤ 0Yes (RequireTenantId)
Per-tenant asset-code uniqueness (CodeExistsAsync, 409 Conflict)YesNoAssetCode index is non-unique
Workflow callback idempotency (Status ≠ Requested → acknowledge)Yes
Workflow-managed guard (direct action while managed → 409)Yes
Clearance blocking states (Issued / Damaged / Lost / Repair)Query-level, read-only
Primary-key uniqueness (7 keys, all Guid)Yes
CompatId uniquenessYes (UX_Assets_CompatId)
Outbox / processed-event EventId uniquenessYes (unique indexes)
One current custodian (single Assignee on the aggregate)Aggregate holds a single assigneeNo DB constraintConcurrent assigns could each read Available
Serial-number uniquenessNoNot enforced anywhere
Employee / labor / workflow / document reference validityNo FK (identifier-only)Cross-service validity not enforced
Concurrency protection on transitionsStatus re-check onlyNo concurrency tokenSee Concurrency

Notes on each layer

  • Domain invariants live on the Asset aggregate: tenant required (> 0), valid state transitions, assignee required to assign, only-Issued-returns, only-Requested-approves/rejects, rejection reason required, retired terminal, and the IsDeletable gate. Violations throw DomainValidationException.
  • Application checks (AssetCommands, compatibility/workflow integration): RequireTenantId(), the CodeExistsAsync duplicate check surfaced as 409, the workflow-managed guard (409), and workflow-callback idempotency.
  • Database constraints: seven primary keys, two cascade foreign keys (history → asset, document reference → asset), three unique indexes (CompatId, outbox EventId, processed-event EventId), and NOT NULL / max-length on required columns.
  • Not database-enforced: per-tenant code uniqueness (application-only, and a unique index would be global-across-tenants), serial uniqueness (none), one-active-assignment (none), and all cross-service references, which are identifier-only with no foreign keys.

Classification

Implemented layered integrity with domain and application coverage; several business-level uniqueness and cross-service expectations are Unenforced at the database level by design.

Requires confirmation

Whether serial uniqueness, database-level per-tenant code uniqueness, a one-active-assignment constraint, and concurrency protection should be hardened requires product and database confirmation.

Diagram

See Also

Keywords

  • Asset persistence
  • Data Integrity
  • Draft database documentation

Source References

  • microservices/src/asset-service/Domain/Asset/Asset.cs
  • microservices/src/asset-service/Application/Commands/AssetCommands.cs
  • microservices/src/asset-service/Infrastructure/AssetDbContext.cs
  • microservices/src/asset-service/Infrastructure/Migrations/AssetDbContextModelSnapshot.cs

Revision Information

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