Domain Building Blocks

Cards

Cards are the visual representation of your domain entities. Create classes, interfaces, enums, and records with attributes, methods, and DDD patterns.

Card types

Choose the right card type for your domain model. Each type generates different code patterns.

Card types overview
[01]

Class

Standard domain class with attributes and methods. Most common choice for entities. Generates entity classes, DTOs, repositories, and EF Core configurations.

[02]

Interface

Contract definition without implementation. Use for abstractions and ports in Clean Architecture. Implementing classes inherit the method signatures.

[03]

Enum

Fixed set of named values. Perfect for status codes, types, and categorical data. Generates enum definitions with optional string/numeric backing.

[04]

Abstract

Base class template that cannot be instantiated. Use for inheritance hierarchies where you want to share common attributes and methods.

[05]

Record

Immutable value type with value equality. Ideal for DTOs and Value Objects. Automatically generates equality comparison based on all properties.

Tip

Records automatically generate equality comparison based on all properties, making them perfect for Value Objects in DDD.

DDD patterns

Apply Domain-Driven Design patterns to your cards. Each pattern affects code generation and behavior.

DDD patterns
[01]

Aggregate Root

Entry point for a consistency boundary. Generates Repository, Use Cases (CRUD), and Controller. Always LOCAL scope - cannot be shared across bounded contexts. Shown with amber color indicator.

Aggregate Root card example
[02]

Entity

Domain object with unique identity. Can be standalone or owned by an aggregate via composition. CRUD generation depends on ownership - standalone entities get their own repository, owned entities are managed through their aggregate.

Entity card example
[03]

Value Object

Immutable, identity-less object defined by its attributes. Embedded in parent entities as components. Can be shared across bounded contexts. Perfect for concepts like Address, Money, or DateRange.

Value Object card example

Info

DDD patterns are only available for Class, Abstract, and Record types. Records can only be Value Objects due to their immutable nature.

Configuring cards

Select a card to configure its properties in the right sidebar. The panel adapts based on card type.

Properties panel
[01]

Name & Type

Configure the card name and choose between Class, Interface, Enum, Abstract, or Record. The type determines which tabs and options are available.

[02]

Header Color

Customize the visual appearance with a color picker. Each card can have a unique header color for easy identification. Reset to default blue anytime.

[03]

DDD Pattern

Select Aggregate Root, Entity, or Value Object to define the domain role. This affects code generation, CRUD behavior, and scope options.

[04]

Scope

Choose LOCAL (bounded context) or SHARED (cross-context). Aggregate Roots are always LOCAL and cannot be shared.

[05]

CRUD Generation

Override default behavior for Repository, Use Cases, and Controller generation. By default, Aggregate Roots and standalone entities get full CRUD.

Attributes

Define the data your card holds. Each attribute has a type, visibility, and optional validations.

