Skip to content
This repository was archived by the owner on Aug 11, 2026. It is now read-only.
This repository was archived by the owner on Aug 11, 2026. It is now read-only.

Issue 3: Implement Pages, Taxonomies, and PostgreSQL Search #539

Description

@ahliweb

Parent Epic: #536
Depends on: #537, #538

Objective

Add static page management, category/tag management, post-term assignment, and PostgreSQL full-text search for admin and public-safe content discovery.

Context

This issue extends the core blog_content module beyond posts. It must follow the same auth, tenant, RBAC/ABAC, audit, idempotency, RLS, and standard response patterns introduced in the blog post API.

Scope

  • Page CRUD
  • Category management
  • Tag management
  • Post-term relation handling
  • PostgreSQL full-text search for posts and pages
  • Admin search with permission enforcement
  • Public-safe search helper

Out of Scope

  • Public route rendering
  • RSS and sitemap generation
  • Admin UI
  • Revisions and scheduled publishing
  • Template/widget/menu/ads implementation

Routes

GET    /api/v1/blog/pages
POST   /api/v1/blog/pages
GET    /api/v1/blog/pages/{id}
PATCH  /api/v1/blog/pages/{id}
DELETE /api/v1/blog/pages/{id}

GET    /api/v1/blog/terms
POST   /api/v1/blog/terms
PATCH  /api/v1/blog/terms/{id}
DELETE /api/v1/blog/terms/{id}

GET    /api/v1/blog/search

Permission Mapping

GET pages list/detail        -> blog_content.pages.read
POST pages create            -> blog_content.pages.create
PATCH pages update           -> blog_content.pages.update
DELETE pages soft-delete     -> blog_content.pages.delete
GET terms                    -> blog_content.taxonomies.read
POST/PATCH/DELETE terms      -> blog_content.taxonomies.configure
GET admin search             -> blog_content.search.read

Data Rules

Pages

  • Pages follow the same core lifecycle model as posts.
  • Pages support page_type:
    • standard
    • landing
    • legal
    • system
  • Pages support parent-child structure through parent_page_id.
  • Pages support menu_order.

Categories and Tags

  • Categories support parent-child hierarchy.
  • Tags must reject parent_id.
  • Terms are unique by tenant, taxonomy type, and slug where not deleted.
  • Post-term relation must include tenant_id and be protected by RLS.

Search

  • Use PostgreSQL full-text search.
  • Search must be tenant-scoped.
  • Use tenant-prefixed indexes.
  • Use bounded or keyset pagination.
  • Admin search may include draft/review/scheduled/published/archived content according to permission.
  • Public-safe helper must only return content allowed by the public visibility predicate.

Public Visibility Predicate for Public-Safe Search

status = 'published'
AND visibility = 'public'
AND deleted_at IS NULL
AND published_at IS NOT NULL
AND published_at <= now()

Acceptance Criteria

  • Page CRUD works with the same auth, tenant, RBAC/ABAC, audit, and RLS pattern as posts.
  • Categories support parent-child hierarchy.
  • Tags reject parent_id.
  • Terms are unique by tenant, taxonomy type, and slug where not deleted.
  • Post-term relation is tenant-scoped.
  • Search vector is maintained for posts and pages.
  • Admin search respects tenant and permissions.
  • Public-safe search only returns published public content.
  • Search uses PostgreSQL full-text search.
  • Search uses bounded or keyset pagination.
  • OpenAPI is updated.
  • Tests cover page CRUD.
  • Tests cover taxonomy rules.
  • Tests cover search visibility.
  • Tests cover RLS tenant isolation.
  • Tests cover ABAC allow/deny behavior.

Validation Commands

bun run db:migrate
bun run api:spec:check
bun run test
bun run typecheck

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions