Skip to content

Config Platform - Domain Model Schema

Overview

This document provides structured schemas for Config Platform domain models. Use these schemas to generate domain entities, aggregate roots, value objects, and persistence mappings.

Aggregate Roots

ConfigItem Aggregate

Schema:

ConfigItem:
  type: aggregate_root
  properties:
    id:
      type: uuid
      required: true
      description: Unique identifier
    key:
      type: string
      required: true
      maxLength: 500
      pattern: "^[a-zA-Z0-9._-]+$"
      description: Configuration key (dot-notation supported)
    value:
      type: any
      required: true
      description: Configuration value (JSON, string, number, boolean)
    contentType:
      type: string
      enum: [application/json, text/plain, application/yaml, text/xml]
      default: application/json
    isSecret:
      type: boolean
      default: false
      description: Indicates if value contains sensitive data
    isFeatureToggle:
      type: boolean
      default: false
      description: Indicates if this is a feature flag
    labels:
      type: array
      items:
        type: string
      description: Tags for categorization and filtering
    description:
      type: string
      maxLength: 1000
    version:
      type: integer
      required: true
      description: Current version number
    etag:
      type: string
      required: true
      description: Entity tag for optimistic concurrency
    createdAt:
      type: datetime
      required: true
    updatedAt:
      type: datetime
      required: true
    createdBy:
      type: string
      required: true
    updatedBy:
      type: string
      required: true
  invariants:
    - key must be unique within config set and tenant
    - value must pass schema validation if schema is defined
    - version increments on each update
    - etag changes on each update
  relationships:
    belongsTo:
      - ConfigSet
    hasMany:
      - ConfigVersion

C# Domain Model:

public class ConfigItem : AggregateRoot<Guid>
{
    public string Key { get; private set; }
    public object Value { get; private set; }
    public string ContentType { get; private set; }
    public bool IsSecret { get; private set; }
    public bool IsFeatureToggle { get; private set; }
    public List<string> Labels { get; private set; }
    public string Description { get; private set; }
    public int Version { get; private set; }
    public string ETag { get; private set; }
    public DateTime CreatedAt { get; private set; }
    public DateTime UpdatedAt { get; private set; }
    public string CreatedBy { get; private set; }
    public string UpdatedBy { get; private set; }

    public Guid ConfigSetId { get; private set; }
    public ConfigSet ConfigSet { get; private set; }

    public ICollection<ConfigVersion> Versions { get; private set; }

    public void UpdateValue(object newValue, string updatedBy)
    {
        // Business logic: validate, increment version, update etag
    }
}

ConfigVersion Entity

Schema:

ConfigVersion:
  type: entity
  properties:
    id:
      type: uuid
      required: true
    configItemId:
      type: uuid
      required: true
      foreignKey: ConfigItem.id
    versionNumber:
      type: integer
      required: true
      description: Immutable version number
    value:
      type: any
      required: true
      description: Snapshot of value at this version
    changeSummary:
      type: string
      maxLength: 500
      description: Human-readable description of change
    createdBy:
      type: string
      required: true
    createdAt:
      type: datetime
      required: true
    hash:
      type: string
      required: true
      description: SHA-256 hash of value for integrity
  invariants:
    - versions are immutable (append-only)
    - version numbers are sequential
    - hash must match value content
  relationships:
    belongsTo:
      - ConfigItem

ConfigBundle Aggregate

Schema:

ConfigBundle:
  type: aggregate_root
  properties:
    id:
      type: uuid
      required: true
    name:
      type: string
      required: true
      maxLength: 200
    appId:
      type: string
      required: true
      description: Application identifier
    environment:
      type: string
      enum: [dev, staging, prod]
      required: true
    scope:
      type: string
      enum: [global, edition, tenant, service, instance]
      required: true
      description: Configuration scope level
    tenantId:
      type: uuid
      description: Tenant identifier (required if scope is tenant or service)
    editionId:
      type: string
      description: Edition identifier (required if scope is edition)
    serviceId:
      type: string
      description: Service identifier (required if scope is service or instance)
    labels:
      type: array
      items:
        type: string
    status:
      type: string
      enum: [draft, published, archived]
      default: draft
    version:
      type: integer
      required: true
    etag:
      type: string
      required: true
    createdAt:
      type: datetime
      required: true
    updatedAt:
      type: datetime
      required: true
  invariants:
    - name must be unique within tenant and environment
    - scope determines required identifiers
    - status transitions: draft -> published -> archived
  relationships:
    hasMany:
      - ConfigItem
      - ConfigSnapshot

ConfigSchema Value Object

Schema:

ConfigSchema:
  type: value_object
  properties:
    id:
      type: uuid
      required: true
    name:
      type: string
      required: true
      maxLength: 200
    jsonSchema:
      type: object
      required: true
      description: JSON Schema definition for validation
    version:
      type: string
      required: true
      description: Schema version (semantic versioning)
    appliesTo:
      type: array
      items:
        type: string
      description: Config keys this schema applies to (supports wildcards)
    createdAt:
      type: datetime
      required: true
    updatedAt:
      type: datetime
      required: true
  invariants:
    - jsonSchema must be valid JSON Schema
    - version follows semantic versioning
  relationships:
    validates:
      - ConfigItem

