Browse the docs

Imported from laracms/docs/rag/COMMENT_MODERATION.mdEdit it in the module repository to change this page

CMS — comment moderation and approval capture

Purpose

CMS owns the comment domain: pending save capture, diff enrichment, publication after approval, and the moderation adapter registered on Core's ModerationAdapterRegistry.

CMS does not import AI config or jobs. Orchestration events are emitted by Core.

See also: Modules/Core/docs/rag/EVENT_ORCHESTRATION.md, Modules/AI/docs/rag/MODERATION_AND_SEARCH.md.

Capabilities

Concern Owner Artifact
Pending comment save CMS Comment + CommentApprovalCapture
Modification diff CMS CommentApprovalCapture::enrichDiff()
Emit moderation need Core ModificationRequiresModeration on modification create
LLM context + prompts CMS CommentModerationAdapter, CommentModerationPrompt
AI analysis + vote AI ApproveModificationJob (via registry)
Publish approved comment CMS Comment::applyModificationChanges()
Post-approve translate Core + AI ModificationApproved, fired by ModificationVoteService

InternalFlow

  1. User saves comment → CommentApprovalCapture::captureSave() creates active Modification with diff (body, locale, content_id, optional rating_score).
  2. Core saves modification → ModificationRequiresModeration (first save, wasRecentlyCreated).
  3. AI may run if ai.features.moderation.entities.cms_comments (declared by the AI module) and global moderation are enabled.
  4. Comment hidden from public queries until approved.
  5. Human approves in Filament → ModificationVoteService::cast() → Comment::applyModificationChanges() in the vote's transaction → public comment; the service fires ModificationApproved after the commit.

CommentApprovalCapture and Comment do not dispatch events; Core's emitter and ModificationVoteService handle that.

Only creations and updates of a comment go through moderation (Comment::approvalOperations()): its author deletes their own comment directly, and a comment's deletion never becomes a request. The author may also withdraw a pending comment request from Modifications before it is decided.

HowToUse — posting and moderating over the API

The application creates comments through the generic CRUD API: POST /app/crud/insert/cms/comments with content_id, body, and optionally parent_id (a reply) and rating_score (1-5). The author is the authenticated user unless user_id is given. The comment is validated before it is captured (Comment::getRules(): the content and the parent must exist, the text is required, the rating is 1-5), so an invalid comment answers 422 and never becomes a request. A valid one answers 202 with {modification, operation: "create"}: it is not visible until approved.

A moderator approves or rejects it with PATCH /app/crud/approve|disapprove/cms/comments and modification set to that id, with no id: a pending comment has no record yet. On approval the comment is created with its text and author and becomes visible.

HowToUse — CommentModerationAdapter

Path: Modules/CMS/app/Services/CommentModerationAdapter.php

Implements Modules\Core\Contracts\ModerationAdapter:

  • supports(): modifiable_type === Comment::class
  • build(): loads article context from content_id; when parent_id is in the modification diff, loads the parent comment body for thread context; returns ModerationRequest with CMS-owned prompts (CommentModerationPrompt)

CommentApprovalCapture::enrichDiff() adds parent_id to the modification when the comment is a reply.

Registration in CMSServiceProvider::boot():

$this->app->make(ModerationAdapterRegistry::class)
    ->register($this->app->make(CommentModerationAdapter::class));

Configuration

Setting Group Effect
ai.features.moderation.entities.cms_comments moderation Enables AI vote for comments (declared by the AI module)
auto_translate_comments translations Post-approve TranslateModelJob via ModificationApproved

Seeded via Core settings; cache flushed on Setting save (PerModelSettingResolver).

PermissionsAndSecurity

  • Pending comments: not visible in public listings until modification approved.
  • Comment deletions are never captured: the author deletes their own comment directly.
  • AI vote is additive; human approval still required per approvers_required.
  • Audit trail in approvals.meta / disapprovals.meta (AI module writes JSON).

ErrorsAndTroubleshooting

Symptom Check
Modification without modifiable_id on create Expected for pending comments; builder uses diff JSON
AI never runs for comments ai.features.moderation.entities.cms_comments, AI moderation enabled, builder registered
Comment stuck pending Human approval in Filament, modification active

FAQPrompts

  • How does CommentApprovalCapture work?
  • When is ModificationRequiresModeration fired for comments?
  • Where is CommentModerationContextBuilder registered?
  • Does CMS call AI directly?
  • What setting enables AI moderation for comments?
100%