Continuous Integration / config (pull_request) Successful in 11s
Continuous Integration / changes (pull_request) Successful in 21s
Continuous Integration / backend-build (pull_request) Successful in 6m10s
Continuous Integration / vulnerability-scan (pull_request) Successful in 4m59s
Continuous Integration / frontend-prepare (pull_request) Successful in 1m27s
Continuous Integration / backend-test (pull_request) Failing after 7m48s
Continuous Integration / frontend-build (pull_request) Successful in 2m5s
Continuous Integration / frontend-test (pull_request) Successful in 4m24s
Continuous Integration / frontend-lint (pull_request) Successful in 2m0s
Continuous Integration / publish-test (pull_request) Skipped
Continuous Integration / publish-production (pull_request) Skipped
Continuous Integration / deploy-test (pull_request) Skipped
Continuous Integration / deploy-production (pull_request) Skipped
Unit 1 of the slpsoftware-api feature (FR-1/FR-2/FR-3): a new Client project in the Clients solution folder, intended to eventually become the deployed API for test.slpsoftware.nl/slpsoftware.nl, hosting the same four modules as SlpModularCms.Api plus a future Offerings module. - Extracts SlpModularCms.Api/Program.cs's hosting-pipeline composition into SlpModularCms.Core.Hosting.CmsHost (ConfigureServices/ConfigurePipeline), shared by both Client projects so they cannot drift apart - Moves StaticContentExtensions.cs + WebsitePlaceholder.html from Api into Core, since CmsHost cannot live in Api but Core cannot depend on Api - Adds SlpModularCms.Api.SlpSoftware with its own isolated local dev database and dev ports (5286/7223, distinct from Api's and Api.Slave's) - Adds SlpModularCms.Api.Tests with WebApplicationFactory-based pipeline regression tests (security headers, health check, SPA fallback, rate limiting), scoped to Api per NFR Design - Adds a frontend dev:slpsoftware pnpm script mirroring dev:slave - Fixes GlobalExceptionHandler logging routine 401s (e.g. an expired/missing refresh token) as unhandled errors -- pre-existing, unrelated to this feature's own scope, found while testing the new instance Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FWyStNL2ZsjrS7FLd7xvvN
5.5 KiB
5.5 KiB
Component Methods — SlpSoftware Production API
Note: Signatures and high-level purpose only. Detailed business rules (exact exclusivity algorithm, validation rules, reorder edge cases) are defined in Functional Design for the relevant unit (CONSTRUCTION phase).
CmsHost (static class, SlpModularCms.Core.Hosting)
| Method | Input | Output | Purpose |
|---|---|---|---|
ConfigureServices |
WebApplicationBuilder builder |
ModuleOrchestrator |
Runs logging/Sentry setup, discovers and registers module services, registers core infrastructure (CORS, rate limiting, health checks, security headers, observability, Data Protection), and configures MVC controllers. Returns the ModuleOrchestrator instance so the caller can pass it into ConfigurePipeline after builder.Build(). |
ConfigurePipeline |
WebApplication app, ModuleOrchestrator orchestrator |
void |
Runs the Core DB migration, wires the exception handler, security headers, rate limiter, Development-only OpenAPI/Scalar, HTTPS redirection, static content + SPA fallbacks, CORS, module middleware (orchestrator.UseModules), authentication/authorization, controller mapping, health checks, and the Sentry tunnel — in the exact order Api/Program.cs uses today, since that order encodes real constraints (documented as code comments in the current Program.cs). |
Each project's Program.cs becomes:
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("appsettings.local.json", optional: true, reloadOnChange: true);
var orchestrator = CmsHost.ConfigureServices(builder);
var app = builder.Build();
CmsHost.ConfigurePipeline(app, orchestrator);
app.Run();
IOfferingRepository (SlpModularCms.Modules.Offerings.Repositories)
| Method | Input | Output | Purpose |
|---|---|---|---|
GetAllAsync |
— | IReadOnlyList<Offering> |
All non-deleted offerings, ordered by DisplayOrder. |
GetByIdAsync |
Guid id |
Offering? |
Single non-deleted offering, or null. |
AddAsync |
Offering offering |
Offering |
Persist a new offering. |
UpdateAsync |
Offering offering |
Offering |
Persist changes to an existing offering. |
GetMaxDisplayOrderAsync |
— | int |
Used by the service to append new offerings at the end of the display order. |
GetFeaturedAsync |
— | Offering? |
The currently-featured offering (if any), used to enforce exclusivity. |
IOfferingsService (SlpModularCms.Modules.Offerings.Services)
| Method | Input | Output | Purpose |
|---|---|---|---|
GetPublicOfferingsAsync |
— | IReadOnlyList<OfferingDto> |
Backs FR-6 / US-01, US-02, US-03. |
GetAllForAdminAsync |
— | IReadOnlyList<OfferingAdminDto> |
Backs the admin list view. |
CreateAsync |
CreateOfferingRequest request |
OfferingAdminDto |
Backs US-04. Assigns a new Id (Q4 = A) and appends to the end of DisplayOrder. If request.Featured is true, un-features the previously-featured offering (US-10). |
UpdateAsync |
Guid id, UpdateOfferingRequest request |
OfferingAdminDto |
Backs US-05. Same featured-exclusivity handling as CreateAsync when request.Featured is true. |
DeleteAsync |
Guid id |
void |
Backs US-06/US-07. Soft-delete (Q5 = B) — always allowed, including for the last remaining offering. |
ReorderAsync |
IReadOnlyList<Guid> orderedIds |
void |
Backs US-08 (drag-and-drop). Full-list reorder — reassigns DisplayOrder to match the given sequence. |
MoveUpAsync |
Guid id |
void |
Backs US-09. Swaps DisplayOrder with the immediately preceding offering. |
MoveDownAsync |
Guid id |
void |
Backs US-09. Swaps DisplayOrder with the immediately following offering. |
OfferingsController (SlpModularCms.Modules.Offerings.Controllers)
| Action | Route | Auth | Input | Output | Purpose |
|---|---|---|---|---|---|
GetOfferings |
GET /api/v1/offerings |
[AllowAnonymous] |
— | 200 OK, OfferingDto[] |
FR-6 |
GetAllForAdmin |
GET /api/v1/offerings/admin |
AdminOnly |
— | 200 OK, OfferingAdminDto[] |
Admin list view |
Create |
POST /api/v1/offerings/admin |
AdminOnly |
CreateOfferingRequest |
201 Created, OfferingAdminDto |
US-04 |
Update |
PUT /api/v1/offerings/admin/{id} |
AdminOnly |
UpdateOfferingRequest |
200 OK, OfferingAdminDto |
US-05 |
Delete |
DELETE /api/v1/offerings/admin/{id} |
AdminOnly |
— | 204 No Content |
US-06/US-07 |
Reorder |
PUT /api/v1/offerings/admin/reorder |
AdminOnly |
ReorderOfferingsRequest (ordered Guid[]) |
204 No Content |
US-08 |
MoveUp |
POST /api/v1/offerings/admin/{id}/move-up |
AdminOnly |
— | 204 No Content |
US-09 |
MoveDown |
POST /api/v1/offerings/admin/{id}/move-down |
AdminOnly |
— | 204 No Content |
US-09 |
Note: Exact route naming (e.g. /admin suffix vs. a route-group prefix) may be refined in Functional Design or Code Generation Planning; the split shown here keeps the public route exactly as FR-6 specifies while keeping admin routes obviously distinct, consistent with decision Q3 (single controller, per-action authorization).
OfferingsModule (SlpModularCms.Modules.Offerings)
| Method | Input | Output | Purpose |
|---|---|---|---|
RegisterServices |
IServiceCollection services |
void |
Registers OfferingsDbContext (MySQL), IOfferingRepository/OfferingRepository, IOfferingsService/OfferingsService. |
UseModule |
IApplicationBuilder app |
void |
Applies pending OfferingsDbContext migrations. |