# How the Prompt Reporting System Handles Spam, Inappropriate Content, and Copyright Violations in prompts.chat

> Learn how prompts.chat handles spam inappropriate content and copyright violations with its robust reporting system featuring UI API and admin management.

- Repository: [Fatih Kadir Akın/prompts.chat](https://github.com/f/prompts.chat)
- Tags: security
- Published: 2026-04-02

---

**The prompts.chat reporting system allows authenticated users to flag content for spam, inappropriate material, or copyright violations through a three-layer architecture consisting of a React dialog UI, a Next.js API route with validation logic, and an admin interface for status management.**

The **f/prompts.chat** repository implements a comprehensive content moderation workflow that empowers users to report problematic prompts while preventing abuse through strict business rules. This system captures six distinct report categories—including spam, copyright infringement, and misleading content—and routes them through a structured review pipeline. All report data persists in a dedicated Prisma model with indexed relationships to both users and prompts.

## Three-Layer Architecture Overview

The reporting workflow splits responsibilities across distinct application layers to maintain separation of concerns and security boundaries.

**UI Layer**: The `ReportPromptDialog` component in [`src/components/prompts/report-prompt-dialog.tsx`](https://github.com/f/prompts.chat/blob/main/src/components/prompts/report-prompt-dialog.tsx) renders a modal interface for selecting report reasons and submitting details.

**API Layer**: The [`src/app/api/reports/route.ts`](https://github.com/f/prompts.chat/blob/main/src/app/api/reports/route.ts) endpoint enforces authentication, validates input against Zod schemas, and applies business rules such as self-reporting prevention and duplicate detection.

**Admin Layer**: The `src/app/api/admin/reports/[id]/route.ts` endpoint restricts status updates to users with the `ADMIN` role, allowing transitions between `PENDING`, `REVIEWED`, and `DISMISSED` states.

## Database Schema and Enums

The reporting functionality centers on the **PromptReport** model defined in `prisma/schema.prisma`. This schema establishes foreign key relationships to both the `Prompt` and `User` models with cascading deletion rules.

```prisma
model PromptReport {
  id         String       @id @default(cuid())
  reason     ReportReason
  details    String?
  status     ReportStatus @default(PENDING)
  createdAt  DateTime     @default(now())
  updatedAt  DateTime     @updatedAt
  promptId   String
  reporterId String

  prompt   Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
  reporter User   @relation(fields: [reporterId], references: [id], onDelete: Cascade)

  @@index([promptId])
  @@index([reporterId])
  @@index([status])
  @@map("prompt_reports")
}

```

The system classifies reports using two dedicated enums. **ReportReason** supports six categories: `SPAM`, `INAPPROPRIATE`, `COPYRIGHT`, `MISLEADING`, `RELIST_REQUEST`, and `OTHER`. **ReportStatus** tracks the review lifecycle through `PENDING`, `REVIEWED`, and `DISMISSED` values.

## User Interface Implementation

The `ReportPromptDialog` component operates as a client-side React component (`"use client"`) that encapsulates the reporting experience. It renders a flag icon button that triggers a modal containing a reason selector and optional details textarea.

Upon submission, the component sends a POST request to `/api/reports` with the `promptId`, selected `reason`, and optional `details`. The implementation fires an analytics event via `analyticsPrompt.report(promptId, reason)` to track moderation metrics. The component also handles loading states and displays success or error toast notifications based on the API response.

## API Validation and Business Rules

The [`src/app/api/reports/route.ts`](https://github.com/f/prompts.chat/blob/main/src/app/api/reports/route.ts) endpoint implements a strict validation pipeline to prevent abuse and ensure data integrity.

**Authentication**: The handler requires a valid session from `auth()` and returns **401 Unauthorized** for unauthenticated requests.

**Input Validation**: A Zod schema ensures the `promptId` is a non-empty string and the `reason` matches one of the defined enum values, returning **400 Bad Request** for malformed input.

**Existence Check**: The system verifies the target prompt exists via `db.prompt.findUnique` before accepting the report, returning **404 Not Found** for invalid prompt IDs.

**Self-Reporting Protection**: The endpoint rejects reports where the reporter's ID matches the prompt's `authorId`, unless the reason is `RELIST_REQUEST`, preventing users from flagging their own content inappropriately.

**Duplicate Prevention**: The system queries for existing `PENDING` reports from the same user for the same prompt, returning **400 Bad Request** if a duplicate exists to prevent report spamming.

After passing all checks, the endpoint creates a new `PromptReport` record and returns `{ success: true }`.

## Admin Report Management

Administrators manage report queues through the `src/app/api/admin/reports/[id]/route.ts` endpoint. This route accepts PATCH requests exclusively from users with the `ADMIN` role to update the `status` field of existing reports.

The endpoint validates that the incoming status value conforms to the `ReportStatus` enum before persisting changes, ensuring the review workflow progresses from `PENDING` to either `REVIEWED` or `DISMISSED` states.

## Implementation Examples

### Embedding the Report Dialog

Integrate the reporting functionality into any prompt display using the `ReportPromptDialog` component:

```tsx
import { ReportPromptDialog } from "@/components/prompts/report-prompt-dialog";

export function PromptActions({ promptId, isLoggedIn }) {
  return (
    <div className="flex space-x-2">
      <ReportPromptDialog promptId={promptId} isLoggedIn={isLoggedIn} />
    </div>
  );
}

```

### Programmatic API Access

Submit reports programmatically using standard fetch calls with session credentials:

```typescript
async function reportPrompt(promptId: string, reason: string, details?: string) {
  const res = await fetch("https://your-instance.com/api/reports", {
    method: "POST",
    credentials: "include",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ promptId, reason, details }),
  });

  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? "Report failed");
  return data;
}

// Usage example
reportPrompt("abc123", "COPYRIGHT", "Contains proprietary code without license")
  .then(() => console.log("Copyright violation reported"))
  .catch(console.error);

```

### Admin Status Updates

Administrators can resolve reports by updating their status through the administrative API:

```typescript
async function updateReportStatus(reportId: string, status: "REVIEWED" | "DISMISSED") {
  const res = await fetch(`/api/admin/reports/${reportId}`, {
    method: "PATCH",
    credentials: "include",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ status }),
  });

  if (!res.ok) {
    const err = await res.json();
    throw new Error(err.error ?? "Failed to update");
  }
  return await res.json();
}

```

## Summary

- The reporting system in **f/prompts.chat** uses a three-tier architecture separating UI components, API validation, and admin controls.
- **Six report categories** cover spam, inappropriate content, copyright violations, misleading information, relist requests, and other issues.
- **Business rules** prevent self-reporting (except for relist requests) and block duplicate pending reports from the same user.
- **Database indexing** on `promptId`, `reporterId`, and `status` fields ensures efficient query performance for moderation queues.
- **Role-based access control** restricts report status modifications to users with the `ADMIN` role.

## Frequently Asked Questions

### What report reasons are available in the prompts.chat system?

The system supports six distinct report reasons defined in the `ReportReason` enum: `SPAM` for unsolicited promotional content, `INAPPROPRIATE` for content violating community standards, `COPYRIGHT` for intellectual property violations, `MISLEADING` for deceptive or inaccurate prompts, `RELIST_REQUEST` for authors requesting content republication, and `OTHER` for edge cases not covered by standard categories.

### How does the system prevent users from spamming the report feature?

The API endpoint in [`src/app/api/reports/route.ts`](https://github.com/f/prompts.chat/blob/main/src/app/api/reports/route.ts) enforces a duplicate check that queries for existing `PENDING` reports from the same user targeting the same prompt. If such a record exists, the endpoint returns **400 Bad Request**, preventing users from flooding the moderation queue with duplicate reports while allowing new reports after existing ones are reviewed or dismissed.

### Can users report their own prompts in prompts.chat?

The system generally prohibits self-reporting through a specific business rule that compares the reporter's ID against the prompt's `authorId`. However, the `RELIST_REQUEST` reason serves as an exception to this rule, allowing authors to flag their own content specifically for republication requests without triggering the self-reporting protection mechanism.

### What database indexes support the reporting functionality?

The `PromptReport` model in `prisma/schema.prisma` defines three database indexes: `@@index([promptId])` optimizes queries fetching all reports for a specific prompt, `@@index([reporterId])` accelerates lookups of a user's reporting history, and `@@index([status])` enables efficient filtering of pending reports for the admin moderation queue.