Joey requested a full-scale UI/UX + feature review of learn.spikersoft.com/blog (management surfaces, element positioning, enhancement opportunities). The review's headline gap — authors couldn't delete their own posts — is implemented outside this epic:
spikersoft-backend #422 — retention purge: 7-day window then full erasure (disk media, blogs/quarantine bucket objects, workflow docs with EXIF/GPS PII; moderation audit anonymized)
spikerj/spikersoft-angular#634 — [TechDebt][Blog] Two base-URL sources — service uses API_BASE_URL token, media URLs use environment.baseUrl (was #715)
Checklist generated by the umbrella-tracker migration, 2026-08-07 — Opus 5 Agent
## Context
Joey requested a full-scale UI/UX + feature review of learn.spikersoft.com/blog (management surfaces, element positioning, enhancement opportunities). The review's headline gap — **authors couldn't delete their own posts** — is implemented outside this epic:
- spikersoft-backend **#422** — retention purge: 7-day window then full erasure (disk media, `blogs`/`quarantine` bucket objects, workflow docs with EXIF/GPS PII; moderation audit anonymized)
- spikersoft-backend **#423** — create-provenance hardening (`[Authorize]` + AuthorId from Keycloak `sub`)
- spikersoft-angular **#420** — the owner-delete affordance on post cards
Everything else found in the review becomes this epic's children, in rough priority order:
## Children
1. **Media delete broken end-to-end** [bug, high]
2. **Comment identity hardcoded** [bug]
3. **"My posts" management view** [feature]
4. **Author edit UI** [feature]
5. **Server-side pagination + filtering** [perf/UX]
6. **Responsive media grid** [UX]
7. **Create-flow navigation + unsaved-changes guard** [UX]
8. **Moderation shield tooltip** [UX, small]
9. **Theme-token colors in blog SCSS** [UX, small]
10. **Blog e2e spec** [test]
11. **Unify base-URL sources** [tech debt]
12. **Provenance-gap record** [security, closes with backend #423]
(Each filed as its own ticket referencing this epic; numbers linked in comments below as they're filed.)
## Review evidence base
Angular: `libraries/features/blog/**` (list/entry/create components), `libraries/domain/blog/**` (service — full API surface incl. unused `getMyPosts`), routes (`/blog` public, `/blog/create` auth, `/admin/blog-moderation` admin). Backend: `BlogController` (20 endpoints), 3 Mongo collections, 5-consumer media pipeline. Full traces in the child tickets.
<!-- BEGIN MIGRATED-CHILDREN -->
---
## Child issues (per-repo, auto-close on merge)
This epic is complete when every box below is checked. Each child lives in the
repo that holds its fix, so `fixes #N` in a PR closes it automatically.
**Angular**
- [ ] spikerj/spikersoft-angular#627 — [Feature][Blog] "My posts" management view — surface drafts/pending/rejected in one place <sub>(was #708)</sub>
- [ ] spikerj/spikersoft-angular#628 — [Feature][Blog] Author edit UI — updateBlogPost exists server+service side, no surface calls it <sub>(was #709)</sub>
- [ ] spikerj/spikersoft-angular#629 — [Perf][Blog] List loads ALL posts and filters client-side — backend pagination discarded, no pagination UI <sub>(was #710)</sub>
- [ ] spikerj/spikersoft-angular#630 — [UX][Blog] Media grid hardcodes cols=3 — squashed tiles on mobile <sub>(was #711)</sub>
- [ ] spikerj/spikersoft-angular#631 — [UX][Blog] Create flow: setTimeout(1000) navigation + no unsaved-changes guard <sub>(was #712)</sub>
- [ ] spikerj/spikersoft-angular#632 — [UX][Blog] Small polish batch: moderation shield tooltip + theme-token colors in blog SCSS <sub>(was #713)</sub>
- [ ] spikerj/spikersoft-angular#633 — [Test][Blog][E2E] Blog has zero Playwright coverage — add an authenticated blog spec <sub>(was #714)</sub>
- [ ] spikerj/spikersoft-angular#634 — [TechDebt][Blog] Two base-URL sources — service uses API_BASE_URL token, media URLs use environment.baseUrl <sub>(was #715)</sub>
<sub>Checklist generated by the umbrella-tracker migration, 2026-08-07 — Opus 5 Agent</sub>
<!-- END MIGRATED-CHILDREN -->
Epic status roll-up — audited every child against origin/master. Owner-delete shipped; none of the eight UX children have started. Posting once here rather than eight near-identical comments.
#709 is another instance of the pattern this audit keeps hitting.libraries/domain/blog/src/lib/blog.service.ts:183 defines updateBlogPost(dto: UpdateBlogPostDto): Observable<BlogPost> — and git grep -n "updateBlogPost" origin/master -- '*.ts' returns exactly that one line. Server side and service side both exist; no surface calls it. That's the seventh confirmed case in this audit (alongside #593's ExtractChapters, #663's /quiz/{id}/review, #698's registry, #756's DLQ config, #847's Enabled flag, #785's SCSS class).
#715 has become better-documented rather than fixed, which is worth recording. libraries/features/blog/README.md:33 now names it explicitly as a "Code smell", notes it's "same shape as the domain → platform debt that drove Phase 4h's API_BASE_URL DI refactor", and prescribes the fix — add a MEDIA_BASE_URL token (or reuse API_BASE_URL) to @spikersoft/shared-api-config. So the analysis is done and written down; only the change is outstanding. The domain lib itself is clean (libraries/domain/blog/README.md:16-17 — zero boundary warnings since Phase 4h); it's BlogEntryComponent building media URLs from ${environment.baseUrl}${media.url} that remains.
#714 is the one I'd prioritise. Blog has zero Playwright coverage while this epic proposes changing the create flow (#712), the list (#710), the grid (#711) and adding an edit surface (#709). Landing those against no E2E coverage on a user-facing content surface is how #785 shipped green — its specs asserted on the component model while the template was never wired.
Epic scope check: the body describes owner-delete as delivered (backend #422/#423 + angular #420), and that's consistent with what I see. So this epic is one shipped slice plus eight untouched ones — worth deciding whether it stays a single epic or the UX batch gets re-scoped, since nothing has moved on it since 2026-07-19.
**Epic status roll-up** — audited every child against `origin/master`. **Owner-delete shipped; none of the eight UX children have started.** Posting once here rather than eight near-identical comments.
| Child | State | Evidence |
|---|---|---|
| #708 "My posts" management view | ❌ not started | zero `my-posts`/`myPosts` hits in the blog lib or `routes.ts` |
| #709 Author edit UI | ❌ not started | see below — **service method exists, no caller** |
| #710 Pagination UI | ❌ not started | zero `mat-paginator`/`MatPaginator` in `libraries/features/blog/**` |
| #711 Media grid mobile | ❌ not started | `blog-entry-component.html:189` still `cols="3"` |
| #712 Create-flow nav + guard | ❌ not started | `blog-create.ts:276` and `:326` still `setTimeout(() => this.router.navigate(["/blog"]), 1000)`; no `CanDeactivate` anywhere |
| #713 Polish batch | ❌ not started | no shield `matTooltip` found |
| #714 Blog E2E coverage | ❌ not started | **zero** blog spec files under `e2e/playwright/` |
| #715 Two base-URL sources | ❌ not started | still live — and now self-documented, see below |
**#709 is another instance of the pattern this audit keeps hitting.** `libraries/domain/blog/src/lib/blog.service.ts:183` defines `updateBlogPost(dto: UpdateBlogPostDto): Observable<BlogPost>` — and `git grep -n "updateBlogPost" origin/master -- '*.ts'` returns **exactly that one line**. Server side and service side both exist; no surface calls it. That's the seventh confirmed case in this audit (alongside #593's `ExtractChapters`, #663's `/quiz/{id}/review`, #698's registry, #756's DLQ config, #847's `Enabled` flag, #785's SCSS class).
**#715 has become better-documented rather than fixed**, which is worth recording. `libraries/features/blog/README.md:33` now names it explicitly as a **"Code smell"**, notes it's "same shape as the `domain → platform` debt that drove Phase 4h's `API_BASE_URL` DI refactor", and prescribes the fix — add a `MEDIA_BASE_URL` token (or reuse `API_BASE_URL`) to `@spikersoft/shared-api-config`. So the analysis is done and written down; only the change is outstanding. The domain lib itself is clean (`libraries/domain/blog/README.md:16-17` — zero boundary warnings since Phase 4h); it's `BlogEntryComponent` building media URLs from `${environment.baseUrl}${media.url}` that remains.
**#714 is the one I'd prioritise.** Blog has **zero** Playwright coverage while this epic proposes changing the create flow (#712), the list (#710), the grid (#711) and adding an edit surface (#709). Landing those against no E2E coverage on a user-facing content surface is how #785 shipped green — its specs asserted on the component model while the template was never wired.
**Epic scope check:** the body describes owner-delete as delivered (backend #422/#423 + angular #420), and that's consistent with what I see. So this epic is one shipped slice plus eight untouched ones — worth deciding whether it stays a single epic or the UX batch gets re-scoped, since nothing has moved on it since 2026-07-19.
spikerj
added the epic label 2026-08-07 13:43:02 +00:00
spikerj/spikersoft-angular#634 — [TechDebt][Blog] Two base-URL sources — service uses API_BASE_URL token, media URLs use environment.baseUrl
The unit is tracked by the shared [Blog UX] title prefix and by sibling
cross-links in each issue body. Closing here — the umbrella tracker is being
emptied.
— Opus 5 Agent
Dissolved into per-repo issues as part of the umbrella-tracker breakup.
This epic could never auto-close from a merge, because Gitea only resolves
`fixes #N` within a single repo. Its work now lives where the code is:
**Angular**
- spikerj/spikersoft-angular#627 — [Feature][Blog] "My posts" management view — surface drafts/pending/rejected in one place
- spikerj/spikersoft-angular#628 — [Feature][Blog] Author edit UI — updateBlogPost exists server+service side, no surface calls it
- spikerj/spikersoft-angular#629 — [Perf][Blog] List loads ALL posts and filters client-side — backend pagination discarded, no pagination UI
- spikerj/spikersoft-angular#630 — [UX][Blog] Media grid hardcodes cols=3 — squashed tiles on mobile
- spikerj/spikersoft-angular#631 — [UX][Blog] Create flow: setTimeout(1000) navigation + no unsaved-changes guard
- spikerj/spikersoft-angular#632 — [UX][Blog] Small polish batch: moderation shield tooltip + theme-token colors in blog SCSS
- spikerj/spikersoft-angular#633 — [Test][Blog][E2E] Blog has zero Playwright coverage — add an authenticated blog spec
- spikerj/spikersoft-angular#634 — [TechDebt][Blog] Two base-URL sources — service uses API_BASE_URL token, media URLs use environment.baseUrl
The unit is tracked by the shared `[Blog UX]` title prefix and by sibling
cross-links in each issue body. Closing here — the umbrella tracker is being
emptied.
— Opus 5 Agent
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.
Context
Joey requested a full-scale UI/UX + feature review of learn.spikersoft.com/blog (management surfaces, element positioning, enhancement opportunities). The review's headline gap — authors couldn't delete their own posts — is implemented outside this epic:
blogs/quarantinebucket objects, workflow docs with EXIF/GPS PII; moderation audit anonymized)[Authorize]+ AuthorId from Keycloaksub)Everything else found in the review becomes this epic's children, in rough priority order:
Children
(Each filed as its own ticket referencing this epic; numbers linked in comments below as they're filed.)
Review evidence base
Angular:
libraries/features/blog/**(list/entry/create components),libraries/domain/blog/**(service — full API surface incl. unusedgetMyPosts), routes (/blogpublic,/blog/createauth,/admin/blog-moderationadmin). Backend:BlogController(20 endpoints), 3 Mongo collections, 5-consumer media pipeline. Full traces in the child tickets.Child issues (per-repo, auto-close on merge)
This epic is complete when every box below is checked. Each child lives in the
repo that holds its fix, so
fixes #Nin a PR closes it automatically.Angular
Checklist generated by the umbrella-tracker migration, 2026-08-07 — Opus 5 Agent
Children filed (priority order):
getMyPostsunused)Implementation PRs for the headline feature (outside this epic's scope): backend #422 (retention purge), backend #423 (create provenance), angular #420 (owner-delete UI).
Epic status roll-up — audited every child against
origin/master. Owner-delete shipped; none of the eight UX children have started. Posting once here rather than eight near-identical comments.my-posts/myPostshits in the blog lib orroutes.tsmat-paginator/MatPaginatorinlibraries/features/blog/**blog-entry-component.html:189stillcols="3"blog-create.ts:276and:326stillsetTimeout(() => this.router.navigate(["/blog"]), 1000); noCanDeactivateanywherematTooltipfounde2e/playwright/#709 is another instance of the pattern this audit keeps hitting.
libraries/domain/blog/src/lib/blog.service.ts:183definesupdateBlogPost(dto: UpdateBlogPostDto): Observable<BlogPost>— andgit grep -n "updateBlogPost" origin/master -- '*.ts'returns exactly that one line. Server side and service side both exist; no surface calls it. That's the seventh confirmed case in this audit (alongside #593'sExtractChapters, #663's/quiz/{id}/review, #698's registry, #756's DLQ config, #847'sEnabledflag, #785's SCSS class).#715 has become better-documented rather than fixed, which is worth recording.
libraries/features/blog/README.md:33now names it explicitly as a "Code smell", notes it's "same shape as thedomain → platformdebt that drove Phase 4h'sAPI_BASE_URLDI refactor", and prescribes the fix — add aMEDIA_BASE_URLtoken (or reuseAPI_BASE_URL) to@spikersoft/shared-api-config. So the analysis is done and written down; only the change is outstanding. The domain lib itself is clean (libraries/domain/blog/README.md:16-17— zero boundary warnings since Phase 4h); it'sBlogEntryComponentbuilding media URLs from${environment.baseUrl}${media.url}that remains.#714 is the one I'd prioritise. Blog has zero Playwright coverage while this epic proposes changing the create flow (#712), the list (#710), the grid (#711) and adding an edit surface (#709). Landing those against no E2E coverage on a user-facing content surface is how #785 shipped green — its specs asserted on the component model while the template was never wired.
Epic scope check: the body describes owner-delete as delivered (backend #422/#423 + angular #420), and that's consistent with what I see. So this epic is one shipped slice plus eight untouched ones — worth deciding whether it stays a single epic or the UX batch gets re-scoped, since nothing has moved on it since 2026-07-19.
Dissolved into per-repo issues as part of the umbrella-tracker breakup.
This epic could never auto-close from a merge, because Gitea only resolves
fixes #Nwithin a single repo. Its work now lives where the code is:Angular
The unit is tracked by the shared
[Blog UX]title prefix and by siblingcross-links in each issue body. Closing here — the umbrella tracker is being
emptied.
— Opus 5 Agent