Estate Structures Domain
Overview
Section titled “Overview”The Estate Structures bounded context (estate_structures_v1) manages the hierarchical organization of physical assets and spaces within a company’s property portfolio. It provides comprehensive domain models for organizing estates, sites, buildings, rooms, and their spatial relationships through a topology system that tracks geographic features and floor plans.
Core Responsibility
Section titled “Core Responsibility”This domain answers the question: “How is our physical portfolio organized, and where are things located?”
It handles:
- Hierarchical structure: Estate → Site → Building → Room organization
- Spatial relationships: Geographic features, boundaries, footprints, and topology
- Floor plans: Visual representations with tile-based floor plan management
- Asset placement: Positioning of buildings and rooms within sites
- Change tracking: Versioning of topology and floor plan changes
Hierarchical Structure
Section titled “Hierarchical Structure”The domain models a four-level hierarchy that organizes physical assets:
Estate (root aggregate) ├── Site (site aggregate) │ ├── Building (building aggregate) │ │ └── Room (room aggregate) │ └── Topology (geographic features and spatial data) └── Floor Plans (visual layer for site floors)Estate Aggregate
Section titled “Estate Aggregate”The Estate is the root aggregate representing a company’s entire property portfolio. There is exactly one estate per workspace.
Responsibilities:
- Maintain metadata about the organization’s property portfolio
- Track the headquarters site
- Store organizational contact information
- Define the top-level container for all sites and buildings
Key Properties:
class EstateAggregate { final EstateId estateId; final EstateName name; final EstateDescription? description; final PostalAddress? address; final UserId? primaryContact; final SiteId? headquartersSiteId; final OrganizationName? officialOrganisationName; final UserId createdBy; final DateTime createdAt; final DateTime updatedAt;}Example Creation:
// Estate created event - represents a new estate in the systemEstateCreatedEvent( estateId: EstateId('estate-001'), name: EstateName('Acme Corporation Properties'), description: EstateDescription('Central property portfolio'), address: PostalAddress( streetAddress: '123 Business Ave', city: 'London', countryCode: 'GB', ), createdBy: UserId('user-123'), createdAt: DateTime.now(),)Site Aggregate
Section titled “Site Aggregate”The Site aggregate represents a physical location within the estate (e.g., a campus, office building, warehouse).
Responsibilities:
- Manage site metadata and metadata (name, description, location)
- Track all buildings within the site
- Maintain the published topology version
- Coordinate spatial structure and floor plan information
Key Properties:
class SiteRootAggregate { final SiteId siteId; final EstateId estateId; final SiteName name; final SiteDescription? description; final SiteTypeEnum? siteType; // office, warehouse, retail, etc. final SiteLocation location; final TopologyVersion? publishedTopologyVersion; final List<BuildingId> buildingIds; final UserId createdBy; final DateTime createdAt; final DateTime updatedAt;}Site Location Structure:
class SiteLocation { final PostalAddress? postalAddress; final GeoPoint? geoPoint; // Latitude/Longitude final String? countryCode; // ISO country code}Example Creation:
SiteCreatedEvent( siteId: SiteId('site-london-hq'), estateId: EstateId('estate-001'), name: SiteName('London Headquarters'), siteType: SiteTypeEnum.office, address: PostalAddress( streetAddress: '100 Main Street', city: 'London', countryCode: 'GB', ), mapMarkerPosition: GeoPoint(latitude: 51.5074, longitude: -0.1278), createdBy: UserId('user-123'), createdAt: DateTime.now(),)Building Aggregate
Section titled “Building Aggregate”The Building aggregate represents a physical structure within a site.
Responsibilities:
- Maintain building metadata (name, description, usage type)
- Track geometric placement (anchor point or full footprint)
- Store unique property reference (UPRN)
- Link to the parent site
Key Properties:
class BuildingAggregate { final BuildingId buildingId; final SiteId siteId; final BuildingName name; final BuildingDescription? description; final BuildingUsageType? usageType; // office, retail, residential, etc. final UniquePropertyReference? uprn; // UK property identifier final GeoJSONPoint? anchor; // Single point location final FeaturePointer? geometry; // Full polygon geometry final UserId createdBy; final DateTime createdAt; final DateTime updatedAt;}Placement Status:
A building is considered “placed” if it has either:
- A geometry (full polygon footprint)
- An anchor point (single location)
// Check if building has geographic placementbool get isPlaced => geometry != null || anchor != null;Example Creation:
BuildingCreatedEvent( buildingId: BuildingId('bldg-001'), siteId: SiteId('site-london-hq'), name: BuildingName('Main Office Tower'), usageType: BuildingUsageType.office, uprn: UniquePropertyReference('123456789'), createdBy: UserId('user-123'), createdAt: DateTime.now(),)Room Aggregate
Section titled “Room Aggregate”The Room aggregate represents an indoor space within a site or building.
Responsibilities:
- Maintain room metadata (name, description, type)
- Track room geometry (polygon outline)
- Link to parent site
- Support room type taxonomy
Key Properties:
class RoomAggregate { final RoomId roomId; final SiteId siteId; final RoomName name; final RoomDescription? description; final RoomTypeEnum? roomType; // office, meeting, storage, etc. final FeaturePointer? geometry; // Room boundary polygon final UserId createdBy; final DateTime createdAt; final DateTime updatedAt;}Example Creation:
RoomCreatedEvent( roomId: RoomId('room-001'), siteId: SiteId('site-london-hq'), name: RoomName('Meeting Room A'), roomType: RoomTypeEnum.meeting, createdBy: UserId('user-123'), createdAt: DateTime.now(),)Geographic Topology System
Section titled “Geographic Topology System”The domain includes a sophisticated topology system for managing spatial relationships and geographic features.
GeoFeature Entity
Section titled “GeoFeature Entity”GeoFeature represents a geographic element within a site’s topology (building boundaries, room outlines, site boundaries, etc.).
Key Properties:
class GeoFeature { final GeoFeatureKey key; // Stable identifier final GeoFeatureKind geoFeatureKind; // Type of feature final BuildingLevel? level; // Floor number final BuildingId? buildingId; // Parent building final SiteBoundaryId? siteBoundaryId; // Site boundary reference final RoomId? roomId; // Room reference final GeoJSONGeometry? geometry; // Polygon/LineString/Point final List<double>? bbox; // [west, south, east, north] final List<String>? covering; // S2 cells or geohashes final List<double>? zRangeMeters; // [zMin, zMax) final GeometryOrientation? geometryOrientation; final GeoFeatureName? name; final TaxonomyEnum? usageType;}Feature Kinds:
The domain supports multiple types of geographic features:
enum GeoFeatureKind { siteBoundary, // Overall site perimeter buildingFootprint, // Building outline unplacedBuilding, // Building without location room, // Indoor space virtualFootprint, // Computed from floor plans generic // Fallback type}Feature IDs:
Each feature generates a canonical feature ID based on its kind:
// buildingFootprint -> "building-${buildingId}"// room -> "room-${buildingId}-${level}-${roomId}"// siteBoundary -> uses siteBoundaryId value directlyGeoFeatureId get featureId { ... }SiteTopologyAggregate
Section titled “SiteTopologyAggregate”SiteTopologyAggregate manages all geographic features and spatial relationships for a single site.
Responsibilities:
- Aggregate all geographic features (features collection)
- Track topology versioning (topologySequence)
- Manage floor plan tile metadata
- Link features to attachments (PDFs, images)
- Support draft and published topology states
Key Properties:
class SiteTopologyAggregate { final SiteId siteId; final List<GeoFeature> features; final bool isPublished; final Map<FloorPlanImageTileId, FloorPlanTileMeta> floorPlanTiles; final Map<GeoFeatureKey, FeatureAttachmentRef> featureAttachments; final int topologySequence; final UserId createdBy; final DateTime createdAt; final DateTime updatedAt;}Topology States:
- Draft: Mutable topology in editing mode, can be modified before publishing
- Published: Immutable topology, represents a stable version
SiteTopologyVersionAggregate (V2)
Section titled “SiteTopologyVersionAggregate (V2)”A newer topology version aggregate with enhanced spatial capabilities:
Key Properties:
class SiteTopologyVersionAggregate { final SiteId siteId; final SiteTopologyVersionId versionId; final bool isDraft; final GeoJSONPolygon? boundary; // Site extent final Map<BuildingId, GeoJSONPolygon> buildingFootprints; final Map<RoomId, GeoJSONPolygon> rooms; final Map<MapTileId, MapTile> mapTiles; final UserId createdBy; final DateTime createdAt; final DateTime updatedAt;}Floor Plan System
Section titled “Floor Plan System”The domain includes a tile-based floor plan system for visual floor representations.
FloorPlanTile Value Object
Section titled “FloorPlanTile Value Object”FloorPlanTile represents a single visual tile of a floor plan (e.g., a scanned floor plan image with positioning).
Properties:
class FloorPlanTile { final String tileId; final GeoJSONGeometry shape; // Polygon or MultiPolygon in site CRS final String mediaRef; // URI to image/PDF final double opacity; // 0.0 to 1.0 final int zIndex; // Render order final Map<String, dynamic>? affineTransform; // Scale/rotation metadata}FloorPlanTileSet Aggregate
Section titled “FloorPlanTileSet Aggregate”FloorPlanTileSetAggregate manages a collection of floor plan tiles for a specific floor/level.
Responsibilities:
- Aggregate multiple floor plan tiles
- Manage tile lifecycle (add, update, remove)
- Track publication state
- Coordinate with topology for spatial reference
Example Structure:
FloorPlanTileSet (for Level "Ground Floor") ├── FloorPlanTile (South Wing) ├── FloorPlanTile (East Wing) └── FloorPlanTile (West Wing)Domain Events
Section titled “Domain Events”The domain emits rich events to track all state changes. These events are persisted and can be replayed to reconstruct aggregate state.
Estate Events
Section titled “Estate Events”EstateCreatedEvent - When a new estate is created:
class EstateCreatedEvent { final EstateId estateId; final EstateName name; final EstateDescription? description; final PostalAddress? address; final SiteId? headquartersSiteId; final OrganizationName? officialOrganisationName; final UserId createdBy; final DateTime createdAt;}EstateUpdatedEvent - When estate properties change
UserAddedToEstateLedgerEvent - When a user is granted access to an estate
Site Events
Section titled “Site Events”SiteCreatedEvent - When a new site is created
SiteUpdatedEvent - When site metadata changes
SiteLocationUpdatedEvent - When location information changes
SiteTopologyPublishedEvent - When topology is published
Building Events
Section titled “Building Events”BuildingCreatedEvent - When a new building is added
class BuildingCreatedEvent { final BuildingId buildingId; final SiteId siteId; final BuildingName name; final BuildingDescription? description; final BuildingUsageType? usageType; final UniquePropertyReference? uprn; final UserId createdBy; final DateTime createdAt;}BuildingUpdatedEvent - When building properties change
BuildingFootprintSetEvent - When building geometry is added/updated
BuildingGeometryUpdatedEvent - When geometric placement changes
Room Events
Section titled “Room Events”RoomCreatedEvent - When a new room is created
RoomUpdatedEvent - When room properties change
RoomGeometryUpdatedEvent - When room geometry is set/changed
Topology Events
Section titled “Topology Events”SiteBoundarySetEvent - When site boundary polygon is set
FloorFootprintSetEvent - When floor/building footprint is set
FloorPlanImageTransformSetEvent - When floor plan positioning is adjusted
SiteBoundaryRenamedEvent - When boundary is renamed
MapTileAddedEvent - When a new map tile is added to topology
SiteTopologyPublishedEvent - When complete topology is published
TopologyValidationFailedEvent - When topology fails validation
Floor Plan Events
Section titled “Floor Plan Events”FloorPlanTileSetPublishedEvent - When floor plan tiles are published
Directives
Section titled “Directives”Directives are commands that trigger state changes. The domain provides directives for all major operations.
Estate Directives
Section titled “Estate Directives”CreateEstateDirective - Create a new estate
class CreateEstatePayload { final EstateId estateId; final EstateName name; final EstateDescription? description; final PostalAddress? address; final UserId createdBy;}UpdateEstateDirective - Update estate properties
DeleteEstateDirective - Remove an estate
Site Directives
Section titled “Site Directives”CreateSiteDirective - Create a new site
class CreateSitePayload { final SiteId siteId; final EstateId estateId; final SiteName name; final SiteDescription? description; final SiteTypeEnum? siteType; final PostalAddress? address; final GeoPoint? mapMarkerPosition; final UserId createdBy;}DeleteSiteDirective - Remove a site
SetSiteLocationDirective - Update site location
Building Directives
Section titled “Building Directives”CreateBuildingDirective - Create a new building
class CreateBuildingPayload { final BuildingId buildingId; final SiteId siteId; final BuildingName name; final BuildingDescription? description; final BuildingUsageType? usageType; final UniquePropertyReference? uprn; final UserId createdBy;}UpdateBuildingDirective - Update building properties
ApplyBuildingFootprintV2Directive - Set building geometry in V2 topology
Room Directives
Section titled “Room Directives”CreateRoomDirective - Create a new room
AddRoomGeometryDirective - Set room geometry
Topology Directives
Section titled “Topology Directives”SetSiteBoundaryDirective - Set site boundary polygon
SetFloorFootprintDirective - Set floor/building footprint
ModifySiteBoundaryDirective - Modify existing boundary polygon
ModifyFloorFootprintDirective - Modify floor footprint polygon
RenameSiteBoundaryDirective - Rename boundary
PublishSiteTopologyDirective - Publish complete topology
V2 Topology Directives
Section titled “V2 Topology Directives”OpenDraftTopologyDirective - Start editing a topology version
AddMapTileV2Directive - Add map tile to V2 topology
SetBoundaryV2Directive - Set boundary in V2 topology
PublishTopologyVersionDirective - Publish V2 topology version
Floor Plan Directives
Section titled “Floor Plan Directives”AddFloorPlanTileDirective - Add a floor plan tile
class AddFloorPlanTilePayload { final FloorPlanTileSetId tileSetId; final FloorPlanTile tile; final UserId createdBy;}UpdateFloorPlanTileDirective - Modify tile properties
RemoveFloorPlanTileDirective - Delete a floor plan tile
PublishFloorPlanTileSetDirective - Publish floor plan tiles
Value Objects
Section titled “Value Objects”The domain uses strongly-typed value objects for all identifiers and concepts:
Identity Value Objects
Section titled “Identity Value Objects”- EstateId - Unique estate identifier
- SiteId - Unique site identifier within an estate
- BuildingId - Unique building identifier within a site
- RoomId - Unique room identifier within a site
- SiteBoundaryId - Identifies site boundary features
- GeoFeatureKey - Stable key for geographic features
- GeoFeatureId - Computed canonical ID derived from typed IDs
- BuildingLevel - Floor/level number (e.g., “Ground”, “1st Floor”, “-1” for basement)
- SiteTopologyVersionId - Version identifier for topology versions
- FloorPlanImageTileId - Identifier for floor plan tiles
- MapTileId - Identifier for map tiles
Description Value Objects
Section titled “Description Value Objects”- EstateName - Name of the estate
- EstateDescription - Narrative description
- SiteName - Name of the site
- SiteDescription - Site narrative description
- BuildingName - Building name
- BuildingDescription - Building narrative description
- RoomName - Room name
- RoomDescription - Room narrative description
- GeoFeatureName - Name for geographic features
Type Value Objects
Section titled “Type Value Objects”- SiteTypeEnum - office, warehouse, retail, manufacturing, etc.
- BuildingUsageType - office, retail, residential, storage, etc.
- RoomTypeEnum - office, meeting, storage, restroom, etc.
- BoundaryUsageType - Taxonomy for boundary types
- GeoFeatureKind - Type of geographic feature (siteBoundary, buildingFootprint, room, etc.)
- GeometryOrientation - Orientation information for polygon features
- TopologyVersion - Version string for published topologies
Location Value Objects
Section titled “Location Value Objects”- SiteLocation - Composite location (postal address + geo point + country code)
- PostalAddress - Mailing address details
- GeoPoint - Latitude/longitude pair
- UniquePropertyReference - UPRN (UK property identifier)
Geometric Value Objects
Section titled “Geometric Value Objects”- FeaturePointer - Reference to a feature and its geometry
- VirtualTileFootprint - Computed footprint from floor plan tiles
- GeoJSONGeometry - Standard GeoJSON geometry (Point, Polygon, MultiPolygon, etc.)
- MapTile - Map tile with metadata
Domain Relationships
Section titled “Domain Relationships”Cross-Domain Relationships
Section titled “Cross-Domain Relationships”The Estate Structures domain relates to other domains:
Trackable Asset Domain (trackable_asset_v1)
- Assets are positioned within rooms/buildings/sites
- Asset position selectors query this domain for location hierarchy
- Assets emit position change events tracked here
Catalogues Domain (catalogues_v1)
- Buildings and rooms reference taxonomy for usage types
- Building and room type classifications use catalogue taxonomy
Contracts Domain (contracts_v1)
- Value objects are imported from contracts (address, locations, etc.)
- Shared identity types across domains
Permissions Domain (permissions_v1)
- Estate structures define permission scopes
- Users have access to specific estates/sites
Identity Domain (identity_v1)
- Tracks which users created/modified structures
- Audit trail of changes by user
Service Layer
Section titled “Service Layer”The domain includes domain services for complex operations:
SiteBaselineLocator
Section titled “SiteBaselineLocator”Locates the baseline (published) topology for a site:
- Finds the most recent published topology version
- Resolves draft vs. published states
- Used for asset positioning and spatial queries
TopologyChangeService
Section titled “TopologyChangeService”Tracks changes to topology between versions:
- Compares two topology states
- Identifies feature additions, modifications, removals
- Supports change notification and reconciliation
FloorPlanChangeService
Section titled “FloorPlanChangeService”Tracks changes to floor plan tile sets:
- Compares tile collections
- Identifies tile order changes, opacity/transform changes
- Supports incremental updates
AttachmentChangeService
Section titled “AttachmentChangeService”Manages attachments linked to geographic features:
- Associates PDFs, images with features
- Supports page selection for multi-page PDFs
- Change tracking for attachment references
VirtualFootprintCalculator
Section titled “VirtualFootprintCalculator”Computes virtual building footprints from floor plans:
- Aggregates tile geometry to estimate building envelope
- Handles overlapping tiles and gaps
- Provides virtual footprint for untraced buildings
TopologyComparisonService
Section titled “TopologyComparisonService”Compares topology versions:
- Detailed feature-by-feature comparison
- Spatial difference analysis
- Used for validation and reconciliation
SiteValidationService
Section titled “SiteValidationService”Validates topology structure and spatial coherence:
- Checks feature consistency
- Validates geometry quality
- Ensures hierarchy integrity
Integration Points
Section titled “Integration Points”Event Subscription
Section titled “Event Subscription”Other domains subscribe to estate structures events to synchronize state:
// Example: Asset domain listening for building placement changesstream.where((event) => event is BuildingFootprintSetEvent) .listen((event) { // Update asset positions for assets in this building });Capability Matrix
Section titled “Capability Matrix”| Operation | Initiator | Event | Consumer |
|---|---|---|---|
| Create Estate | Admin UI | EstateCreatedEvent | Permissions, Identity |
| Create Site | Site Admin | SiteCreatedEvent | Asset Domain |
| Create Building | Site Admin | BuildingCreatedEvent | Asset Domain |
| Create Room | Site Admin | RoomCreatedEvent | Asset Domain |
| Set Boundary | Site Admin | SiteBoundarySetEvent | Asset Domain, Topology V2 |
| Set Footprint | Site Admin | BuildingFootprintSetEvent | Asset Domain |
| Add Tile | Site Admin | MapTileAddedEvent | Topology Validation |
| Publish Topology | Site Admin | SiteTopologyPublishedEvent | All subscribers |
Code Examples
Section titled “Code Examples”Creating an Estate and Site
Section titled “Creating an Estate and Site”// Step 1: Create estate via directivefinal createEstateDirective = CreateEstateDirective( payload: CreateEstatePayload( estateId: EstateId('estate-acme'), name: EstateName('Acme Corporation'), address: PostalAddress( streetAddress: '123 Business Ave', city: 'London', countryCode: 'GB', ), createdBy: UserId('user-admin'), ),);
// Step 2: Create site via directivefinal createSiteDirective = CreateSiteDirective( payload: CreateSitePayload( siteId: SiteId('site-london-hq'), estateId: EstateId('estate-acme'), name: SiteName('London Headquarters'), siteType: SiteTypeEnum.office, address: PostalAddress( streetAddress: '100 Main Street', city: 'London', countryCode: 'GB', ), mapMarkerPosition: GeoPoint( latitude: 51.5074, longitude: -0.1278, ), createdBy: UserId('user-admin'), ),);Adding a Building with Footprint
Section titled “Adding a Building with Footprint”// Create buildingfinal buildingDirective = CreateBuildingDirective( payload: CreateBuildingPayload( buildingId: BuildingId('bldg-main-tower'), siteId: SiteId('site-london-hq'), name: BuildingName('Main Tower'), usageType: BuildingUsageType.office, uprn: UniquePropertyReference('123456789'), createdBy: UserId('user-admin'), ),);
// Set building footprint (boundary polygon)final footprintDirective = ApplyBuildingFootprintV2Directive( payload: ApplyBuildingFootprintV2Payload( siteId: SiteId('site-london-hq'), buildingId: BuildingId('bldg-main-tower'), footprint: GeoJSONPolygon( coordinates: [ [ [51.5070, -0.1280], [51.5075, -0.1280], [51.5075, -0.1270], [51.5070, -0.1270], [51.5070, -0.1280], ] ], ), createdBy: UserId('user-admin'), ),);Creating Rooms
Section titled “Creating Rooms”final roomDirective = CreateRoomDirective( payload: CreateRoomPayload( roomId: RoomId('room-meeting-a'), siteId: SiteId('site-london-hq'), name: RoomName('Meeting Room A'), roomType: RoomTypeEnum.meeting, createdBy: UserId('user-admin'), ),);
// Add room geometryfinal geometryDirective = AddRoomGeometryDirective( payload: AddRoomGeometryPayload( roomId: RoomId('room-meeting-a'), siteId: SiteId('site-london-hq'), geometry: FeaturePointer(...), updatedBy: UserId('user-admin'), ),);Publishing Topology
Section titled “Publishing Topology”// Publish the complete topology versionfinal publishDirective = PublishTopologyVersionDirective( payload: PublishTopologyVersionPayload( siteId: SiteId('site-london-hq'), versionId: SiteTopologyVersionId('v1-2024-01-15'), createdBy: UserId('user-admin'), ),);Testing & Validation
Section titled “Testing & Validation”The domain includes comprehensive test coverage:
- GeoFeature Tests - Feature ID generation, JSON serialization, kind classification
- TopologyIndex Tests - Feature lookup and spatial indexing
- Event Tests - Event creation, serialization, reconstruction
- SiteBaseline Tests - Baseline topology locator functionality
- VirtualFootprint Tests - Footprint calculation from tiles
- Registration Tests - Type registry and directive registration
Related Documentation
Section titled “Related Documentation”- Trackable Asset Domain - Asset positioning
- Catalogues Domain - Taxonomy and classification
- Permissions Domain - Access control by estate/site
- Nomos Core Framework - Event sourcing infrastructure
Package Details
Section titled “Package Details”Path: dart_packages/co2/domains/estate_structures_v1
Dependencies:
nomos_core- Event sourcing frameworkfoundation_geometry_v1- Geometric utilities and polygon operationscontracts_v1- Shared value objects and contracts
Version: 1.0.0
Dart SDK: >=3.6.0 <4.0.0