BTST
PluginsQuickstartDocs
Live Blog

From research to product evaluation

Evaluating a publishing workflow for an app you already own?

See what the BTST Blog plugin adds to an existing React or Next.js app
BTST

Open-source TypeScript features for the React application, data, and deployment you already own.

Released plugins

  • Blog
  • AI Chat
  • CMS
  • Form Builder
  • UI Builder
  • Kanban
  • Comments
  • Media
  • Route Docs
  • OpenAPI
  • Better Auth UI

Resources

  • Quickstart
  • Documentation
  • All plugins
  • Live Blog
  • GitHub (opens in a new tab)
© 2026 BTST. Open source under the MIT License.
AI Chat
September 11, 2026ReactComments

React Comments: Design Moderation and Permissions Before Launch

Define thread identity, pending-comment visibility, and separate reader, author, and moderator permissions for an existing React app.

React Comments: Design Moderation and Permissions Before Launch

A comments feature needs separate decisions about who can read a thread, who can post, and who can approve a comment. Adding a React component handles the visible interaction; the server must enforce those decisions for every request.

Take a public article with comments from signed-in readers. Anonymous visitors can see approved comments. Authors can see feedback about their own pending comments. Moderators can review the pending queue. These are three different views of the same discussion, not one list with buttons hidden by CSS.

Identify the resource behind the thread#

A comment needs a stable association with the thing being discussed. In BTST Comments 3.0.0, a thread uses resourceType and resourceId. For an article, use its persistent record ID and an application-defined type such as article. A title or mutable URL slug is a poor identifier if renaming it would detach the conversation.

The pair identifies a thread; it does not establish access. Before allowing a read or new comment, your server policy must decide whether the referenced article exists and whether that visitor may use its discussion. This matters even more when the same comments system serves public articles and private project pages.

Keep those choices in the shared backend policy so your Next.js, TanStack Start, or React Router page and direct API requests get the same answer. The Comments integration guide covers the component and backend setup.

Define a policy for each operation#

Here is a starting policy for a moderated public blog. It is an application policy, not a claim about defaults:

OperationAnonymous visitorSigned-in authorModerator
Read approved comments on a public articleAllowAllowAllow
Post a new commentDenyAllow on an eligible articleAllow
Read the moderation queueDenyDenyAllow
Edit someone else's commentDenyDenyDecide explicitly
Approve or mark spamDenyDenyAllow

BTST separates thread reads, comment creation, editing, deletion, reactions, and moderation into permission descriptors. Thread reads distinguish public, own-history, and moderation scopes. Its released permission definitions show the available server facts.

Implement the chosen policy through BTST authorization and attach its server adapter to the backend stack. Authorization is opt-in in 3.0.0; adding the Comments plugin alone does not activate these rules. Derive the current user and roles from your server's authenticated identity. A browser-supplied author ID or moderator flag is not evidence of permission.

Make pending status understandable#

BTST supports pending, approved, and spam comment states. Its creation workflow uses the backend's autoApprove option to choose whether a new comment starts approved or pending. Choose this option deliberately and test the result with an ordinary reader account.

When approval is required, show the author that their comment was received and is awaiting review. Do not make it look as though a successful submission disappeared. At the same time, the public thread and count must not reveal comments that the viewer cannot read.

Replies need the same care. A pending reply should not become publicly visible merely because its parent is approved. An author seeing their own pending reply is a different observation from a logged-out visitor seeing it.

Verify using separate identities#

In a development database, use an anonymous session, reader A, reader B, and a moderator. Reader A posts a comment. Confirm its status, the author's feedback, the public list, and the displayed count. Approve it as the moderator and repeat the checks.

Then try editing A's comment as B by calling the API directly. Try changing moderation status as A. Try posting a reply against a parent from another resource. These requests exercise boundaries that a normal click-through cannot prove.

For private resources, repeat the read and create checks using a signed-in person who lacks access to that resource. Being authenticated should not grant access to every discussion. Also verify any server-rendered initial data: a correctly protected API does not undo private comments already embedded in page HTML.

Decide what happens after moderation#

If your app sends notifications, trigger them from the appropriate authorized lifecycle event and account for retries. Decide whether authors hear about receipt, approval, or replies. Avoid promising immediate delivery or realtime updates unless you have implemented and verified them.

Start with the Comments plugin overview to inspect the supplied threads, replies, moderation, and persistence. The useful first milestone is one complete discussion with correct visibility for each role, including requests made outside the UI.

In This Post

Identify the resource behind the threadDefine a policy for each operationMake pending status understandableVerify using separate identitiesDecide what happens after moderation