mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-14 17:54:42 +00:00
Features/public biography endpoint (#316)
This commit is contained in:
@@ -176,7 +176,9 @@ brewery photo upload command) rather than bound to an HTTP route directly.
|
||||
|
||||
- All business logic for that feature lives in its command/query handlers
|
||||
- No direct controller-to-repository calls; everything flows through MediatR
|
||||
- Read endpoints return a dedicated `Dto`, never the domain entity directly
|
||||
- Read endpoints return a dedicated `Dto` rather than the domain entity
|
||||
directly. The one exception is `UserController.GetAuthenticated`, which
|
||||
returns the caller's own `UserAccount` entity
|
||||
|
||||
#### Shared projects (`Shared.Contracts`, `Shared.Application`)
|
||||
|
||||
@@ -187,7 +189,7 @@ needs it, or because duplicating it four times would be worse than sharing it
|
||||
|
||||
| Project | Purpose |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Shared.Contracts` | `ResponseBody<T>`/`ResponseBody`, the API response envelope every controller returns |
|
||||
| `Shared.Contracts` | `ResponseBody<T>`/`ResponseBody`, the API response envelope `AuthController`, `BreweryController`, and `CityController` return; `UserController`'s read endpoints return their DTOs unwrapped |
|
||||
| `Shared.Application` | `ValidationBehavior<TRequest,TResponse>`, the MediatR pipeline behavior that runs FluentValidation before a handler executes |
|
||||
|
||||
**Rules**:
|
||||
|
||||
@@ -76,7 +76,7 @@ updates (`UPDATE ... WHERE ... AND RowVersion = @RowVersion`).
|
||||
| `UserAccount` | `Domain.Entities.UserAccount`, `Features.Users` | `Username` and `Email` are unique |
|
||||
| `UserCredential` | `Domain.Entities.UserCredential`, `Features.Users` | Argon2id password hash; `IsRevoked`/`RevokedAt` track credential rotation, not JWTs |
|
||||
| `UserVerification` | `Domain.Entities.UserVerification`, `Features.Users` | Written when a user confirms their email |
|
||||
| `UserProfile` | `Domain.Entities.UserProfile`, `Features.Users` | 1:1 with `UserAccount`; holds the user's biography; written via `IUserProfileRepository` |
|
||||
| `UserProfile` | `Domain.Entities.UserProfile`, `Features.Users` | 1:1 with `UserAccount`; holds the user's biography; written via `IUserProfileRepository`, read via `IUserListRepository.GetByIdAsync`'s left join |
|
||||
| `UserAvatar` | `Domain.Entities.UserAvatar`, `Features.Users` | Links a `UserProfile` to a `Photo` as its avatar; written via `IUserProfileRepository.SaveAvatarAsync` |
|
||||
| `BreweryPost` | `Domain.Entities.BreweryPost`, `Features.Breweries` | A user-submitted brewery listing |
|
||||
| `BreweryPostLocation` | `Domain.Entities.BreweryPostLocation`, `Features.Breweries` | 1:1 with `BreweryPost`; `Coordinates` is a `GEOGRAPHY` column, read via a plain Dapper query that selects `CONVERT(varbinary(max), Coordinates)`, since Dapper can't deserialize SQL Server UDTs directly |
|
||||
|
||||
@@ -250,7 +250,7 @@ API.Specs/
|
||||
│ ├── TokenRefresh.feature # Refresh token scenarios
|
||||
│ ├── AccessTokenValidation.feature # Protected endpoint access scenarios
|
||||
│ ├── NotFound.feature # 404 handling
|
||||
│ └── PublicUserProfile.feature # Public profile & locked-down account scenarios
|
||||
│ └── PublicUserProfile.feature # Public profile & authenticated account scenarios
|
||||
├── Steps/
|
||||
│ ├── AuthSteps.cs # Step definitions for the Auth features
|
||||
│ ├── UserSteps.cs # Step definitions for the public profile & user-account features
|
||||
@@ -282,17 +282,25 @@ Scenario: Successful user registration
|
||||
Features.Users.Tests/
|
||||
├── Commands/
|
||||
│ ├── RegisterUserHandlerTests.cs
|
||||
│ ├── RegisterUserValidatorTests.cs
|
||||
│ ├── ConfirmUserHandlerTests.cs
|
||||
│ ├── ResendConfirmationEmailHandlerTests.cs
|
||||
│ ├── RefreshTokenHandlerTests.cs
|
||||
│ ├── RefreshTokenValidatorTests.cs
|
||||
│ ├── LoginValidatorTests.cs # tests LoginCommand's validator
|
||||
│ ├── UpdateUsernameHandlerTests.cs
|
||||
│ ├── UpdateUsernameValidatorTests.cs
|
||||
│ ├── UpdateEmailHandlerTests.cs
|
||||
│ ├── UpdateEmailValidatorTests.cs
|
||||
│ ├── UpdatePasswordHandlerTests.cs
|
||||
│ ├── UpdatePasswordValidatorTests.cs
|
||||
│ ├── UpdateProfileHandlerTests.cs
|
||||
│ ├── UpdateProfileValidatorTests.cs
|
||||
│ └── DeleteAccountHandlerTests.cs
|
||||
├── Queries/
|
||||
│ ├── LoginHandlerTests.cs # tests LoginCommand, despite the folder name
|
||||
│ ├── GetAllUsersHandlerTests.cs
|
||||
│ ├── GetPublicUserProfileByIdHandlerTests.cs
|
||||
│ └── GetUserByIdHandlerTests.cs
|
||||
├── Services/
|
||||
│ ├── TokenServiceRefreshTests.cs
|
||||
@@ -300,10 +308,13 @@ Features.Users.Tests/
|
||||
└── TestSupport/ # shared test fixtures/helpers
|
||||
```
|
||||
|
||||
Each of the other slices (`Features.Breweries.Tests`, `Features.Emails.Tests`,
|
||||
`Features.PhotoUpload.Tests`) follows the same shape: a `Commands/`/`Queries/`
|
||||
folder with one test file per handler (`Features.PhotoUpload.Tests` also adds a
|
||||
validator test file alongside its handler test).
|
||||
`Features.Breweries.Tests` and `Features.PhotoUpload.Tests` follow the same
|
||||
shape: a `Commands/`/`Queries/` folder with one test file per handler, plus a
|
||||
`*ValidatorTests.cs` file beside each handler whose command or query has a
|
||||
FluentValidation validator (`Features.Breweries.Tests` has one of these in
|
||||
`Queries/` as well, for the nearby-search query). `Features.Emails.Tests`
|
||||
differs: its handlers respond to MediatR notifications, so its test files live
|
||||
under `Notifications/`.
|
||||
|
||||
## Writing tests
|
||||
|
||||
|
||||
Reference in New Issue
Block a user