Skip to main content

Business Rules

The Wrapsfer API today implements a single business concept — greetings — used as a sample to demonstrate the layered architecture. This page lists every rule that exists in the codebase, separating them by the layer that enforces them, and is explicit about what is not a business rule today.

If you are looking for the request/response contract, see the Endpoint Reference. For error shapes, see Errors & Validation.

Layer Map

ConcernEnforced in
HTTP-level input shape (name length)GreetingsController[ApiController] + data annotations
Use-case orchestration & timestampGreetingService (Application)
Domain invariants (non-blank, trimming, message format)Greeting (Domain)

Domain rules apply regardless of how the use case is invoked. API validation only fires for HTTP requests through the controller.

Domain Rules — Greeting

Defined in Wrapsfer.Domain.Greetings.Greeting.

  • Construction is restricted to Greeting.Create(string name). The constructor is private.
  • name must not be null, empty, or whitespace. Create throws ArgumentException with message "A greeting name is required." and parameter name name if string.IsNullOrWhiteSpace(name) is true.
  • name is trimmed. Surrounding whitespace is removed before the value is stored. The unit test GreetingTests.Create_TrimsNameAndFormatsMessage confirms " Vernon " becomes "Vernon".
  • Message format is fixed. Greeting.Message is computed as $"Hello, {Name}!" — there is no localization, no template configuration, no salutation variation.

These rules apply to any caller of Greeting.Create, not just the HTTP path.

Application Rules — GreetingService

Defined in Wrapsfer.Application.Greetings.GreetingService.

  • Invokes the domain. GreetingService.CreateGreeting(string name) calls Greeting.Create(name), so all domain rules above apply transitively.
  • Returns a GreetingResponse DTO, not the domain entity. The DTO shape is (string Message, DateTimeOffset GeneratedAt).
  • Timestamp comes from injected TimeProvider. GeneratedAt is timeProvider.GetUtcNow(). The Infrastructure layer registers TimeProvider.System as a singleton (Wrapsfer.Infrastructure.DependencyInjection.AddInfrastructure), so in production the value is the current system UTC time. Tests can substitute a fake TimeProvider to control the value.
  • IGreetingService is registered as Scoped. A new instance is created per HTTP request.

There are no further application-layer rules — no caching, no rate limiting, no retries, no logging beyond default ASP.NET Core request logging.

API Validation Rules — GreetingsController

Defined in Wrapsfer.Api.Controllers.GreetingsController.

  • Route: GET /api/greetings (controller route api/[controller]).
  • name query parameter default. When the caller omits name, the action parameter defaults to "World". A request with no query string therefore succeeds with greeting "Hello, World!".
  • name length validation. Decorated with [StringLength(80, MinimumLength = 1)]:
    • Empty string (?name=) fails MinimumLength = 1.
    • More than 80 characters fails MaximumLength = 80.
    • Either failure causes ASP.NET Core's [ApiController] automatic model-state validation to short-circuit with 400 Bad Request and a problem-details body. See Errors & Validation.
  • No other API validation rules exist. No content-type negotiation rules, no required headers, no rate limits, no authorization checks (the pipeline includes UseAuthorization, but no policies or [Authorize] attributes are defined).

What Is Intentionally Not A Business Rule Today

The following concepts are not implemented anywhere in the codebase. They should not be assumed to exist or be enforced.

  • Users / accounts / identities. No user model, no registration, no profile.
  • Authentication. No authentication scheme is registered. No bearer tokens, cookies, or API keys are validated.
  • Authorization. UseAuthorization is in the pipeline, but there are no policies, no roles, and no [Authorize] attributes. No request is rejected on authorization grounds.
  • Sessions. No session state is stored.
  • Tenancy / scoping. No tenant resolution, no scoping of data per caller.
  • Persistence. No database, no repositories, no entity tracking. Greetings are not saved; each request is fully recomputed.
  • Auditing / event sourcing. No audit log, no event publication.
  • Payments / billing / quotas. No charging, no usage tracking, no quotas.
  • Workflows / state machines. No multi-step business processes.
  • Notifications. No email, SMS, push, or webhook delivery.
  • Background jobs. No hosted services, no scheduled tasks, no queues.
  • Localization / i18n. Greeting message is hard-coded English.

When any of these are added, document them as they land — do not document them in advance.

See Also