Skip to main content

Moderation Service

Overview

The Moderation Service implements the complete content moderation pipeline for the platform, handling content removal, user warnings, suspensions, and bans. It integrates with the reporting system, audit trail, and email notification services to provide a comprehensive moderation workflow. Every moderation action is logged to a history table and triggers an email notification to the affected user.

Architecture

The Moderation Service operates as the central orchestrator for admin-initiated moderation actions. It coordinates between content repositories (items and comments), user profiles, moderation history logging, and email notifications. All actions require an admin user ID and a report ID for traceability.

Admin Dashboard / API Route
|
moderation.service.ts (orchestration)
|
+----------+----------+-----------+
| Comment | Item | Client |
| Queries | Repo | Profile |
+----------+----------+-----------+
| |
moderation.queries email-notification.service
|
Database (moderation_history, client_profiles, comments, items)

API Reference

Types

ModerationResult

Standard result type for all moderation operations.

interface ModerationResult {
success: boolean;
message: string;
error?: string; // Error code: 'NOT_FOUND', 'ALREADY_BANNED', 'INVALID_TYPE', etc.
}

ContentOwnerResult

Result of looking up the owner of reported content.

interface ContentOwnerResult {
success: boolean;
userId?: string;
error?: string;
}

Functions

getContentOwner(contentType: ReportContentTypeValues, contentId: string): Promise<ContentOwnerResult>

Resolves the owner (author) of reported content. For comments, it looks up the comment's userId. For items, it looks up the item's submitted_by field via the ItemRepository.

Parameters:

ParameterTypeDescription
contentTypeReportContentTypeValues'comment' or 'item'
contentIdstringID of the content

Returns: ContentOwnerResult -- Contains userId on success, or error on failure.


removeContent(contentType: ReportContentTypeValues, contentId: string, reportId: string, adminId: string): Promise<ModerationResult>

Removes reported content (deletes a comment or item) and logs the moderation action. Sends an email notification to the content owner.

Parameters:

ParameterTypeDescription
contentTypeReportContentTypeValues'comment' or 'item'
contentIdstringID of the content to remove
reportIdstringAssociated report ID for audit trail
adminIdstringAdmin user performing the action

Behavior by content type:

  • Comment: Soft-deletes the comment via deleteComment, logs to moderation history, sends content-removed email
  • Item: Deletes the item via ItemRepository.delete(), logs with item name and slug metadata, sends email

warnUser(userId: string, reason: string, reportId: string, adminId: string): Promise<ModerationResult>

Issues a warning to a user. Increments their warning count, logs the action, and sends a warning email.

Parameters:

ParameterTypeDescription
userIdstringClient profile ID of the user
reasonstringReason for the warning
reportIdstringAssociated report ID
adminIdstringAdmin performing the action

Guards:

  • Returns error if user not found
  • Returns error if user is already banned (cannot warn a banned user)

suspendUser(userId: string, reason: string, reportId: string, adminId: string): Promise<ModerationResult>

Suspends a user account. Updates the user's status to 'suspended', logs the action, and sends a suspension email.

Parameters: Same as warnUser.

Guards:

  • Returns error if user not found
  • Returns error if user is already suspended
  • Returns error if user is already banned

banUser(userId: string, reason: string, reportId: string, adminId: string): Promise<ModerationResult>

Permanently bans a user account. Updates the user's status to 'banned', logs the action, and sends a ban notification email.

Parameters: Same as warnUser.

Guards:

  • Returns error if user not found
  • Returns error if user is already banned

Implementation Details

  • Non-blocking emails: All email notifications are dispatched with .catch() handlers, meaning email failures are logged but never block the moderation action from completing.
  • Moderation history: Every action creates a record in the moderation_history table via createModerationHistory, providing a complete audit trail of all moderation decisions.
  • Escalation path: The service supports a natural escalation: warn -> suspend -> ban. Each level has guards preventing redundant actions (e.g., cannot warn a banned user).
  • Warning counter: warnUser calls incrementWarningCount which atomically increments the user's warning count and returns the new total, which is included in the moderation history and the email.
  • Content type polymorphism: removeContent handles both comments and items through the ReportContentType enum, using the appropriate repository/query for each type.

Database Interactions

OperationQuery FunctionTable
Get commentgetCommentById(id)comments
Delete commentdeleteComment(id)comments
Get itemItemRepository.findById(id)items (YAML/Git)
Delete itemItemRepository.delete(id)items (YAML/Git)
Get user profilegetClientProfileById(id)client_profiles
Increment warningsincrementWarningCount(userId)client_profiles
Suspend usersuspendUserQuery(userId)client_profiles
Ban userbanUserQuery(userId)client_profiles
Log actioncreateModerationHistory(data)moderation_history

Error Handling

  • All functions return ModerationResult with structured error codes (NOT_FOUND, ALREADY_BANNED, ALREADY_SUSPENDED, INVALID_TYPE, UNKNOWN_ERROR).
  • Errors are caught at the top level of each function, logged to console, and returned as failure results.
  • Email sending failures are caught independently and do not affect the moderation result.
  • The getContentOwner helper catches errors and returns a failure result rather than throwing.

Usage Examples

import {
removeContent,
warnUser,
suspendUser,
banUser,
getContentOwner,
} from '@/lib/services/moderation.service';

// Remove a reported comment
const result = await removeContent('comment', commentId, reportId, adminId);
if (result.success) {
console.log(result.message); // "Comment removed successfully"
}

// Warn a user
const warnResult = await warnUser(userId, 'Inappropriate language', reportId, adminId);
// => { success: true, message: "User warned successfully. Total warnings: 2" }

// Suspend a user after repeated violations
const suspendResult = await suspendUser(userId, 'Repeated violations', reportId, adminId);

// Ban a user
const banResult = await banUser(userId, 'Severe violation of terms', reportId, adminId);

// Look up who owns the reported content
const owner = await getContentOwner('item', itemId);
if (owner.success) {
console.log('Content owner:', owner.userId);
}

Configuration

This service has no direct environment variable dependencies. Email sending depends on the EmailNotificationService being properly configured (SMTP/provider credentials).