Attributes tab
PropertyDescription
NameThe attribute identifier
TypeData type: string, int, bool, datetime, uuid, decimal, or custom
VisibilityAccess modifier: public (+), private (-), protected (#)
NullableWhether the attribute can be null/undefined
DefaultDefault value when not provided
IdentityMarks as primary key (only one per card)
UniqueSingle-attribute unique constraint
[01]

Add attributes

Click the + button in the Attributes tab or directly on the card. Set name and type using the dropdown or by typing a custom type.

[02]

Configure visibility

Click the visibility icon to cycle through: public (+) → private (-) → protected (#) → public (+). Most attributes are public by default.

[03]

Set nullable

Toggle the nullable button to allow null values. Required attributes show a * indicator and generate appropriate validation.

[04]

Add default value

Expand attribute options to set a default value. Type-specific inputs are available: boolean dropdown, number input, date picker, or text field.

Validations

Add validation rules to ensure data integrity. Validations are enforced in generated code.

Validation configuration
RuleDescriptionExample
requiredCannot be null or empty-
minLengthMinimum string length3
maxLengthMaximum string length100
minMinimum numeric value0
maxMaximum numeric value1000
emailValid email format-
urlValid URL format-
patternRegex pattern match^[A-Z]{2}\d{4}$

Tip

These are just the most common validations. The editor includes many more specialized rules like phone, credit card, IP address, CPF/CNPJ, IBAN, password strength, and custom regex patterns.

Generated validation examples

AeroCoding generates validations across multiple layers of your architecture. Here's how validations flow from your visual schema to production code:

DomainEntity with fluent validation
User.cs
public sealed class User : Entity
{
public string Name { get; private set; }
public string Email { get; private set; }
public int? Age { get; private set; }
public static Result<User> Create(string name, string email, int? age)
{
var nameResult = Validate.String(name, nameof(Name))
.Required()
.MinLength(3)
.MaxLength(100)
.Build();
var emailResult = Validate.String(email, nameof(Email))
.Required()
.Email()
.Build();
var ageResult = age is null
? Result<int?>.Ok(null)
: Validate.Number(age.Value, nameof(Age))
.Between(0, 150)
.Build()
.Map(v => (int?)v);
return Result.Combine(nameResult, emailResult, ageResult)
.Map(() => new User
{
Name = nameResult.Value!,
Email = emailResult.Value!,
Age = ageResult.Value
});
}
}
ApplicationCommand with Data Annotations
CreateUser.cs
public static class CreateUser
{
public record Input(
[Required, MinLength(3), MaxLength(100)]
string Name,
[Required, EmailAddress]
string Email,
[Range(0, 150)]
int? Age
);
public record Output(UserDto User);
}
InfrastructureEF Core configuration
UserConfiguration.cs
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("users");
builder.HasKey(e => e.Id);
builder.Property(e => e.Name)
.IsRequired()
.HasMaxLength(100);
builder.Property(e => e.Email)
.IsRequired()
.HasMaxLength(255);
builder.Property(e => e.Age);
builder.HasIndex(e => e.Email)
.IsUnique();
}
}

Unique constraints

Define composite unique keys when multiple attributes together must be unique. Essential for join entities and many-to-many relationships.

Unique constraints configuration
[01]

Create constraint

In the Properties tab, scroll to Unique Constraints section and click 'Add Group' to create a new composite constraint.

[02]

Select attributes

Choose 2 or more attributes that together form a unique combination. For example, workspaceId + userId for workspace membership.

[03]

Name the constraint

A name is auto-generated like 'unique_workspace_user', but you can customize it to match your naming conventions.

Info

Unique constraints are essential for join entities in many-to-many relationships. For example, a WorkspaceMember entity would have a unique constraint on (workspaceId, userId) to prevent duplicate memberships.

Tip

Base attributes (id, createdAt, updatedAt) inherited from EntityBase can be included in unique constraints using the (base) selector.

Methods

Define behavior and operations for your cards. Methods appear in generated domain classes.

Methods tab
PropertyDescription
NameMethod identifier (camelCase)
Return TypeReturn value type or void
Visibilitypublic, private, or protected
StaticClass-level method, no instance needed
AbstractSignature only, implementation in subclasses
ParametersInput parameters with name and type
[01]

Add methods

Click + in the Methods tab. Name your method and set the return type using the dropdown or a custom type.

[02]

Add parameters

Expand the method to add parameters. Each parameter has a name and type. Parameters appear in the generated method signature.

[03]

Mark as static

Toggle static for utility methods that don't need instance data. Static methods are called on the class, not an instance.

Info

Methods generate the signature only. You implement the logic after code generation. This keeps your domain model clean and focused.

Reactions

Configure automatic responses to domain events. Reactions trigger when entities are created, updated, or deleted.

Reactions configuration
Reaction TypeDescription
loggingLog the event to the application logger
telemetrySend metrics to observability platform
emailSend email notification
notificationPush notification to users
cache_invalidateInvalidate related cache entries
webhookCall external HTTP endpoint
sagaTrigger a distributed saga/workflow
auditRecord to audit log
customCustom handler implementation
[01]

Add reaction

In the Methods tab, expand a method and click 'Add Reaction'. Choose the trigger event: created, updated, deleted, or custom.

[02]

Configure type

Select the reaction type from the dropdown. Each type generates the appropriate handler code and infrastructure.

