CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

ai-unified-process/aiup-blazor-dotnet

AI Unified Process for the C# / Blazor .NET 10 stack - migrations, implementation, tests

0.96x
Quality

92%

Does it follow best practices?

Impact

96%

0.96x

Average score across 3 eval scenarios

SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

example-slice.mdskills/implement/references/

Example Slice: UC-010 Create Order

The command, validator, and handler of one write use case. The use case states two rules: BR-001 "An order has at least one item" and BR-002 "A blocked customer cannot place an order". The page calls the handler and shows Result.Error next to the form.

Features/UC010_CreateOrder/UC010_Command.cs

namespace MyApp.Features.UC010_CreateOrder;

public sealed record UC010_Command(long CustomerId, List<UC010_Item> Items);

public sealed record UC010_Item(long ProductId, int Quantity);

Features/UC010_CreateOrder/UC010_Validator.cs

using FluentValidation;

namespace MyApp.Features.UC010_CreateOrder;

public sealed class UC010_Validator : AbstractValidator<UC010_Command>
{
    public UC010_Validator()
    {
        // UC-010 BR-001: An order has at least one item.
        RuleFor(c => c.Items).NotEmpty().WithMessage("Add at least one item.");
        RuleForEach(c => c.Items).ChildRules(item =>
            item.RuleFor(i => i.Quantity).GreaterThan(0));
    }
}

Features/UC010_CreateOrder/UC010_Handler.cs

using FluentValidation;
using Microsoft.EntityFrameworkCore;

namespace MyApp.Features.UC010_CreateOrder;

public sealed record UC010_Result(long? OrderId, string? Error);

public sealed class UC010_Handler(
    IDbContextFactory<AppDbContext> dbFactory,
    IValidator<UC010_Command> validator)
{
    public async Task<UC010_Result> HandleAsync(UC010_Command command, CancellationToken ct)
    {
        var validation = await validator.ValidateAsync(command, ct);
        if (!validation.IsValid)
            return new UC010_Result(null, validation.Errors[0].ErrorMessage);

        await using var db = await dbFactory.CreateDbContextAsync(ct);
        var customer = await db.Customers.SingleAsync(c => c.Id == command.CustomerId, ct);

        // UC-010 BR-002: A blocked customer cannot place an order.
        if (customer.Blocked)
            return new UC010_Result(null, "Your account is blocked. Please contact support.");

        var order = new Order
        {
            Customer = customer,
            Items = command.Items
                .Select(i => new OrderItem { ProductId = i.ProductId, Quantity = i.Quantity })
                .ToList()
        };
        db.Orders.Add(order);
        await db.SaveChangesAsync(ct);
        return new UC010_Result(order.Id, null);
    }
}

What it shows

  • One DbContext per call from IDbContextFactory, so a circuit-scoped page never shares one.
  • A rule enforced in the validator and a rule enforced in the handler each carry their marker.
  • The messages are the ones the specification's alternative flows state; the page displays them as they are.
  • Register the handler and validator in Program.cs (AddScoped<UC010_Handler>(), AddValidatorsFromAssemblyContaining<UC010_Validator>()) if the project does not scan for them.

skills

implement

.mcp.json

LICENSE

README.md

tile.json