JSON Schema Example:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "apiUrl": {
      "type": "string",
      "format": "uri",
      "description": "API base URL"
    },
    "timeout": {
      "type": "integer",
      "minimum": 1,
      "maximum": 300,
      "description": "Request timeout in seconds"
    },
    "retryCount": {
      "type": "integer",
      "minimum": 0,
      "maximum": 10
    }
  },
  "required": ["apiUrl", "timeout"]
}

TenantConfig Aggregate

Schema:

TenantConfig:
  type: aggregate_root
  properties:
    id:
      type: uuid
      required: true
    tenantId:
      type: uuid
      required: true
      unique: true
    editionId:
      type: string
      required: true
      description: Product edition (Free, Pro, Enterprise)
    configSet:
      type: object
      description: Resolved configuration set
    overrides:
      type: object
      description: Tenant-specific overrides
    version:
      type: integer
      required: true
    createdAt:
      type: datetime
      required: true
    updatedAt:
      type: datetime
      required: true
  invariants:
    - tenantId must be unique
    - overrides must pass edition policy validation
  relationships:
    hasMany:
      - ServiceConfig
    belongsTo:
      - EditionConfig

ServiceConfig Entity

Schema:

ServiceConfig:
  type: entity
  properties:
    id:
      type: uuid
      required: true
    tenantConfigId:
      type: uuid
      required: true
      foreignKey: TenantConfig.id
    serviceId:
      type: string
      required: true
      description: Microservice identifier
    configItems:
      type: array
      items:
        $ref: ConfigItem
    version:
      type: integer
      required: true
    createdAt:
      type: datetime
      required: true
    updatedAt:
      type: datetime
      required: true
  relationships:
    belongsTo:
      - TenantConfig
    hasMany:
      - ConfigItem

Entity Relationship Diagram

erDiagram
    ConfigBundle ||--o{ ConfigItem : contains
    ConfigItem ||--o{ ConfigVersion : versions
    ConfigItem }o--|| ConfigSchema : validates
    TenantConfig ||--o{ ServiceConfig : contains
    TenantConfig }o--|| EditionConfig : inherits
    ServiceConfig ||--o{ ConfigItem : holds
    ConfigBundle ||--o{ ConfigSnapshot : snapshots
Hold "Alt" / "Option" to enable pan & zoom

Validation Rules

ConfigItem Validation

validation_rules:
  key:
    - required: true
    - pattern: "^[a-zA-Z0-9._-]+$"
    - maxLength: 500
    - uniqueWithin: [configSetId, tenantId]
  value:
    - required: true
    - validateAgainstSchema: true
    - secretDetection: true
  contentType:
    - enum: [application/json, text/plain, application/yaml, text/xml]
  labels:
    - maxItems: 20
    - uniqueItems: true

ConfigBundle Validation

validation_rules:
  name:
    - required: true
    - maxLength: 200
    - uniqueWithin: [tenantId, environment]
  scope:
    - required: true
    - conditionalRequired:
        - if: scope == "tenant" or "service"
          then: tenantId required
        - if: scope == "edition"
          then: editionId required
        - if: scope == "service" or "instance"
          then: serviceId required

Persistence Mapping

NHibernate Mapping Example

<hibernate-mapping>
  <class name="ConfigItem" table="config_items">
    <id name="Id" column="id" type="guid">
      <generator class="guid.comb"/>
    </id>

    <property name="Key" column="key" type="string" length="500" not-null="true"/>
    <property name="Value" column="value" type="string" length="10000" not-null="true"/>
    <property name="ContentType" column="content_type" type="string" length="100"/>
    <property name="IsSecret" column="is_secret" type="boolean"/>
    <property name="IsFeatureToggle" column="is_feature_toggle" type="boolean"/>
    <property name="Labels" column="labels" type="string" length="1000"/>
    <property name="Description" column="description" type="string" length="1000"/>
    <property name="Version" column="version" type="int" not-null="true"/>
    <property name="ETag" column="etag" type="string" length="64" not-null="true"/>
    <property name="CreatedAt" column="created_at" type="datetime" not-null="true"/>
    <property name="UpdatedAt" column="updated_at" type="datetime" not-null="true"/>
    <property name="CreatedBy" column="created_by" type="string" length="200" not-null="true"/>
    <property name="UpdatedBy" column="updated_by" type="string" length="200" not-null="true"/>

    <many-to-one name="ConfigSet" column="config_set_id" class="ConfigBundle" not-null="true"/>

    <bag name="Versions" cascade="all-delete-orphan">
      <key column="config_item_id"/>
      <one-to-many class="ConfigVersion"/>
    </bag>
  </class>
</hibernate-mapping>

Domain Events

ConfigItem Events

public class ConfigItemCreatedEvent : IDomainEvent
{
    public Guid ConfigItemId { get; set; }
    public string Key { get; set; }
    public Guid ConfigSetId { get; set; }
    public string TenantId { get; set; }
    public DateTime OccurredAt { get; set; }
}

public class ConfigItemUpdatedEvent : IDomainEvent
{
    public Guid ConfigItemId { get; set; }
    public string Key { get; set; }
    public int OldVersion { get; set; }
    public int NewVersion { get; set; }
    public DateTime OccurredAt { get; set; }
}

public class ConfigItemDeletedEvent : IDomainEvent
{
    public Guid ConfigItemId { get; set; }
    public string Key { get; set; }
    public DateTime OccurredAt { get; set; }
}

References