Skip to main content

Asset Storage

Summary

Source-backed persistence of the canonical Asset aggregate root — its scalar columns, owned value objects, lifecycle state, generated values, and current integrity gaps.

Audience

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

Overview

Asset is the aggregate root of the Asset bounded context and maps to the Assets table. It carries the tenant scope, a compatibility identity, four owned value objects, free-text category, lifecycle status and condition, an optional assignee, workflow linkage, and creation/update evidence. Assignment history and document references are owned children (documented separately) that cascade from the same table's key.

Confirmed persistence behavior

FieldStorageRequiredNotes
IdGuid primary keyYesAssigned by the aggregate factory (not a DB default at runtime)
TenantIdintegerYesTenant scope; participates in query filter and composite indexes
TenantKeyvarchar(120)NoOptional tenant slug
CompatIdinteger identityYesNumeric external id; unique index; DB identity at runtime, app-assigned during backfill
Codeowned AssetCodeAssetCode varchar(80)YesUpper-cased; non-unique lookup index
AssetTypevarchar(120)YesFree-text category, default General, normalized and length-checked
Nameowned AssetNameAssetName varchar(200)YesDisplay name
Serialowned SerialNumberSerialNumber varchar(160)Yes at DBEmpty string allowed for requests/consumables
Assigneeowned AssetAssigneeAssignedToUserId, LaborIdNoBoth integer, nullable; identifier-only references
AssignedOnUtctimestamptzNoSet on issue, cleared on return/available
ReturnDueDatetimestamp without time zoneNoDate-only
ConditionAssetCondition enum → varchar(40)YesDefault New
StatusAssetStatus enum → varchar(40)YesDefault Available
Notesvarchar(2000)NoFree text
WorkflowInstanceIdGuidNoSet when approval is delegated to the Workflow Service
CreatedOnUtc / UpdatedOnUtctimestamptzYesLifecycle evidence
  • Owned value objects persist as columns on the same row: AssetCode, AssetName, SerialNumber, and the assignee pair AssignedToUserId/LaborId. See Value-Object Conversions.
  • Enums AssetStatus (Available, Requested, Approved, Issued, Rejected, Returned, Damaged, Lost, Repair, Retired) and AssetCondition (New, Good, Repair, Damaged, Lost) are stored as strings, not integers.
  • Ignored domain property: DomainEvents is not mapped (Ignore). Computed properties (IsWorkflowManaged, IsDeletable) are not persisted.
  • Generated values: CompatId uses a database identity column at runtime; Id is a Guid supplied by the factory.
  • Lifecycle storage: status transitions mutate Status/Condition/Assignee in place and stamp UpdatedOnUtc; each transition also appends an assignment-history row.
  • Duplicate prevention: per-tenant asset-code uniqueness is enforced in the application layer (CodeExistsAsync over the tenant-filtered query). The AssetCode index is non-unique; there is no database unique constraint on the code.

Integrity gaps

  • No database uniqueness on AssetCode (application-enforced only) or on SerialNumber (none at all).
  • AssignedToUserId, LaborId, and WorkflowInstanceId are identifier-only values with no foreign keys.
  • No concurrency token protects concurrent lifecycle transitions. See Concurrency.

Classification

Implemented aggregate persistence with Transitional compatibility identity.

Requires confirmation

Per-tenant code-uniqueness hardening, serial-number policy, and concurrency protection require confirmation.

Diagram

See Also

Keywords

  • Asset persistence
  • Asset Storage
  • Draft database documentation

Source References

  • microservices/src/asset-service/Domain/Asset/Asset.cs
  • microservices/src/asset-service/Infrastructure/AssetDbContext.cs
  • microservices/src/asset-service/Domain/Common/Enums.cs
  • microservices/src/asset-service/Infrastructure/Migrations/AssetDbContextModelSnapshot.cs

Revision Information

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