Skip to content

feat(domain): introduce PostAuthor value object for blog post authorship (#296)#298

Merged
mpaulosky merged 4 commits into
devfrom
squad/296-post-author-value-object
May 11, 2026
Merged

feat(domain): introduce PostAuthor value object for blog post authorship (#296)#298
mpaulosky merged 4 commits into
devfrom
squad/296-post-author-value-object

Conversation

@mpaulosky

Copy link
Copy Markdown
Owner

Summary

Implements Issue #296 — auto-fill Author when creating a new blog post.

Closes #296

Working as Sam (Backend Developer)

Changes

  • New: PostAuthor sealed record in MyBlog.Domain.ValueObjects (Id, Name, Email, Roles + PostAuthor.Empty helper)
  • Domain: BlogPost.Author changed from string to PostAuthor; Create() guards null author and empty Name
  • Infrastructure: BlogDbContext uses OwnsOne to map PostAuthor as a MongoDB sub-document
  • DTO: BlogPostDto flattens PostAuthor to AuthorId, AuthorName, AuthorEmail, AuthorRoles
  • Command/Validation: CreateBlogPostCommand.Author is now PostAuthor; validator checks NotNull + Name.NotEmpty
  • UI stub: Create.razor has a temporary placeholder constructing PostAuthor from a form field — Legolas needs to replace this with AuthenticationStateProvider injection
  • Tests: All test projects updated for new types and constructor signatures

Breaking Change

Existing MongoDB documents with "Author": "string" will fail to deserialize. Dev: drop/recreate collection. Prod: migration script needed (out of scope Sprint 19).

Notes for Legolas

Create.razor still has an Author text input as a placeholder. The next step is to inject AuthenticationStateProvider, read claims (NameIdentifier, Name, Email, roles), and build PostAuthor automatically — removing the manual input field.

Copilot AI review requested due to automatic review settings May 11, 2026 19:08
@github-actions github-actions Bot added the squad Squad triage inbox — Lead will assign to a member label May 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ PR Added to Squad Triage Queue

This PR has been labeled with squad and added to the triage queue.

Next steps:

  • The squad Lead will review and assign to an appropriate team member
  • A squad:member label will be added after triage

If you know which squad member should handle this, you can add the appropriate squad:member label yourself.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a structured PostAuthor value object and threads it through the domain, persistence, DTO mapping, validators, UI, and tests to support capturing richer authorship data on blog posts (Issue #296).

Changes:

  • Added PostAuthor value object and updated BlogPost.Author from string to PostAuthor, including creation guards.
  • Updated MongoDB EF Core mapping (OwnsOne) and web DTO/mapping to flatten author fields (AuthorId, AuthorName, AuthorEmail, AuthorRoles).
  • Updated create flow command/validation and adjusted unit/integration/bUnit tests for the new author model.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Web.Tests/Infrastructure/Caching/BlogPostCacheServiceTests.cs Updated cached DTO construction to new flattened author DTO shape.
tests/Web.Tests/Handlers/GetBlogPostsHandlerTests.cs Updated handler tests to construct BlogPost with PostAuthor and updated DTOs.
tests/Web.Tests/Handlers/EditBlogPostHandlerTests.cs Updated handler tests for new BlogPost.Create signature and DTO shape.
tests/Web.Tests/Handlers/CreateBlogPostHandlerTests.cs Updated create handler tests to pass PostAuthor into the command.
tests/Web.Tests/GlobalUsings.cs Added MyBlog.Domain.ValueObjects global using for tests.
tests/Web.Tests/Features/BlogPosts/Commands/CreateBlogPostDomainCommandValidatorTests.cs Updated validation tests for PostAuthor (null + name validation).
tests/Web.Tests/Features/BlogPosts/Commands/CreateBlogPostCommandValidatorTests.cs Updated validator tests for PostAuthor fields and property paths.
tests/Web.Tests/Data/BlogPostMappingsTests.cs Updated mapping assertions to verify flattened author DTO fields.
tests/Web.Tests/BlogPostTests.cs Updated entity unit tests for PostAuthor and new author guards.
tests/Web.Tests/Behaviors/ValidationBehaviorTests.cs Updated pipeline tests to use PostAuthor in commands.
tests/Web.Tests.Integration/GlobalUsings.cs Added MyBlog.Domain.ValueObjects global using for integration tests.
tests/Web.Tests.Integration/Caching/BlogPostCacheServiceTests.cs Updated integration cache DTO construction for flattened author fields.
tests/Web.Tests.Integration/BlogPosts/MongoDbBlogPostRepositoryTests.cs Updated integration repo tests to persist/load PostAuthor instead of string author.
tests/Web.Tests.Bunit/GlobalUsings.cs Added MyBlog.Domain.ValueObjects global using for bUnit tests.
tests/Web.Tests.Bunit/Components/RazorSmokeTests.cs Updated UI smoke tests for new DTO shape and command author object.
tests/Domain.Tests/GlobalUsings.cs Added MyBlog.Domain.ValueObjects global using for domain tests.
tests/Domain.Tests/Entities/BlogPostTests.cs Updated domain entity tests for PostAuthor and new guards.
src/Web/Features/BlogPosts/List/Index.razor Updated list UI to display AuthorName instead of prior Author string.
src/Web/Features/BlogPosts/Create/CreateBlogPostCommandValidator.cs Updated validator to validate PostAuthor presence and Author.Name.
src/Web/Features/BlogPosts/Create/CreateBlogPostCommand.cs Updated command contract to use PostAuthor instead of string.
src/Web/Features/BlogPosts/Create/Create.razor Updated submit handler to construct a PostAuthor for the create command.
src/Web/Data/BlogPostMappings.cs Updated mapping to flatten PostAuthor into BlogPostDto.
src/Web/Data/BlogPostDto.cs Updated DTO contract to carry flattened author identity fields and roles.
src/Web/Data/BlogDbContext.cs Added OwnsOne mapping for BlogPost.Author as an embedded MongoDB document.
src/Domain/ValueObjects/PostAuthor.cs Added new PostAuthor value object record (Id/Name/Email/Roles + Empty).
src/Domain/Entities/BlogPost.cs Updated domain entity to store PostAuthor and enforce author null/name guards.

Comment on lines +27 to +30
.WithMessage("Author is required.");
RuleFor(x => x.Author.Name)
.NotEmpty()
.WithMessage("Author name is required.")
Comment on lines +16 to +20
public sealed record PostAuthor(
string Id,
string Name,
string Email,
IReadOnlyList<string> Roles)
Comment on lines +49 to +50
var author = new PostAuthor(string.Empty, _model.Author, string.Empty, []);
var result = await Sender.Send(new CreateBlogPostCommand(_model.Title, _model.Content, author));
@github-actions

github-actions Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Test Results Summary

354 tests   - 2   353 ✅  - 2   19s ⏱️ ±0s
  6 suites ±0     1 💤 ±0 
  6 files   ±0     0 ❌ ±0 

Results for commit fb9db3c. ± Comparison against base commit 4b5d0d2.

This pull request removes 15 and adds 13 tests. Note that renamed tests count towards both.
Tests.Domain.Entities.BlogPostTests ‑ Create NullOrWhiteSpaceAuthor ThrowsArgumentException(author: "   ")
Tests.Domain.Entities.BlogPostTests ‑ Create NullOrWhiteSpaceAuthor ThrowsArgumentException(author: "")
Tests.Domain.Entities.BlogPostTests ‑ Create NullOrWhiteSpaceAuthor ThrowsArgumentException(author: null)
Tests.Unit.Features.BlogPosts.Commands.CreateBlogPostDomainCommandValidatorTests ‑ Validate AuthorExceedsMaxLength FailsValidation
Tests.Unit.Features.BlogPosts.Commands.CreateBlogPostDomainCommandValidatorTests ‑ Validate EmptyAuthor FailsValidation(author: "")
Tests.Unit.Features.BlogPosts.Commands.CreateBlogPostDomainCommandValidatorTests ‑ Validate EmptyAuthor FailsValidation(author: null)
Web.BlogPostTests ‑ Create WithBlankArgs ThrowsArgumentException(title: "", content: "content", author: "author")
Web.BlogPostTests ‑ Create WithBlankArgs ThrowsArgumentException(title: "title", content: "", author: "author")
Web.BlogPostTests ‑ Create WithBlankArgs ThrowsArgumentException(title: "title", content: "content", author: "")
Web.Features.BlogPosts.Commands.CreateBlogPostCommandValidatorTests ‑ Validate AuthorAtMaxLength ReturnsNoErrors
…
Tests.Domain.Entities.BlogPostTests ‑ Create NullAuthor ThrowsArgumentNullException
Tests.Domain.Entities.BlogPostTests ‑ Create WhiteSpaceAuthorName ThrowsArgumentException(authorName: "   ")
Tests.Domain.Entities.BlogPostTests ‑ Create WhiteSpaceAuthorName ThrowsArgumentException(authorName: "")
Tests.Unit.Features.BlogPosts.Commands.CreateBlogPostDomainCommandValidatorTests ‑ Validate AuthorWithEmptyName FailsValidation
Tests.Unit.Features.BlogPosts.Commands.CreateBlogPostDomainCommandValidatorTests ‑ Validate NullAuthor FailsValidation
Web.BlogPostTests ‑ Create WithBlankTitleOrContent ThrowsArgumentException(title: "", content: "content")
Web.BlogPostTests ‑ Create WithBlankTitleOrContent ThrowsArgumentException(title: "title", content: "")
Web.BlogPostTests ‑ Create WithEmptyAuthorName ThrowsArgumentException
Web.BlogPostTests ‑ Create WithNullAuthor ThrowsArgumentNullException
Web.Features.BlogPosts.Commands.CreateBlogPostCommandValidatorTests ‑ Validate AuthorWithEmptyName ReturnsError
…

♻️ This comment has been updated with latest results.

@mpaulosky

Copy link
Copy Markdown
Owner Author

Triage: ✅ Routed to Sam (Backend Developer)

This PR implements PostAuthor value object per feature #296. The PR body correctly identifies the work as backend domain (Domain, Infrastructure, DTO, Command/Validation, Tests). Sam will own implementation.

Note for Legolas: UI stub in Create.razor still needs AuthenticationStateProvider injection to auto-populate PostAuthor from auth claims.

@codecov

codecov Bot commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.75000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.08%. Comparing base (4b5d0d2) to head (fb9db3c).

Files with missing lines Patch % Lines
src/Web/Features/BlogPosts/Create/Create.razor 78.57% 0 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #298      +/-   ##
==========================================
+ Coverage   82.80%   83.08%   +0.28%     
==========================================
  Files          46       47       +1     
  Lines        1192     1230      +38     
  Branches      145      148       +3     
==========================================
+ Hits          987     1022      +35     
  Misses        147      147              
- Partials       58       61       +3     
Files with missing lines Coverage Δ
src/Domain/Entities/BlogPost.cs 100.00% <100.00%> (ø)
src/Domain/ValueObjects/PostAuthor.cs 100.00% <100.00%> (ø)
src/Web/Data/BlogDbContext.cs 100.00% <100.00%> (ø)
src/Web/Data/BlogPostDto.cs 100.00% <100.00%> (ø)
src/Web/Data/BlogPostMappings.cs 100.00% <100.00%> (ø)
...Features/BlogPosts/Create/CreateBlogPostCommand.cs 100.00% <100.00%> (ø)
...BlogPosts/Create/CreateBlogPostCommandValidator.cs 100.00% <100.00%> (ø)
src/Web/Features/BlogPosts/List/Index.razor 86.84% <100.00%> (ø)
src/Web/Features/BlogPosts/Create/Create.razor 87.50% <78.57%> (-12.50%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Boromir and others added 4 commits May 11, 2026 12:32
…hip (#296)

- Add PostAuthor sealed record (Id, Name, Email, Roles) with PostAuthor.Empty helper
- Replace string Author with PostAuthor on BlogPost entity and Create() factory
- Update BlogDbContext with OwnsOne mapping for PostAuthor sub-document
- Flatten PostAuthor fields in BlogPostDto (AuthorId, AuthorName, AuthorEmail, AuthorRoles)
- Update BlogPostMappings.ToDto() for new flat DTO shape
- Update CreateBlogPostCommand to carry PostAuthor; update FluentValidation rules
- Add temporary stub in Create.razor (Legolas to inject AuthenticationStateProvider)
- Update Index.razor to use @post.AuthorName
- Update all test projects for new types and constructor signatures

BREAKING: Existing MongoDB docs with 'Author' string field must be migrated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
#296)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove manual Author input from Create.razor. Inject AuthenticationStateProvider
and populate PostAuthor from the logged-in user's claims (sub, name, email, roles)
in OnInitializedAsync. Pass PostAuthor to CreateBlogPostCommand in HandleSubmit.
Show read-only "Author: {name}" display above the form for transparency.
Uses RoleClaimsHelper.GetRoles() consistent with Profile.razor pattern.

Add TestAuthenticationStateProvider to bUnit test support so Create component
tests can resolve the injected AuthenticationStateProvider. Update RazorSmokeTests
to register it in DI, set the user in RenderWithUser, and remove stale assertions
that assumed an Author input field.

Closes #296

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Aragorn: PR #297 merge review, PR #295 merge patterns, ADR #296
- Legolas: Create.razor auth auto-fill patterns

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mpaulosky
mpaulosky force-pushed the squad/296-post-author-value-object branch from aa66e0a to fb9db3c Compare May 11, 2026 19:33
@mpaulosky
mpaulosky merged commit 3c4ed03 into dev May 11, 2026
19 checks passed
@mpaulosky
mpaulosky deleted the squad/296-post-author-value-object branch May 11, 2026 19:42
mpaulosky pushed a commit that referenced this pull request May 11, 2026
Summary: PRs #297, #298, #301, #302 merged. Issues #293, #296, #299,
#300 all closed. Sprint 19 complete.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

squad Squad triage inbox — Lead will assign to a member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Sprint 19] feat(app): auto-fill Author when creating a new blog post

2 participants