Skip to main content

Reports Endpoints

The reports system allows authenticated users to flag inappropriate content and provides administrators with tools to review, moderate, and resolve reports. Reports support content types including items and comments, with built-in duplicate prevention.

Overview

EndpointMethodAuthDescription
/api/reportsPOSTUserSubmit a content report
/api/admin/reportsGETAdminList reports with filtering
/api/admin/reports/statsGETAdminGet report statistics
/api/admin/reports/[id]GETAdminGet a single report
/api/admin/reports/[id]PUTAdminUpdate report status and resolution

Public Endpoints

Submit a Report

POST /api/reports

Authenticated users can report items or comments for inappropriate content. Each user can only report the same content once (duplicate prevention via hasUserReportedContent check). Blocked users (suspended or banned) are prevented from submitting reports.

Authentication: Required (session-based)

Request Body:

{
"contentType": "item",
"contentId": "awesome-productivity-tool",
"reason": "spam",
"details": "This tool is promoting malicious software"
}
FieldTypeRequiredDescription
contentTypestringYesType of content: "item" or "comment"
contentIdstringYesID or slug of the content being reported
reasonstringYesOne of: "spam", "harassment", "inappropriate", "other"
detailsstringNoAdditional context about the report

Success Response (200):

{
"success": true,
"message": "Report submitted successfully",
"report": {
"id": "rpt_abc123",
"contentType": "item",
"contentId": "awesome-productivity-tool",
"reason": "spam",
"status": "pending",
"createdAt": "2024-01-20T10:30:00.000Z"
}
}

Error Responses:

StatusCondition
400Invalid content type, missing content ID, or invalid reason
401User not authenticated
403Client profile required, or user is suspended/banned
404Client profile not found
409User has already reported this content
500Internal server error

Source: template/app/api/reports/route.ts

Admin Endpoints

All admin endpoints require session.user.isAdmin to be true.

List Reports

GET /api/admin/reports

Returns a paginated list of content reports with reporter information. Supports filtering by status, content type, and reason, plus text search across content ID, details, and reporter name/email.

Query Parameters:

ParameterTypeDefaultDescription
pageinteger1Page number (minimum 1)
limitinteger10Results per page (1-100)
searchstring-Search across content ID, details, reporter name/email
statusstring-Filter: "pending", "reviewed", "resolved", "dismissed"
contentTypestring-Filter: "item", "comment"
reasonstring-Filter: "spam", "harassment", "inappropriate", "other"

Success Response (200):

{
"success": true,
"data": {
"reports": [
{
"id": "rpt_abc123",
"contentType": "item",
"contentId": "some-item-slug",
"reason": "spam",
"status": "pending",
"details": "Suspicious content",
"reportedBy": "client_456",
"createdAt": "2024-01-20T10:30:00.000Z"
}
],
"pagination": {
"total": 42,
"page": 1,
"limit": 10,
"totalPages": 5
}
}
}

Source: template/app/api/admin/reports/route.ts

Get Report Statistics

GET /api/admin/reports/stats

Returns aggregate statistics about reports including counts by status, content type, and reason.

Success Response (200):

{
"success": true,
"data": {
"total": 156,
"pendingCount": 23,
"resolvedCount": 120,
"byStatus": {
"pending": 23,
"reviewed": 10,
"resolved": 120,
"dismissed": 3
},
"byContentType": {
"item": 100,
"comment": 56
},
"byReason": {
"spam": 80,
"inappropriate": 45,
"harassment": 20,
"other": 11
}
}
}

Source: template/app/api/admin/reports/stats/route.ts

Get Report by ID

GET /api/admin/reports/[id]

Retrieves a single report with full details including reporter and reviewer information.

Path Parameters:

ParameterTypeDescription
idstringReport ID

Success Response (200):

{
"success": true,
"data": {
"id": "rpt_abc123",
"contentType": "item",
"contentId": "some-item-slug",
"reason": "spam",
"status": "reviewed",
"details": "Suspicious content",
"reportedBy": "client_456",
"reviewedBy": "admin_789",
"reviewNote": "Confirmed as spam",
"resolution": "content_removed",
"createdAt": "2024-01-20T10:30:00.000Z",
"updatedAt": "2024-01-21T09:00:00.000Z"
}
}
StatusCondition
403Not an admin
404Report not found

Source: template/app/api/admin/reports/[id]/route.ts

Update Report

PUT /api/admin/reports/[id]

Updates a report's status, resolution, and review note. When a resolution is set, the system automatically executes the corresponding moderation action (content removal, user warning, suspension, or ban).

Request Body:

{
"status": "resolved",
"resolution": "content_removed",
"reviewNote": "Confirmed spam content, removed from listing"
}
FieldTypeRequiredDescription
statusstringNo"pending", "reviewed", "resolved", "dismissed"
resolutionstringNo"content_removed", "user_warned", "user_suspended", "user_banned", "no_action"
reviewNotestringNoAdmin notes about the review

Moderation Actions by Resolution:

The following automated actions are triggered based on the resolution value:

ResolutionAction
content_removedCalls removeContent() to remove the reported item or comment
user_warnedCalls warnUser() to issue a warning to the content owner
user_suspendedCalls suspendUser() to suspend the content owner's account
user_bannedCalls banUser() to permanently ban the content owner
no_actionNo moderation action is taken

Success Response (200):

{
"success": true,
"message": "Report updated successfully",
"data": {
"id": "rpt_abc123",
"status": "resolved",
"resolution": "content_removed",
"reviewNote": "Confirmed spam content"
},
"moderationResult": {
"success": true,
"message": "Content removed successfully"
}
}
StatusCondition
400Invalid status or resolution value; content owner not found for user-level actions
403Not an admin
404Report not found

Source: template/app/api/admin/reports/[id]/route.ts

Data Model

Reports use the following enums defined in lib/db/schema:

  • ReportContentType: "item", "comment"
  • ReportReason: "spam", "harassment", "inappropriate", "other"
  • ReportStatus: "pending", "reviewed", "resolved", "dismissed"
  • ReportResolution: "content_removed", "user_warned", "user_suspended", "user_banned", "no_action"

Integration with Moderation

When a report is resolved with a user-level resolution (user_warned, user_suspended, user_banned), the system:

  1. Looks up the content owner via getContentOwner()
  2. Executes the appropriate moderation function from lib/services/moderation.service
  3. Uses the reviewNote as the reason for the moderation action
  4. Records the admin's ID as the reviewer

If the moderation action fails, the report update still succeeds but the failure is logged. The moderationResult field in the response indicates whether the action succeeded.