Blog Module Feature List
Blog feature surfaces, slug lifecycle, cache behavior, and mobile composition.
Blog Module - Feature List
1. Feature Overview
Blog module supports admin authoring and public consumption:
- Admin post lifecycle: create, update, delete, publish, unpublish
- Admin category lifecycle: create, update, delete with safety checks
- Product linking per post (
blog_post_product) - FAQ block per post (
blog_post_faq) - CTA block per post (
blog_cta_block) - Video block per post (
blog_post_video) with per-video SEO metadata linkage - Public listing/detail/category APIs
- Slug-history fallback for old blog URLs
- Redis-backed cache on public reads with admin mutation invalidation
2. Route Ownership and Surfaces
| Surface | Route prefix | Owner |
|---|---|---|
| Admin posts | /api/admin/blog/posts | BlogPostAdminController |
| Admin categories | /api/admin/blog/categories | BlogCategoryAdminController |
| Public blog | /api/blogs | BlogCustomerController |
| Mobile-composed public blog | /api/mobile/blogs | MobileModule composition of BlogCustomerModule |
Swagger tags:
Blog Posts (Admin)Blog (Admin)Blog
3. Admin Feature Matrix
| Capability | Endpoint | AuthZ |
|---|---|---|
| List posts (paginated + filters) | GET /api/admin/blog/posts | Blog_READ |
| Get post detail | GET /api/admin/blog/posts/:id | Blog_READ |
| Create post | POST /api/admin/blog/posts | Blog_CREATE |
| Update post | PUT /api/admin/blog/posts/:id | Blog_UPDATE |
| Delete post | DELETE /api/admin/blog/posts/:id | Blog_DELETE |
| Publish post | POST /api/admin/blog/posts/:id/publish | Blog_UPDATE |
| Unpublish post | POST /api/admin/blog/posts/:id/unpublish | Blog_UPDATE |
| List categories | GET /api/admin/blog/categories | Blog_READ |
| Get category | GET /api/admin/blog/categories/:id | Blog_READ |
| Create category | POST /api/admin/blog/categories | Blog_CREATE |
| Update category | PUT /api/admin/blog/categories/:id | Blog_UPDATE |
| Delete category | DELETE /api/admin/blog/categories/:id | Blog_DELETE |
4. Public/Mobile Feature Matrix
| Capability | Endpoint | Runtime mode |
|---|---|---|
| List published posts | GET /api/blogs | Synchronous read + Redis cache |
| Category list with published count | GET /api/blogs/categories | Synchronous read + Redis cache |
| Published post by slug | GET /api/blogs/:slug | Synchronous read + Redis cache |
Equivalent mobile endpoints:
GET /api/mobile/blogsGET /api/mobile/blogs/categoriesGET /api/mobile/blogs/:slug
5. Key Business Rules
- Public APIs return published posts only.
- Slug fallback is allowed only when target post is currently published.
- Category delete is blocked if any blog post references the category.
- Product linking from admin accepts published products only.
- FAQ/CTA are modeled as write-replace payloads on create/update.
- Videos are modeled as write-replace payloads on create/update.
- Each video requires a valid
seoId; eachseoIdcan be linked to only one blog video globally. - Post search and category search use trigram-style behavior (
ILIKE+similarity).
6. Slug Lifecycle
6.1 Admin slug generation
- Normalize input to URL-safe base slug.
- Check uniqueness against:
- current post slugs (
blog_post.slug) - historical slugs (
blog_slug_history.old_slug)
- current post slugs (
- Collision strategy:
slug,slug-1,slug-2, … up to max attempts, then timestamp fallback.
6.2 Slug history fallback (public)
GET /blogs/:slug resolution order:
- Direct hit in
blog_post.slugwithstatus='published' - Fallback hit in
blog_slug_history.old_slugjoined toblog_postwithstatus='published'
No redirect is emitted. Response always represents the current canonical post record.
7. Structured Data Surface
Public detail returns server-built structured-data payload:
ArticleArticle.videoasVideoObject[]when post videos existFAQPage(only when FAQ rows exist)BreadcrumbList
This is returned in API response so frontend can render JSON-LD script tags deterministically.
8. Cache Strategy
Public keyspaces:
blog:posts:list:*blog:post:slug:*blog:categories:*
Invalidation behavior:
- Admin post mutations invalidate
blog:* - Admin category mutations invalidate
blog:*
9. Rate Limiting
Admin blog endpoints use existing IP throttle guard with per-route policy:
- Reads: 30/min
- Writes: 10/min
Public blog endpoints are cache-backed and unauthenticated (@Public()), following existing shared public-module behavior.
10. Error UX Mapping
| errorCode | Typical HTTP | UX action |
|---|---|---|
BLOG_POST_NOT_FOUND | 404 | Show not-found state and back-to-blog CTA |
BLOG_CATEGORY_NOT_FOUND | 404 | Refresh category state in admin and retry |
BLOG_CATEGORY_NOT_EMPTY | 409 | Block delete with message to reassign/remove posts first |
BLOG_CATEGORY_SLUG_ALREADY_EXISTS | 409 | Prompt user to edit category name/slug |
BLOG_POST_INVALID_STATUS_TRANSITION | 400 | Disable/guard publish toggle by current state |
PRODUCT_NOT_FOUND (during link update) | 400 | Show invalid linked-product selection message |
11. Release/QA Checklist
- Public list returns only published posts and correct pagination envelope.
- Public slug endpoint resolves both current and historical slugs.
- Historical slug fallback does not leak drafts.
- Category post counts reflect published-only rows.
- Admin post update persists product links in deterministic order.
- Admin FAQ/CTA create-update-delete flows persist correctly.
- Admin video create-update-delete flows persist correctly.
- Invalid/missing video
seoIdis rejected. - Reusing a video
seoIdalready linked to another post is rejected. -
blog:*invalidation runs on all admin mutations. - Mobile-composed routes (
/api/mobile/blogs/...) resolve correctly.
12. Integration Flows
12.1 Public Read Flow
- Client requests
GET /api/blogs(or/api/mobile/blogs). - Service computes deterministic cache key from query.
- On cache miss, DB query fetches published posts + category info.
- Response wrapped in
ResponseDtowith pagination metadata.
12.2 Slug Fallback Flow
- Client requests
GET /api/blogs/:slug. - Service attempts direct published-slug lookup.
- If no direct hit, service checks slug-history join with published status guard.
- If found, returns canonical current post payload; else
BLOG_POST_NOT_FOUND.
12.3 Admin Mutation Flow
- Admin calls create/update/delete/publish/unpublish.
- Service applies transactional writes (post + relations).
- Service writes activity record where applicable.
- Service invalidates
blog:*public cache namespace.
Time fields in this module should be handled as ISO-8601 instants by clients.
See Also
- Backend Reference: Blog - Backend Documentation
- API Contracts: Blog - API & Integration Guide