toddcan opens blog-create and gets "Blog posting isn't turned on / Ask a parent to enable blog posting in your parental control settings" — even though spikerj granted it. Verified in the live cluster: toddcan's ParentalControls.Permissions.BlogPosting = true in Mongo. The grant is fine.
Root cause
ProfileMapper.ToDto (SpikerSoft.Business/Domain/Profile/DTOs/ProfileDtos.cs ~line 357) builds the child's own profile response with a hand-rolled FeaturePermissionsDto that maps only 8 of the 13 fields — omitting InfoVault, BlogPosting, ParentPreApprovesBlogPosts, Photography, PhotoLocationSharing. Those come back as DTO defaults, so the child's own GetProfile always reports blogPosting=false (and photography=false, etc.) regardless of what the parent granted.
Frontend gates that read the child's own profile are all affected:
any photography gating reading the child's own permissions.photography
The server-side hard gates are NOT affected (DeterminePostStatus reads the DB entity directly), so this is a pure display/UX block — the child is told the permission is off when it's on.
This is the third mapper of the same family: the #729 clobber fix (PR #432) brought FeaturePermissionsDto, the GetChildren read mapper, and UpdateChildPermissionsCommandHandler into 13-field lockstep, but missed ProfileMapper.ToDto.
Fix
Map all 13 fields in ProfileMapper.ToDto; add a mapper pin test alongside the existing round-trip test so all THREE permission mappers stay in lockstep with the entity.
## Symptom
toddcan opens blog-create and gets **"Blog posting isn't turned on / Ask a parent to enable blog posting in your parental control settings"** — even though spikerj granted it. Verified in the live cluster: toddcan's `ParentalControls.Permissions.BlogPosting = true` in Mongo. The grant is fine.
## Root cause
`ProfileMapper.ToDto` (`SpikerSoft.Business/Domain/Profile/DTOs/ProfileDtos.cs` ~line 357) builds the child's own profile response with a hand-rolled `FeaturePermissionsDto` that maps only **8 of the 13** fields — omitting `InfoVault`, `BlogPosting`, `ParentPreApprovesBlogPosts`, `Photography`, `PhotoLocationSharing`. Those come back as DTO defaults, so the child's own GetProfile always reports `blogPosting=false` (and `photography=false`, etc.) regardless of what the parent granted.
Frontend gates that read the child's own profile are all affected:
- `blog-create.ts:105` → the reported blocked message
- reading-journey `canBlogAboutBooks` (#719) → blog-about-book button stays disabled
- any photography gating reading the child's own `permissions.photography`
The server-side hard gates are NOT affected (`DeterminePostStatus` reads the DB entity directly), so this is a pure display/UX block — the child is told the permission is off when it's on.
This is the third mapper of the same family: the #729 clobber fix (PR #432) brought `FeaturePermissionsDto`, the GetChildren read mapper, and `UpdateChildPermissionsCommandHandler` into 13-field lockstep, but missed `ProfileMapper.ToDto`.
## Fix
Map all 13 fields in `ProfileMapper.ToDto`; add a mapper pin test alongside the existing round-trip test so all THREE permission mappers stay in lockstep with the entity.
Resolved in spikersoft-backend PR #435 (merged to master 2026-07-20 15:58Z). ProfileMapper.ToDto now maps all 13 FeaturePermissions fields (was 8 — BlogPosting, Photography, PhotoLocationSharing, InfoVault, ParentPreApprovesBlogPosts were dropped), with a pin test where every value is the opposite of its DTO default so a dropped mapping can't pass. Once the API deploy rolls, toddcan's blog-create unblocks with no data changes (BlogPosting=true was already in his profile). Closing.
Resolved in spikersoft-backend PR #435 (merged to `master` 2026-07-20 15:58Z). `ProfileMapper.ToDto` now maps all 13 FeaturePermissions fields (was 8 — BlogPosting, Photography, PhotoLocationSharing, InfoVault, ParentPreApprovesBlogPosts were dropped), with a pin test where every value is the opposite of its DTO default so a dropped mapping can't pass. Once the API deploy rolls, toddcan's blog-create unblocks with no data changes (`BlogPosting=true` was already in his profile). Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Symptom
toddcan opens blog-create and gets "Blog posting isn't turned on / Ask a parent to enable blog posting in your parental control settings" — even though spikerj granted it. Verified in the live cluster: toddcan's
ParentalControls.Permissions.BlogPosting = truein Mongo. The grant is fine.Root cause
ProfileMapper.ToDto(SpikerSoft.Business/Domain/Profile/DTOs/ProfileDtos.cs~line 357) builds the child's own profile response with a hand-rolledFeaturePermissionsDtothat maps only 8 of the 13 fields — omittingInfoVault,BlogPosting,ParentPreApprovesBlogPosts,Photography,PhotoLocationSharing. Those come back as DTO defaults, so the child's own GetProfile always reportsblogPosting=false(andphotography=false, etc.) regardless of what the parent granted.Frontend gates that read the child's own profile are all affected:
blog-create.ts:105→ the reported blocked messagecanBlogAboutBooks(#719) → blog-about-book button stays disabledpermissions.photographyThe server-side hard gates are NOT affected (
DeterminePostStatusreads the DB entity directly), so this is a pure display/UX block — the child is told the permission is off when it's on.This is the third mapper of the same family: the #729 clobber fix (PR #432) brought
FeaturePermissionsDto, the GetChildren read mapper, andUpdateChildPermissionsCommandHandlerinto 13-field lockstep, but missedProfileMapper.ToDto.Fix
Map all 13 fields in
ProfileMapper.ToDto; add a mapper pin test alongside the existing round-trip test so all THREE permission mappers stay in lockstep with the entity.Resolved in spikersoft-backend PR #435 (merged to
master2026-07-20 15:58Z).ProfileMapper.ToDtonow maps all 13 FeaturePermissions fields (was 8 — BlogPosting, Photography, PhotoLocationSharing, InfoVault, ParentPreApprovesBlogPosts were dropped), with a pin test where every value is the opposite of its DTO default so a dropped mapping can't pass. Once the API deploy rolls, toddcan's blog-create unblocks with no data changes (BlogPosting=truewas already in his profile). Closing.