[03]

Set execution mode

Choose sync (blocking) or async (fire-and-forget) execution. Async is recommended for non-critical reactions.

Info

Reactions are only available for Aggregate Roots and Entities with DDD patterns. They generate domain event handlers following the Mediator pattern.

Enum members

Define the values for your enum cards. Each member can have an explicit value.

Enum members
[01]

Add members

Click + to add new enum values. Names are auto-formatted to UPPER_CASE following enum naming conventions.

[02]

Set explicit values

Optionally assign numeric or string values to members. If not set, values are auto-assigned starting from 0.

[03]

Reorder members

Drag members to change their order. Order matters for numeric enums without explicit values.

OrderStatus.cs
public enum OrderStatus
{
Pending = 0,
Processing = 1,
Shipped = 2,
Delivered = 3,
Cancelled = 4
}

Domain mode

Choose between Pure and Advanced domain modeling. This affects how annotations and framework code are generated.

[01]

Pure mode (default)

Clean domain layer with no framework dependencies. Annotations like [Required] are generated separately in infrastructure layer. Best for Clean Architecture purists.

[02]

Advanced mode

Full control over annotations directly in domain entities. Framework-specific attributes appear in the domain layer. Faster development, less abstraction.

Warning

Switching domain mode may reorganize your generated code structure. A confirmation dialog appears with a "Don't ask again" option.

Annotations

Add framework-specific decorators and attributes to your cards. Available in Advanced domain mode.

Annotations configuration
CategoryExamples
Column[Column], [MaxLength], [Precision]
Key[Key], [DatabaseGenerated]
Relation[ForeignKey], [InverseProperty]
Index[Index], [UniqueIndex]
Validation[Required], [Range], [RegularExpression]
Serialization[JsonIgnore], [JsonPropertyName]
CustomAny custom attribute you define
[01]

Enable Advanced mode

Switch the card to Advanced domain mode in Properties tab. This unlocks the Annotations section.

[02]

Add annotation

Click 'Add Annotation' and select the framework (EF Core, ASP.NET, etc.) or choose Custom for your own attributes.

[03]

Configure parameters

Set annotation parameters like column name, max length, or custom values. Toggle enabled/disabled without deleting.

Info

Annotations are hidden for Enum types since they don't support attributes in the same way as classes.

Inheritance

Cards can inherit attributes and methods from parent classes or implement interfaces.

[01]

Inherited attributes

When a card inherits from another via Inheritance connection, parent attributes appear in a separate 'Inherited' section. They're read-only and grouped by source.

[02]

Inherited methods

Methods from parent classes also appear grouped. You can mark methods as 'override' to customize behavior in the child class.

[03]

Interface implementation

Cards connected via Implementation show interface methods in a separate group. These generate the interface implementation in code.

Tip

Base attributes from EntityBase (id, createdAt, updatedAt) are inherited automatically for Aggregate Roots and Entities, shown with a "(base)" label.

Reusable assets

Save cards as assets and reuse them across diagrams. Changes sync automatically.

[01]

Save as asset

Right-click a card and select 'Save as Asset', or use the Assets tab in the left sidebar. The card becomes a reusable template.

[02]

Link to asset

In the Properties panel, click 'Link to Asset' and select from your library. The card will sync with the source asset.

[03]

Override scope

Linked cards can override the asset's scope setting (LOCAL or SHARED). Aggregate Roots always remain LOCAL.

[04]

Update asset

Changes to linked cards can be pushed back to update the source asset, syncing all instances across your project.

Warning

Unlinking an asset creates an independent copy of the card. Future updates to the source asset won't affect the unlinked card.

Data types

Supported data types with their mappings across target languages.

TypeC#TypeScript
stringstringstring
intintnumber
longlongnumber
decimaldecimalnumber
doubledoublenumber
boolboolboolean
datetimeDateTimeDate
dateDateOnlyDate
timeTimeOnlyDate
uuidGuidstring
jsonJsonDocumentobject

Tip

You can also reference other cards as types to create relationships. See the Relationships guide.

Next steps

Continue building your domain model.