Adds the Offerings module and retargets the CI/CD pipeline to Api.SlpSoftware
Continuous Integration / config (pull_request) Successful in 12s
Continuous Integration / changes (pull_request) Successful in 22s
Continuous Integration / backend-build (pull_request) Successful in 5m53s
Continuous Integration / vulnerability-scan (pull_request) Successful in 5m46s
Continuous Integration / frontend-prepare (pull_request) Successful in 1m54s
Continuous Integration / backend-test (pull_request) Successful in 7m37s
Continuous Integration / frontend-build (pull_request) Successful in 2m14s
Continuous Integration / frontend-test (pull_request) Successful in 4m59s
Continuous Integration / frontend-lint (pull_request) Successful in 2m2s
Continuous Integration / publish-production (pull_request) Skipped
Continuous Integration / deploy-production (pull_request) Skipped
Continuous Integration / publish-test (pull_request) Successful in 7m34s
Continuous Integration / deploy-test (pull_request) Skipped

Implements Unit 2 "Offerings" (backend module, admin CRUD UI with
drag-and-drop reordering, public GET /api/v1/offerings endpoint) and
executes the feature's D-15 CI/CD cutover, switching the deploy
pipeline's build/publish target from SlpModularCms.Api to
SlpModularCms.Api.SlpSoftware.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWyStNL2ZsjrS7FLd7xvvN
This commit is contained in:
2026-08-02 16:23:09 +02:00
co-authored by Claude Sonnet 5
parent b6e9c07c06
commit cfb06b28b6
79 changed files with 4069 additions and 94 deletions
@@ -0,0 +1,26 @@
# NFR Design Plan — Unit: Offerings
**Categorieën die niet van toepassing zijn (met onderbouwing, niet zomaar overgeslagen)**:
- **Scalability Patterns**: N/A — een freelancer-website met een handvol offerings (naar verwachting < 50 rijen); geen schaal-grens om voor te ontwerpen.
- **Performance Patterns**: N/A buiten wat al besloten is — geen caching (NFR-OFF-02), geen zwaar rekenwerk; `GetAllAsync`/`GetPublicOfferingsAsync` zijn simpele, geïndexeerde queries.
- **Security Patterns (rate limiting)**: geen losse vraag nodig — bestaand precedent in `AuthController` (`[EnableRateLimiting("login")]`/`[EnableRateLimiting("refresh")]`, per-actiemethode) wordt direct hergebruikt: `[EnableRateLimiting("offerings-public")]` komt op de publieke `GET`-actiemethode in `OfferingsController`, niet op de admin-mutatie-acties (die geen policy krijgen, per NFR-OFF-01 Q1=A).
**Wél een open ontwerpvraag gevonden**: `services.md` (Application Design) had de transactiegrens voor multi-row-operaties expliciet doorgeschoven naar Functional Design ("Exact transactional boundaries ... are a Functional Design decision for the Offerings unit, not decided here"), maar noch `business-logic-model.md` noch `business-rules.md` heeft dit vastgelegd. Dit raakt direct een NFR (data-integriteit), dus leg ik 'm hier alsnog voor in plaats van 'm stilzwijgend zelf te beslissen.
## Uitvoeringschecklist
- [x] Stap A — `nfr-design-patterns.md`: transactiepatroon, rate-limiting-toepassing, logging-velden vastleggen
- [x] Stap B — `logical-components.md`: `OfferingsService`'s multi-row-operaties en de nieuwe rate-limiting-policy als logische componenten beschrijven
---
## Vragen
### Vraag 1 — Transactiegrens voor multi-row-operaties
Drie operaties in `OfferingsService` raken meer dan één rij in dezelfde logische actie: de featured-exclusiviteitswissel (create/update met `Featured=true`, US-10), de volledige drag-and-drop-reorder (US-08), en de aangrenzende swap via knoppen (US-09). Moeten deze in één DB-transactie (`BeginTransaction`/`Commit`) of als opeenvolgende, niet-transactionele `SaveChangesAsync`-aanroepen?
A) Eén DB-transactie per operatie — garandeert dat bijv. een reorder van 10 rijen nooit half doorgevoerd raakt bij een crash/verbindingsfout; iets meer code (expliciet transactiebeheer), maar dit is precies waar transacties voor bestaan
B) Opeenvolgende `SaveChangesAsync`-aanroepen zonder expliciete transactie — eenvoudiger; een falen halverwege laat de dataset in een inconsistente staat (bijv. twee offerings zonder featured, of dubbele `DisplayOrder`-waarden) tot een volgende succesvolle actie het herstelt; geaccepteerd risico gezien de kleine schaal (1 admin, handmatig direct zichtbaar/herstelbaar)
X) Anders (beschrijf hieronder na de [Answer]:-tag)
[Answer]:A