Staff/admin need the ability to take down a blog post in a way that is fully auditable for history/legal purposes.
Design (approved)
Two-tier takedown:
Hide — reversible; any staff member can hide (required reason) and unhide. Post status becomes Hidden; pre-hide status is stored and restored on unhide.
Remove — soft delete (IsDeleted = true); staff can remove (required reason), only an admin can restore. Nothing is ever hard-deleted.
Authors keep seeing their own hidden/removed posts, marked with the staff reason. The public does not see them at all.
Immutable audit trail: every hide/unhide/remove/restore/author-delete writes a BlogModerationAuditEntry (new blog-moderation-audit Mongo collection): post id, action, actor id/name/roles, reason, previous/new status, title snapshot, author id, IP, user agent, timestamp. Append-only — no update/delete code paths.
Also fixed as part of this work
DELETE /api/blog/posts/{id} had no [Authorize] and performed a hard delete. Now requires auth, only the author or staff/admin may delete, and it soft-deletes with an AuthorDelete audit entry.
Blog endpoints now use the shared AdminOrStaff/AdminOnly policies (#298) instead of only inline role strings.
Commands: HideBlogPost, UnhideBlogPost, RemoveBlogPost, RestoreBlogPost (+ rewritten DeleteBlogPost), all with cache invalidation + activity tracking + audit writes.
Endpoints: POST posts/{id}/hide|unhide|remove (AdminOrStaff), POST posts/{id}/restore (AdminOnly), GET posts/{id}/moderation-history (AdminOrStaff).
Visibility: staff see everything incl. soft-deleted; authors see their own moderated posts; public sees only Published + not-deleted. DTO moderation fields are stripped for other viewers.
Angular (spikersoft-angular)
hidden status + moderation fields in blog.model.ts; hidePost/unhidePost/removePost/restorePost/getModerationHistory in BlogService.
Staff-only moderation menu on blog entries with a required-reason dialog; hidden/removed banner (with reason) visible to the author and staff.
/admin/blog-moderation: new "Moderated Posts" section with Unhide / Restore (admin) and per-post moderation history view.
New lib-local role helper blog-roles.ts (same pattern as art-studio-roles.ts).
Deploy-independent: old Angular simply doesn't show the new buttons.
Staff/admin need the ability to take down a blog post in a way that is fully auditable for history/legal purposes.
## Design (approved)
- **Two-tier takedown:**
- **Hide** — reversible; any staff member can hide (required reason) and unhide. Post status becomes `Hidden`; pre-hide status is stored and restored on unhide.
- **Remove** — soft delete (`IsDeleted = true`); staff can remove (required reason), **only an admin can restore**. Nothing is ever hard-deleted.
- **Authors keep seeing their own hidden/removed posts**, marked with the staff reason. The public does not see them at all.
- **Immutable audit trail:** every hide/unhide/remove/restore/author-delete writes a `BlogModerationAuditEntry` (new `blog-moderation-audit` Mongo collection): post id, action, actor id/name/roles, reason, previous/new status, title snapshot, author id, IP, user agent, timestamp. Append-only — no update/delete code paths.
## Also fixed as part of this work
- `DELETE /api/blog/posts/{id}` had **no `[Authorize]`** and performed a **hard delete**. Now requires auth, only the author or staff/admin may delete, and it soft-deletes with an `AuthorDelete` audit entry.
- Blog endpoints now use the shared `AdminOrStaff`/`AdminOnly` policies (#298) instead of only inline role strings.
## Backend (spikersoft-backend)
- `BlogPostStatus.Hidden`; `BlogPost` fields `ModeratedBy/ModeratedAt/ModerationReason/PreviousStatus/DeletedBy/DeletionReason`.
- Commands: `HideBlogPost`, `UnhideBlogPost`, `RemoveBlogPost`, `RestoreBlogPost` (+ rewritten `DeleteBlogPost`), all with cache invalidation + activity tracking + audit writes.
- Endpoints: `POST posts/{id}/hide|unhide|remove` (AdminOrStaff), `POST posts/{id}/restore` (AdminOnly), `GET posts/{id}/moderation-history` (AdminOrStaff).
- Visibility: staff see everything incl. soft-deleted; authors see their own moderated posts; public sees only Published + not-deleted. DTO moderation fields are stripped for other viewers.
## Angular (spikersoft-angular)
- `hidden` status + moderation fields in `blog.model.ts`; `hidePost/unhidePost/removePost/restorePost/getModerationHistory` in `BlogService`.
- Staff-only moderation menu on blog entries with a required-reason dialog; hidden/removed banner (with reason) visible to the author and staff.
- `/admin/blog-moderation`: new "Moderated Posts" section with Unhide / Restore (admin) and per-post moderation history view.
- New lib-local role helper `blog-roles.ts` (same pattern as `art-studio-roles.ts`).
Deploy-independent: old Angular simply doesn't show the new buttons.
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.
Staff/admin need the ability to take down a blog post in a way that is fully auditable for history/legal purposes.
Design (approved)
Hidden; pre-hide status is stored and restored on unhide.IsDeleted = true); staff can remove (required reason), only an admin can restore. Nothing is ever hard-deleted.BlogModerationAuditEntry(newblog-moderation-auditMongo collection): post id, action, actor id/name/roles, reason, previous/new status, title snapshot, author id, IP, user agent, timestamp. Append-only — no update/delete code paths.Also fixed as part of this work
DELETE /api/blog/posts/{id}had no[Authorize]and performed a hard delete. Now requires auth, only the author or staff/admin may delete, and it soft-deletes with anAuthorDeleteaudit entry.AdminOrStaff/AdminOnlypolicies (#298) instead of only inline role strings.Backend (spikersoft-backend)
BlogPostStatus.Hidden;BlogPostfieldsModeratedBy/ModeratedAt/ModerationReason/PreviousStatus/DeletedBy/DeletionReason.HideBlogPost,UnhideBlogPost,RemoveBlogPost,RestoreBlogPost(+ rewrittenDeleteBlogPost), all with cache invalidation + activity tracking + audit writes.POST posts/{id}/hide|unhide|remove(AdminOrStaff),POST posts/{id}/restore(AdminOnly),GET posts/{id}/moderation-history(AdminOrStaff).Angular (spikersoft-angular)
hiddenstatus + moderation fields inblog.model.ts;hidePost/unhidePost/removePost/restorePost/getModerationHistoryinBlogService./admin/blog-moderation: new "Moderated Posts" section with Unhide / Restore (admin) and per-post moderation history view.blog-roles.ts(same pattern asart-studio-roles.ts).Deploy-independent: old Angular simply doesn't show the new buttons.
Resolved: spikersoft-backend PR #203 (auditable staff hide/remove with immutable audit trail) and spikersoft-angular PR #158 (staff moderation UI — hide/remove with reasons, banners, admin view) + #159 (lint follow-up), all merged to master 2026-07-11. Two-tier hide/remove, append-only BlogModerationAuditEntry collection, and author-visible reasons shipped per the approved design. Closing.