Parent Epic: #536
Depends on: #537, #538, #539
Objective
Add revision history, revision restore, scheduled publishing script, audit events, and AsyncAPI blog domain events.
Context
This issue improves editorial workflow safety. It must preserve append-only revision history, make scheduled publishing idempotent, and emit meaningful audit/domain events without calling external providers inside database transactions.
Scope
- Create revision on significant post/page changes
- List revisions
- Read revision detail
- Restore revision
- Add scheduled publishing Bun script
- Add package script for scheduled publishing
- Add AsyncAPI events
- Ensure scheduled publishing is idempotent
Out of Scope
- Admin UI screens
- Public route rendering
- Template/widget/menu/ads implementation
- External scheduler/provider integration
Routes
GET /api/v1/blog/posts/{id}/revisions
GET /api/v1/blog/posts/{id}/revisions/{revisionId}
POST /api/v1/blog/posts/{id}/revisions/{revisionId}/restore
Script
scripts/blog-scheduled-publish.ts
Package script:
"blog:publish:scheduled": "bun scripts/blog-scheduled-publish.ts"
Revision Rules
- Revision is created when post/page content changes significantly.
- Revisions are append-only.
- Revision restore creates a new revision.
- Revision restore requires explicit permission.
- Revision restore requires
Idempotency-Key.
- Normal endpoints must not overwrite or delete existing revision history.
Scheduled Publishing Rules
- Finds due scheduled posts per tenant.
- Publishes only posts with
status = 'scheduled' and scheduled_at <= now().
- Sets
status = 'published'.
- Sets
published_at = now() only if not already set.
- Ignores future scheduled posts.
- Ignores already published posts.
- Must be idempotent.
- Must write audit events.
- Must emit domain event if event outbox is used.
- Must not call external providers inside DB transaction.
Permission Mapping
GET revisions -> blog_content.revisions.read
POST revision restore -> blog_content.revisions.restore
Scheduled publish job -> existing trusted runtime/job execution pattern
Audit Requirements
Record audit events for:
blog.post.revision_restored
blog.post.scheduled_publish_executed
blog.post.scheduled_publish_skipped
Also reuse existing events from post lifecycle where applicable:
blog.post.published
blog.post.updated
AsyncAPI Events
Add meaningful events using existing DomainEvent schema pattern:
awcms-mini.blog-content.post.created
awcms-mini.blog-content.post.updated
awcms-mini.blog-content.post.submitted-for-review
awcms-mini.blog-content.post.published
awcms-mini.blog-content.post.scheduled
awcms-mini.blog-content.post.archived
awcms-mini.blog-content.post.deleted
awcms-mini.blog-content.post.restored
awcms-mini.blog-content.post.purged
awcms-mini.blog-content.revision.created
awcms-mini.blog-content.term.created
awcms-mini.blog-content.term.updated
awcms-mini.blog-content.settings.updated
Acceptance Criteria
Validation Commands
bun run db:migrate
bun run api:spec:check
bun run test
bun run typecheck
bun run blog:publish:scheduled
Parent Epic: #536
Depends on: #537, #538, #539
Objective
Add revision history, revision restore, scheduled publishing script, audit events, and AsyncAPI blog domain events.
Context
This issue improves editorial workflow safety. It must preserve append-only revision history, make scheduled publishing idempotent, and emit meaningful audit/domain events without calling external providers inside database transactions.
Scope
Out of Scope
Routes
GET /api/v1/blog/posts/{id}/revisions GET /api/v1/blog/posts/{id}/revisions/{revisionId} POST /api/v1/blog/posts/{id}/revisions/{revisionId}/restoreScript
Package script:
Revision Rules
Idempotency-Key.Scheduled Publishing Rules
status = 'scheduled'andscheduled_at <= now().status = 'published'.published_at = now()only if not already set.Permission Mapping
Audit Requirements
Record audit events for:
Also reuse existing events from post lifecycle where applicable:
AsyncAPI Events
Add meaningful events using existing DomainEvent schema pattern:
Acceptance Criteria
Idempotency-Key.Validation Commands
bun run db:migrate bun run api:spec:check bun run test bun run typecheck bun run blog:publish:scheduled