Claude Code Plugins

Community-maintained marketplace

Feedback

koan-data-modeling

@sylin-org/koan-framework
1
0

Aggregate boundaries, relationships, lifecycle hooks, value objects

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name koan-data-modeling
description Aggregate boundaries, relationships, lifecycle hooks, value objects

Koan Data Modeling

Core Principle

Entities are aggregates that encapsulate business logic and define clear boundaries. Use lifecycle hooks for invariants, value objects for cohesive data, and navigation helpers for relationships.

Quick Reference

Define Aggregate Boundary

public class Order : Entity<Order>
{
    public string CustomerId { get; set; } = "";
    public Money Total { get; private set; } = new(0m, "USD");
    public OrderStatus Status { get; private set; } = OrderStatus.Draft;

    // Business methods
    public void MarkShipped() => Status = OrderStatus.Shipped;

    // Navigation helper
    public Task<Customer?> GetCustomer(CancellationToken ct = default) =>
        Customer.Get(CustomerId, ct);

    // Domain query
    public static Task<List<Order>> RecentOrders(int days = 7, CancellationToken ct = default) =>
        Query(o => o.Created > DateTimeOffset.UtcNow.AddDays(-days), ct);
}

Value Objects

public record Money(decimal Amount, string Currency);
public record Address(string Street, string City, string State, string Zip);

public class Invoice : Entity<Invoice>
{
    public Money Total { get; set; } = new(0m, "USD");
    public Address ShippingAddress { get; set; } = new("", "", "", "");
}

Lifecycle Hooks

public static class ProductLifecycle
{
    public static void Configure(EntityLifecycleBuilder<Product> pipeline)
    {
        pipeline.ProtectAll()
                .Allow(p => p.Price, p => p.Description)
                .BeforeUpsert(async (ctx, next) =>
                {
                    if (ctx.Entity.Price < 0)
                        throw new InvalidOperationException("Price cannot be negative");
                    await next();
                })
                .AfterLoad(ctx => ctx.Entity.FormattedPrice = $"${ctx.Entity.Price:F2}");
    }
}

Relationships

public class Todo : Entity<Todo>
{
    public string UserId { get; set; } = "";
    public string? CategoryId { get; set; }

    // Navigation helpers
    public Task<User?> GetUser(CancellationToken ct = default) =>
        User.Get(UserId, ct);

    public Task<Category?> GetCategory(CancellationToken ct = default) =>
        string.IsNullOrEmpty(CategoryId) ? Task.FromResult<Category?>(null)
            : Category.Get(CategoryId, ct);

    public Task<List<TodoItem>> GetItems(CancellationToken ct = default) =>
        TodoItem.Query(i => i.TodoId == Id, ct);
}

When This Skill Applies

  • ✅ Designing domain models
  • ✅ Complex entity relationships
  • ✅ Business logic encapsulation
  • ✅ Data validation patterns
  • ✅ Soft deletes and audit trails
  • ✅ Entity lifecycle management

Reference Documentation

  • Full Guide: docs/guides/data-modeling.md
  • Entity Patterns: docs/examples/entity-pattern-recipes.md
  • Sample: samples/S1.Web/ (Relationship patterns)