/simplify pass: efficiency + code-quality batch #52

Merged
eliott merged 1 commit from develop into main 2026-05-15 11:49:13 +02:00
Owner

Summary

Batch from a /simplify pass — efficiency wins + code-quality cleanups across the API.

Efficiency

  • AsNoTracking() added to every read-only repo query
  • FindAccountStateAsync slim projection for the auth filter (was loading the full Roles→Permissions graph to read two booleans)
  • AccountActiveRequirementFilter resolves the user state once and shares it with PermissionRequirementFilter via HttpContext.Items — saves one cache/DB round-trip per authenticated request
  • Every feature service migrated from RemoveByPatternAsync (Redis SCAN) to tag-based InvalidateTagAsync
  • ToggleFavorites writes the join row directly instead of loading the full favourites graph
  • CreateUser parallelizes its independent GetDefaultRole / GetTokenType awaits
  • RolePerUserService.UpdateUserRoles computes add/remove deltas instead of full delete-then-insert
  • RespirationExerciseService drops the redundant user cache+DB round-trip in Update/Delete

Code quality

  • ApiResponse.Ok(...) standardized across controllers (~80 sites)
  • PermissionLabels constants replace stringly-typed permission labels (renamed from Permissions to avoid the cesizen_api.Api.Permissions namespace collision)
  • UserRepository: single shared ToReturnDto projection across all four read paths
  • GlobalExceptionHandler: expected exceptions downgraded from LogError to LogInformation

Test plan

  • dotnet build clean
  • Smoke test authenticated endpoints
  • Verify cache invalidation on mutations
  • Spot-check PermissionLabels-gated endpoints

🤖 Generated with Claude Code

## Summary Batch from a /simplify pass — efficiency wins + code-quality cleanups across the API. ### Efficiency - `AsNoTracking()` added to every read-only repo query - `FindAccountStateAsync` slim projection for the auth filter (was loading the full Roles→Permissions graph to read two booleans) - `AccountActiveRequirementFilter` resolves the user state once and shares it with `PermissionRequirementFilter` via `HttpContext.Items` — saves one cache/DB round-trip per authenticated request - Every feature service migrated from `RemoveByPatternAsync` (Redis SCAN) to tag-based `InvalidateTagAsync` - `ToggleFavorites` writes the join row directly instead of loading the full favourites graph - `CreateUser` parallelizes its independent `GetDefaultRole` / `GetTokenType` awaits - `RolePerUserService.UpdateUserRoles` computes add/remove deltas instead of full delete-then-insert - `RespirationExerciseService` drops the redundant user cache+DB round-trip in Update/Delete ### Code quality - `ApiResponse.Ok(...)` standardized across controllers (~80 sites) - `PermissionLabels` constants replace stringly-typed permission labels (renamed from `Permissions` to avoid the `cesizen_api.Api.Permissions` namespace collision) - `UserRepository`: single shared `ToReturnDto` projection across all four read paths - `GlobalExceptionHandler`: expected exceptions downgraded from `LogError` to `LogInformation` ## Test plan - [ ] dotnet build clean - [ ] Smoke test authenticated endpoints - [ ] Verify cache invalidation on mutations - [ ] Spot-check PermissionLabels-gated endpoints 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- AsNoTracking on every read-only repo query; new FindAccountStateAsync slim projection
- AccountActiveRequirementFilter shares the resolved state with PermissionRequirementFilter via HttpContext.Items so each authenticated request hits the cache once instead of twice
- Migrate every feature service from RemoveByPatternAsync (Redis SCAN) to tag-based InvalidateTagAsync; new <Feature>CacheKeys per module
- ToggleFavorites: direct join-row insert/delete instead of loading the full favourites graph
- ApiResponse.Ok(...) standardization across controllers; remove the `new ApiResponse<T>(200, ...)` form
- PermissionLabels constants replace stringly-typed permission labels (renamed from Permissions to avoid the cesizen_api.Api.Permissions namespace collision)
- CreateUser: parallelize the independent GetDefaultRole / GetTokenType awaits
- UserRepository: single shared ToReturnDto projection across all four read paths so ListUsers can't drift from the detail endpoints
- RolePerUserService.UpdateUserRoles: compute add/remove deltas instead of full delete-then-insert
- GlobalExceptionHandler: downgrade expected exceptions (KeyNotFound, Auth, Validation, BadHttpRequest) from LogError to LogInformation
- RespirationExerciseService: drop the redundant user cache+DB roundtrip in Update/Delete

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eliott merged commit 1abda7e5e1 into main 2026-05-15 11:49:13 +02:00
Commenting is not possible because the repository is archived.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
bloc-cesi/cesizen-api!52
No description provided.