flare-api-patterns
Coding patterns extracted from flare-api — a .NET 10 Clean Architecture feature-flag management API
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Coding patterns extracted from flare-api — a .NET 10 Clean Architecture feature-flag management API
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | flare-api-patterns |
| description | Coding patterns extracted from flare-api — a .NET 10 Clean Architecture feature-flag management API |
| version | 1.0.0 |
| source | local-git-analysis |
| analyzed_commits | 35 |
This project uses conventional commits (with minor variation):
| Prefix | Usage |
|---|---|
feat: / feature: | New features |
fix: / bugfix: | Bug fixes |
chore: | Maintenance, dependency updates, cleanup |
refactor: | Code restructuring |
Examples from history:
feature: implement search and pagination on project detail, feature flag detail, user management endpoints
bugfix: create feature flag values for newly created scopes
chore: update dependencies
feat: different feature flag types
Clean Architecture with four projects in src/:
src/
├── Flare.Api/ # ASP.NET Web API host
│ ├── Controllers/
│ │ ├── WebUI/ # Cookie-auth endpoints for the front-end
│ │ └── Sdk/ # API-key endpoints for SDK consumers
│ ├── Extensions/ # ServiceCollectionRegistration.cs (Api-layer DI)
│ ├── Middleware/ # GlobalExceptionHandler
│ ├── RateLimiting/ # Rate limit options, policies, conventions
│ ├── Attributes/ # Custom authorization attributes
│ ├── Filters/ # Custom authorization filters
│ ├── Startup.cs # ConfigureServices + Configure (classic style)
│ └── Program.cs # Host builder + pre-run startup sequence
│
├── Flare.Application/ # Use-cases, interfaces, DTOs
│ ├── DTOs/ # Input/output data transfer objects
│ ├── Interfaces/ # Service + repository interfaces
│ ├── Services/ # Business logic implementations
│ ├── Authorization/Handlers/ # ASP.NET authorization requirement handlers
│ └── ServiceCollectionRegistration.cs
│
├── Flare.Domain/ # Pure domain model — no DI dependencies
│ ├── Entities/ # EF Core entities with domain behaviour
│ ├── Enums/ # Domain enumerations
│ ├── Exceptions/ # Domain-specific exceptions
│ └── Constants/ # Domain constants (e.g. AuthConstants)
│
└── Flare.Infrastructure/ # EF Core, Postgres, migrations, seed
├── Data/
│ ├── ApplicationDbContext.cs
│ ├── Configurations/ # One IEntityTypeConfiguration<T> per entity
│ └── Repositories/
│ ├── Implementation/ # Concrete repository classes
│ └── Interfaces/ # Repository contracts
├── Initialization/ # DatabaseInitializer, MigrationRunner
├── Migrations/ # EF Core generated migrations
└── ServiceCollectionRegistration.cs
[ApiController], [ApiVersion("1.0")], [Route("api/v{version:apiVersion}")][ProducesResponseType] for all expected status codesuserId from HttpContext.GetCurrentUserId() — never trust route params for identityCreated() (no body) for POST create actions; Ok(result) for readsAlways use PagedResult<T> for list endpoints. Clamp page/pageSize in the controller:
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
[FromQuery] string? search = null
if (page < 1) page = 1;
if (pageSize < 1) pageSize = 1;
if (pageSize > 25) pageSize = 25;
PagedResult<T> shape:
public class PagedResult<T>
{
public List<T> Items { get; init; } = new();
public int TotalCount { get; init; }
public int Page { get; init; }
public int PageSize { get; init; }
public int TotalPages => PageSize > 0 ? (int)Math.Ceiling((double)TotalCount / PageSize) : 0;
}
Interfaces/, one implementation in Implementation/ApplicationDbContext (never IUnitOfWork directly in repos)GetByIdWithScopesAndProjectAsync, GetPagedByProjectIdAsync.Include().ThenInclude() chains for eager loading; avoid lazy loadingpublic async Task<FeatureFlag?> GetByIdWithValuesAsync(Guid featureFlagId)
{
return await _context.FeatureFlags
.Include(f => f.Values)
.ThenInclude(v => v.Scope)
.Include(f => f.Values)
.ThenInclude(v => v.TargetingRules)
.ThenInclude(r => r.Conditions)
.FirstOrDefaultAsync(f => f.Id == featureFlagId);
}
switch expressions for type-dispatch factory methodspublic FeatureFlagValue CreateValueForScope(Guid scopeId) => Type switch
{
FeatureFlagType.Boolean => FeatureFlagValue.ForBoolean(Id, scopeId, false),
FeatureFlagType.String => FeatureFlagValue.ForString(Id, scopeId, null),
FeatureFlagType.Number => FeatureFlagValue.ForNumber(Id, scopeId, null),
FeatureFlagType.Json => FeatureFlagValue.ForJson(Id, scopeId, null),
_ => throw new ArgumentOutOfRangeException(nameof(Type), Type, "Unsupported flag type.")
};
IEntityTypeConfiguration<TEntity> class per entity in Data/Configurations/Flare.Infrastructure/Migrations/ via EF CLIEach layer owns its own ServiceCollectionRegistration.cs with an AddXxx(this IServiceCollection) extension. Layers are registered top-down from Startup.cs:
Startup.cs → Api extensions → Application → Infrastructure
Always run in this order before app.Run():
MigrationRunner.RunAsync() — advisory lock + MigrateAsync()DatabaseInitializer.InitializeAsync() — seed admin if no users existUse GlobalExceptionHandler middleware to map domain exceptions to HTTP status codes. Domain-specific exceptions live in Flare.Domain/Exceptions/.
User entity)SdkEvaluationRateLimiterPolicyIAuthorizationRequirement handlers in Application/Authorization/Handlers/Flare.Domain/Entities/, enum in Flare.Domain/Enums/IEntityTypeConfiguration, update ApplicationDbContext, add repository interface + implementation, run dotnet ef migrations add <Name>Flare.Application/DTOs/, add method to service interface, implement in serviceControllers/WebUI/ or Controllers/Sdk/ServiceCollectionRegistration.csdotnet ef migrations add <MigrationName> \
--project src/Flare.Infrastructure \
--startup-project src/Flare.Api
Migrations run automatically at startup via MigrationRunner with an advisory lock — no manual dotnet ef database update in production.