Domain Model
This diagram illustrates the Domain-Driven Design (DDD) model in BlueRobin, showing aggregates, entities, value objects, and their relationships.
Aggregate Structure
classDiagram
direction TB
class AggregateRoot {
<>
+BlueRobinId Id
-List~IDomainEvent~ _domainEvents
+RaiseDomainEvent(event)
+ClearDomainEvents()
}
class Entity {
<>
+BlueRobinId Id
}
class Archive {
<>
+BlueRobinId Id
+string Name
+BlueRobinId CreatedBy
+DateTime CreatedOn
+Create(name, createdBy)$ Archive
}
class Document {
<>
+BlueRobinId Id
+BlueRobinId ArchiveId
+BlueRobinId CreatedBy
+DocumentStatus Status
+DocumentMetadata Metadata
+DocumentAnalysis Analysis
+DocumentClassification Classification
+ProcessingMetrics Metrics
+DateTime CreatedOnUtc
+Create(archiveId, createdBy, fingerPrint, fileName, fileSize, contentType)$ Document
+UpdateStatus(status)
+RecordOcrTime(ms)
+RecordAnalysisTime(ms)
+UpdateAnalysis(summary, keywords, friendlyName)
}
class ApplicationUser {
<>
+BlueRobinId Id
+string ExternalId
+string Email
+string DisplayName
+bool IsActive
+DateTime CreatedAt
+DateTime? LastLoginAt
}
class CanonicalEntity {
<>
+BlueRobinId Id
+string Name
+string Type
+BlueRobinId OwnerUserId
+string? NormalizedName
+Create(name, type, ownerId)$ CanonicalEntity
}
class EntityRelationship {
<>
+BlueRobinId Id
+BlueRobinId SourceEntityId
+BlueRobinId TargetEntityId
+BlueRobinId RelationshipTypeId
+BlueRobinId DocumentId
}
AggregateRoot <|-- Archive
AggregateRoot <|-- Document
AggregateRoot <|-- ApplicationUser
AggregateRoot <|-- CanonicalEntity
AggregateRoot <|-- EntityRelationship
Entity <|-- AggregateRoot Value Objects
classDiagram
direction LR
class BlueRobinId {
<>
+string Value
+New()$ BlueRobinId
+From(string)$ BlueRobinId
-GenerateId()$ string
Note: 10-char alphanumeric
}
class FingerPrint {
<>
+string Hash
+FromContent(bytes)$ FingerPrint
+FromStream(stream)$ FingerPrint
Note: SHA256 hash
}
class DocumentMetadata {
<>
+string FileName
+string ContentType
+long FileSize
+string ObjectName
+FingerPrint FingerPrint
+int PageCount
+CreateWithGeneratedObjectName(...)$ DocumentMetadata
}
class DocumentAnalysis {
<>
+string? Summary
+string? Keywords
+string? FriendlyName
+int ChunkCount
+Empty()$ DocumentAnalysis
+WithSummary(summary)
+WithKeywords(keywords)
+WithFriendlyName(name)
}
class DocumentClassification {
<>
+string Category
+float Confidence
+DateTime? ClassifiedAt
+Unclassified()$ DocumentClassification
+Create(category, confidence)$ DocumentClassification
}
class ProcessingMetrics {
<>
+long? OcrTimeMs
+long? AnalysisTimeMs
+long? EmbeddingTimeMs
+long? TotalTimeMs
+Empty()$ ProcessingMetrics
+WithOcrTime(ms)
+WithAnalysisTime(ms)
}
class ObjectReference {
<>
+string Bucket
+string Key
+Create(bucket, key)$ ObjectReference
}
class SearchFilters {
<>
+string? Query
+DateRange? DateRange
+string[]? Categories
+string[]? Keywords
} Document Aggregate Detail
classDiagram
direction TB
class Document {
<>
+BlueRobinId Id
+BlueRobinId ArchiveId
+BlueRobinId CreatedBy
+DocumentStatus Status
+DocumentMetadata Metadata
+DocumentAnalysis Analysis
+DocumentClassification Classification
+ProcessingMetrics Metrics
}
class DocumentMetadata {
<>
+string FileName
+string ContentType
+long FileSize
+string ObjectName
+FingerPrint FingerPrint
+int PageCount
}
class DocumentAnalysis {
<>
+string? Summary
+string? Keywords
+string? FriendlyName
+int ChunkCount
}
class DocumentClassification {
<>
+string Category
+float Confidence
+DateTime? ClassifiedAt
}
class ProcessingMetrics {
<>
+long? OcrTimeMs
+long? AnalysisTimeMs
+long? EmbeddingTimeMs
}
class DocumentStatus {
<>
Pending
Processing
Completed
Failed
}
class FingerPrint {
<>
+string Hash
}
Document *-- DocumentMetadata : contains
Document *-- DocumentAnalysis : contains
Document *-- DocumentClassification : contains
Document *-- ProcessingMetrics : contains
Document --> DocumentStatus : has
DocumentMetadata *-- FingerPrint : contains Domain Events
classDiagram
direction TB
class IDomainEvent {
<>
+DateTime OccurredAt
}
class DocumentAddedEvent {
+BlueRobinId DocumentId
+BlueRobinId ArchiveId
+BlueRobinId CreatedBy
+string FileName
+string ContentType
+long FileSize
+string ObjectName
}
class DocumentStatusChangedEvent {
+BlueRobinId DocumentId
+DocumentStatus OldStatus
+DocumentStatus NewStatus
}
class DocumentAnalysisUpdatedEvent {
+BlueRobinId DocumentId
+string Summary
+string Keywords
+string FriendlyName
}
IDomainEvent <|.. DocumentAddedEvent
IDomainEvent <|.. DocumentStatusChangedEvent
IDomainEvent <|.. DocumentAnalysisUpdatedEvent Repository Interfaces
classDiagram
direction TB
class IRepository~T~ {
<>
+GetByIdAsync(id) Task~T?~
+AddAsync(entity) Task
+UpdateAsync(entity) Task
+DeleteAsync(entity) Task
}
class IDocumentsRepository {
<>
+GetByArchiveIdAsync(archiveId) Task~List~Document~~
+GetByFingerprintAsync(fingerprint) Task~Document?~
+GetByUserIdAsync(userId, filters) Task~PagedResult~Document~~
}
class IArchivesRepository {
<>
+GetByOwnerIdAsync(ownerId) Task~Archive?~
+ExistsAsync(id) Task~bool~
}
class IUsersRepository {
<>
+GetByExternalIdAsync(externalId) Task~ApplicationUser?~
+GetByEmailAsync(email) Task~ApplicationUser?~
}
IRepository <|-- IDocumentsRepository
IRepository <|-- IArchivesRepository
IRepository <|-- IUsersRepository Key DDD Patterns Used
| Pattern | Implementation | Example |
|---|---|---|
| Aggregate Root | AggregateRoot base class |
Document, Archive |
| Value Object | Immutable records | BlueRobinId, FingerPrint |
| Domain Event | Event sourcing | DocumentAddedEvent |
| Factory Method | Static Create() methods |
Document.Create(...) |
| Repository | Interface per aggregate | IDocumentsRepository |
| Specification | Search filters | SearchFilters |