- Organize by bounded contexts. Use Kotlin data classes for value objects, sealed classes for domain types.
- Use rich domain models with methods — entities enforce their own invariants.
- Use `value class` (inline classes) for domain primitives like `UserId`, `Email` — they have zero runtime overhead and prevent type confusion.
- Use `value class` (inline class) for domain primitives: `value class UserId(val value: UUID)`.
- Define aggregate roots with `init` blocks for invariant validation.
- Use Kotlin's sealed hierarchies for state machines and type-safe event modeling.
- Use domain events with Kotlin coroutines channels or Spring events for cross-context communication.