Files
budget/.plans/10-project-split.md
T
Spencer Twaddle 087fbdd176 Split into Budget.Core / Budget.Infrastructure / Budget.Api projects
Budget.Core: entities, DTOs, enums, FrequencyCalculator (no EF/ASP.NET deps)
Budget.Infrastructure: AppDbContext, migrations, BudgetAuthorizationService
Budget.Api: controllers, middleware, Program.cs — references both projects

EF and Npgsql packages moved to Infrastructure; Api retains only JwtBearer,
HealthChecks, and EF.Design (needed for dotnet ef CLI). Dockerfile updated
to copy all three project directories before publishing. Migration namespaces
updated from Budget.Api.Data.* to Budget.Infrastructure.Data.* and model
type strings updated to Budget.Core.Models.* in the snapshot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:30:31 -05:00

4.1 KiB

Plan: Core / Infrastructure / API Project Split

Goal

Split the single Budget.Api project into three projects matching the stwaddle stack pattern:

  • Budget.Core — entities, DTOs, enums. No ASP.NET or EF dependencies.
  • Budget.Infrastructure — DbContext, EF configs, migrations, domain services.
  • Budget.Api — controllers, middleware, Program.cs, DI wiring.

Current state

Everything lives in src/Budget.Api/:

Models/         Budget, Income, Outgo, BudgetShare, KnownUser, enums
DTOs/           BudgetDtos, IncomeDtos, OutgoDtos, ShareDtos, SummaryDtos
Data/           AppDbContext, Migrations/
Services/       BudgetAuthorizationService, FrequencyCalculator,
                KnownUserMiddleware, ErrorHandlingMiddleware, ClaimsPrincipalExtensions
Controllers/    BudgetsController, IncomesController, OutgosController,
                SharesController, SummaryController
Program.cs

Target state

src/
  Budget.Core/
    Models/     Budget, Income, Outgo, BudgetShare, KnownUser, enums
    DTOs/       all DTO records and request types
    Services/   FrequencyCalculator (pure logic, no EF/ASP.NET)

  Budget.Infrastructure/
    Data/       AppDbContext, Migrations/
    Services/   BudgetAuthorizationService

  Budget.Api/
    Controllers/
    Services/   KnownUserMiddleware, ErrorHandlingMiddleware,
                ClaimsPrincipalExtensions
    Program.cs

References: Budget.ApiBudget.InfrastructureBudget.Core

Steps

Phase 1 — Create projects and move files

  1. dotnet new classlib -n Budget.Core -o src/Budget.Core --framework net10.0
  2. dotnet new classlib -n Budget.Infrastructure -o src/Budget.Infrastructure --framework net10.0
  3. Add both to the solution: dotnet sln add src/Budget.Core/Budget.Core.csproj src/Budget.Infrastructure/Budget.Infrastructure.csproj
  4. Move Models/ and DTOs/ to Budget.Core; update namespaces from Budget.Api.* to Budget.Core.*.
  5. Move FrequencyCalculator.cs to Budget.Core/Services/.
  6. Move Data/ (AppDbContext + Migrations) to Budget.Infrastructure/Data/.
  7. Move BudgetAuthorizationService.cs to Budget.Infrastructure/Services/.

Phase 2 — Wire up project references and NuGet packages

  1. Add project reference: Budget.InfrastructureBudget.Core.
  2. Move EF Core + Npgsql NuGet packages from Budget.Api.csproj to Budget.Infrastructure.csproj. Keep only Microsoft.AspNetCore.Authentication.JwtBearer and health-check packages in Budget.Api.csproj.
  3. Add project references to Budget.Api.csproj: both Budget.Core and Budget.Infrastructure.
  4. Add Microsoft.EntityFrameworkCore.Design to Budget.Api.csproj (needed for dotnet ef CLI to find the startup project).

Phase 3 — Update namespaces and using statements

  1. Global search-replace across all moved files: namespace Budget.Apinamespace Budget.Core or namespace Budget.Infrastructure as appropriate.
  2. Update using directives in all controllers, middleware, and Program.cs to reference the new namespaces.

Phase 4 — Update Dockerfile and EF migrations command

  1. Update Dockerfile Stage 2 to copy and restore all three projects before publishing Budget.Api.
  2. Verify dotnet ef migrations add command still works with --project Budget.Infrastructure --startup-project Budget.Api.
  3. Build and confirm zero errors.

Key decisions

  • ClaimsPrincipalExtensions and the two middleware classes stay in Budget.Api — they have direct ASP.NET dependencies and are not reusable across projects.
  • BudgetAuthorizationService goes in Budget.Infrastructure because it queries the DbContext.
  • FrequencyCalculator goes in Budget.Core because it is pure arithmetic with no external dependencies.
  • DTOs stay in Budget.Core (not Budget.Api) so Budget.Infrastructure can reference them if needed without creating a circular dependency.

Files affected

  • Budget.sln
  • New: src/Budget.Core/Budget.Core.csproj
  • New: src/Budget.Infrastructure/Budget.Infrastructure.csproj
  • src/Budget.Api/Budget.Api.csproj (trim NuGet packages, add project refs)
  • All .cs files under src/Budget.Api/ (namespace updates)
  • Dockerfile (Stage 2 COPY pattern)