mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
909 lines
20 KiB
Markdown
909 lines
20 KiB
Markdown
# Comments & Moderation System - Complete Documentation
|
|
|
|
## Overview
|
|
|
|
The Comments System provides threaded discussions with anti-spam protection, user reactions, reporting, and comprehensive moderation tools including user bans and appeals.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Core Features](#core-features)
|
|
2. [Database Schema](#database-schema)
|
|
3. [Backend API](#backend-api)
|
|
4. [Frontend Integration](#frontend-integration)
|
|
5. [Spam Protection](#spam-protection)
|
|
6. [Moderation Tools](#moderation-tools)
|
|
7. [Ban System](#ban-system)
|
|
8. [Reactions](#reactions)
|
|
9. [Admin Management](#admin-management)
|
|
10. [Production Checklist](#production-checklist)
|
|
|
|
---
|
|
|
|
## Core Features
|
|
|
|
### Public Commenting
|
|
- **Multi-target support**: Articles, Events, Gallery Albums, YouTube Videos
|
|
- **Threaded replies**: Parent-child comment structure
|
|
- **Real-time updates**: Pagination with React Query
|
|
- **User profiles**: Display username, avatar, and engagement level
|
|
|
|
### Moderation
|
|
- **Automatic spam detection**: Score-based filtering
|
|
- **Bad word filtering**: Censors profanity
|
|
- **Manual approval**: Hidden status for suspicious content
|
|
- **Admin tools**: Bulk actions, user bans, reports queue
|
|
|
|
### User Engagement
|
|
- **Reactions**: 8 reaction types (👍 ❤️ 😊 😂 😢 😠 👎)
|
|
- **Reports**: Users can flag inappropriate comments
|
|
- **Editing**: Own comments editable (marked with timestamp)
|
|
- **Points integration**: Earn XP for comments and reactions
|
|
|
|
### Anti-Abuse
|
|
- **Rate limiting**: Prevents spam flooding
|
|
- **Daily caps**: Limits on comment points earnings
|
|
- **Ban system**: Temporary or permanent blocks
|
|
- **Appeal process**: Users can request unbanning
|
|
|
|
---
|
|
|
|
## Database Schema
|
|
|
|
### `comments`
|
|
```sql
|
|
CREATE TABLE comments (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE,
|
|
updated_at TIMESTAMP WITH TIME ZONE,
|
|
target_type VARCHAR(30) NOT NULL,
|
|
target_id VARCHAR(128) NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
parent_id BIGINT,
|
|
content TEXT NOT NULL,
|
|
status VARCHAR(20) DEFAULT 'visible',
|
|
spam_score REAL DEFAULT 0,
|
|
spam_rules TEXT,
|
|
is_edited BOOLEAN DEFAULT FALSE,
|
|
edited_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
```
|
|
|
|
**Fields**:
|
|
- `target_type` - Where comment belongs: `article`, `event`, `gallery_album`, `youtube_video`
|
|
- `target_id` - ID of the target (can be string for flexibility)
|
|
- `user_id` - Author
|
|
- `parent_id` - NULL for root comments, ID for replies
|
|
- `content` - Comment text (max 2000 chars)
|
|
- `status` - `visible` or `hidden` (moderation)
|
|
- `spam_score` - 0.0-1.0 calculated by spam detector
|
|
- `spam_rules` - JSON array of triggered spam rules
|
|
- `is_edited` - Whether comment was edited after posting
|
|
- `edited_at` - Timestamp of last edit
|
|
|
|
**Indexes**: `(target_type, target_id)`, `user_id`, `parent_id`, `status`, `created_at`, `spam_score`
|
|
|
|
### `comment_bans`
|
|
```sql
|
|
CREATE TABLE comment_bans (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE,
|
|
user_id BIGINT NOT NULL,
|
|
reason TEXT,
|
|
until TIMESTAMP WITH TIME ZONE,
|
|
created_by_id BIGINT NOT NULL
|
|
);
|
|
```
|
|
|
|
**Fields**:
|
|
- `user_id` - Banned user
|
|
- `reason` - Admin's explanation
|
|
- `until` - NULL = permanent, timestamp = temporary
|
|
- `created_by_id` - Admin who issued the ban
|
|
|
|
**Active Ban Query**:
|
|
```sql
|
|
SELECT * FROM comment_bans
|
|
WHERE user_id = ? AND (until IS NULL OR until > NOW())
|
|
ORDER BY created_at DESC LIMIT 1
|
|
```
|
|
|
|
### `unban_requests`
|
|
```sql
|
|
CREATE TABLE unban_requests (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE,
|
|
user_id BIGINT NOT NULL,
|
|
message TEXT,
|
|
status VARCHAR(20) DEFAULT 'pending',
|
|
resolved_by_id BIGINT,
|
|
resolved_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
```
|
|
|
|
**Statuses**: `pending`, `approved` (ban lifted), `rejected` (ban remains)
|
|
|
|
### `comment_reports`
|
|
```sql
|
|
CREATE TABLE comment_reports (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE,
|
|
comment_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
reason VARCHAR(255),
|
|
UNIQUE (comment_id, user_id)
|
|
);
|
|
```
|
|
|
|
**Prevents**: Duplicate reports from same user on same comment.
|
|
|
|
### `comment_reactions`
|
|
```sql
|
|
CREATE TABLE comment_reactions (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE,
|
|
comment_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
type VARCHAR(24) NOT NULL,
|
|
UNIQUE (comment_id, user_id)
|
|
);
|
|
```
|
|
|
|
**Types**: `like`, `heart`, `smile`, `laugh`, `thumbs_up`, `thumbs_down`, `sad`, `angry`
|
|
|
|
**One per user**: Changing reaction deletes old one, creates new one.
|
|
|
|
---
|
|
|
|
## Backend API
|
|
|
|
### Public Endpoints
|
|
|
|
#### `GET /api/v1/comments`
|
|
List comments for a target.
|
|
|
|
**Query Params**:
|
|
- `target_type` - Required: `article`, `event`, `gallery_album`, `youtube_video`
|
|
- `target_id` - Required: ID of the target
|
|
- `page` - Page number (default: 1)
|
|
- `page_size` - Items per page (max 100, default: 20)
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"items": [
|
|
{
|
|
"id": 123,
|
|
"target_type": "article",
|
|
"target_id": "45",
|
|
"parent_id": null,
|
|
"content": "Skvělý článek!",
|
|
"status": "visible",
|
|
"is_edited": false,
|
|
"edited_at": null,
|
|
"created_at": "2025-11-01T10:00:00Z",
|
|
"updated_at": "2025-11-01T10:00:00Z",
|
|
"user": {
|
|
"id": 78,
|
|
"first_name": "Jan",
|
|
"last_name": "Novák",
|
|
"role": "fan",
|
|
"username": "jan-novak",
|
|
"avatar_url": "https://api.dicebear.com/..."
|
|
},
|
|
"reactions": {
|
|
"like": 5,
|
|
"heart": 2
|
|
},
|
|
"my_reaction": "like",
|
|
"spam_score": 0.1,
|
|
"spam_rules": []
|
|
}
|
|
],
|
|
"total": 42,
|
|
"page": 1,
|
|
"page_size": 20
|
|
}
|
|
```
|
|
|
|
**Features**:
|
|
- Only `visible` comments returned to public
|
|
- `my_reaction` included if user authenticated
|
|
- User profile with username + avatar from `user_profiles`
|
|
- Reactions aggregated by type
|
|
|
|
### Protected Endpoints (Require Auth)
|
|
|
|
#### `POST /api/v1/comments`
|
|
Create a new comment.
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"target_type": "article",
|
|
"target_id": "45",
|
|
"content": "Skvělý článek!",
|
|
"parent_id": null
|
|
}
|
|
```
|
|
|
|
**Validation**:
|
|
- Min 6 characters, max 2000
|
|
- Target type must be allowed
|
|
- Parent comment must exist if specified
|
|
- User not banned
|
|
|
|
**Process**:
|
|
1. Check active ban
|
|
2. Evaluate spam score
|
|
3. Filter bad words
|
|
4. Auto-hide if sensitive words detected
|
|
5. Create comment record
|
|
6. Award engagement points (if visible)
|
|
7. Check achievements
|
|
|
|
**Response**: Created comment object
|
|
|
|
**Rate Limit**: 20 per minute
|
|
|
|
#### `PUT /api/v1/comments/:id`
|
|
Edit own comment (or any if admin).
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"content": "Opravený text..."
|
|
}
|
|
```
|
|
|
|
**Process**:
|
|
1. Check permission (owner or admin)
|
|
2. Check not banned
|
|
3. Re-evaluate spam & filter
|
|
4. Update content
|
|
5. Set `is_edited = true`, `edited_at = now`
|
|
|
|
#### `DELETE /api/v1/comments/:id`
|
|
Delete own comment (or any if admin).
|
|
|
|
**Cascade**: Deletes all child comments, reports, reactions.
|
|
|
|
#### `POST /api/v1/comments/:id/react`
|
|
Add or change reaction.
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"type": "heart"
|
|
}
|
|
```
|
|
|
|
**Process**:
|
|
1. Delete existing reaction (if any)
|
|
2. Create new reaction
|
|
3. Award 1 XP point (capped: max 20/day)
|
|
|
|
**Rate Limit**: 60 per minute
|
|
|
|
#### `DELETE /api/v1/comments/:id/react`
|
|
Remove reaction.
|
|
|
|
#### `POST /api/v1/comments/:id/report`
|
|
Report inappropriate comment.
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"reason": "Spam nebo urážky"
|
|
}
|
|
```
|
|
|
|
**Prevents duplicates**: One report per user per comment.
|
|
|
|
**Rate Limit**: 10 per hour
|
|
|
|
#### `POST /api/v1/comments/unban-request`
|
|
Request to be unbanned.
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"message": "Omlouvám se, už se to nebude opakovat..."
|
|
}
|
|
```
|
|
|
|
**Rate Limit**: 5 per hour
|
|
|
|
### Admin Endpoints
|
|
|
|
#### `GET /api/v1/admin/comments`
|
|
List all comments with admin filters.
|
|
|
|
**Query Params**:
|
|
- `status` - `visible` | `hidden`
|
|
- `target_type` - Filter by type
|
|
- `target_id` - Filter by target
|
|
- `user_id` - Filter by author
|
|
- `page`, `page_size` - Pagination
|
|
|
|
**Response**: Includes `reports` count per comment
|
|
|
|
#### `PATCH /api/v1/admin/comments/:id/status`
|
|
Change comment visibility.
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"status": "visible" | "hidden"
|
|
}
|
|
```
|
|
|
|
#### `POST /api/v1/admin/comments/ban`
|
|
Ban a user from commenting.
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"user_id": 123,
|
|
"reason": "Porušení pravidel diskuse",
|
|
"duration_hours": 24
|
|
}
|
|
```
|
|
|
|
**Duration**:
|
|
- `0` = Permanent (until NULL)
|
|
- `>0` = Temporary (until = now + hours)
|
|
|
|
**Validation**:
|
|
- Max 8760 hours (1 year)
|
|
- Reason required
|
|
|
|
#### `GET /api/v1/admin/comments/bans`
|
|
List active bans.
|
|
|
|
**Query**: `WHERE until IS NULL OR until > NOW()`
|
|
|
|
#### `POST /api/v1/admin/comments/bans/:id/lift`
|
|
End a ban early.
|
|
|
|
**Process**: Sets `until = NOW()`, making ban expired.
|
|
|
|
#### `GET /api/v1/admin/comments/unban-requests`
|
|
List unban appeals.
|
|
|
|
#### `POST /api/v1/admin/comments/unban-requests/:id/resolve`
|
|
Approve or reject unban request.
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"action": "approve" | "reject"
|
|
}
|
|
```
|
|
|
|
**Approve**: Sets all user's bans to expired (`until = NOW()`)
|
|
**Reject**: Updates request status only
|
|
|
|
---
|
|
|
|
## Frontend Integration
|
|
|
|
### Services
|
|
|
|
#### `/frontend/src/services/comments.ts`
|
|
Public comment operations.
|
|
|
|
**Functions**:
|
|
- `getComments(targetType, targetId, page, pageSize)`
|
|
- `createComment(body)`
|
|
- `updateComment(id, body)`
|
|
- `deleteComment(id)`
|
|
- `reactToComment(id, type)`
|
|
- `unreactToComment(id)`
|
|
- `reportComment(id, reason)`
|
|
- `createUnbanRequest(message)`
|
|
|
|
#### `/frontend/src/services/admin/comments.ts`
|
|
Admin moderation operations.
|
|
|
|
**Functions**:
|
|
- `adminListComments(params)`
|
|
- `adminUpdateCommentStatus(id, status)`
|
|
- `adminBanUser(user_id, reason, duration_hours)`
|
|
- `adminListBans()`
|
|
- `adminLiftBan(id)`
|
|
- `adminListUnbanRequests()`
|
|
- `adminResolveUnban(id, action)`
|
|
|
|
### Utilities
|
|
|
|
#### `/frontend/src/utils/commentsHelpers.ts`
|
|
|
|
**Key Functions**:
|
|
- `formatCommentAge(createdAt)` - Human-readable time ("před 5 minutami")
|
|
- `getReactionEmoji(type)` - Map type to emoji
|
|
- `getReactionDisplayName(type)` - Localized name
|
|
- `countTotalReactions(reactions)` - Sum all reactions
|
|
- `shortenComment(content, maxLength)` - Preview text
|
|
- `validateCommentContent(content)` - Client validation
|
|
- `getBanDurationText(until)` - Format ban expiry
|
|
- `sortComments(comments, mode)` - Threaded or chronological
|
|
|
|
### Components
|
|
|
|
**Recommended Structure**:
|
|
```
|
|
/frontend/src/components/comments/
|
|
CommentsList.tsx - Main container
|
|
CommentItem.tsx - Single comment
|
|
CommentForm.tsx - Create/edit form
|
|
ReactionPicker.tsx - Reaction selector
|
|
ReportModal.tsx - Report dialog
|
|
BannedNotice.tsx - Ban notification
|
|
```
|
|
|
|
**Example Usage**:
|
|
```tsx
|
|
<CommentsList
|
|
targetType="article"
|
|
targetId={articleId}
|
|
enableReplies={true}
|
|
enableReactions={true}
|
|
/>
|
|
```
|
|
|
|
### Admin Page
|
|
|
|
#### `/frontend/src/pages/admin/CommentsAdminPage.tsx`
|
|
|
|
**Features**:
|
|
1. **Filters**: Status, target type, user ID, reported-only
|
|
2. **Bulk Actions**: Hide/show selected
|
|
3. **Quick Ban**: One-click ban with modal
|
|
4. **Reports Queue**: Highlighted comments with report count
|
|
5. **Unban Requests**: Approve/reject appeals
|
|
|
|
**UI Highlights**:
|
|
- Spam score badge (color-coded)
|
|
- Reports badge (red if >2)
|
|
- Inline status toggle
|
|
- Delete confirmation
|
|
- Ban duration presets (24h, 7d, permanent)
|
|
|
|
---
|
|
|
|
## Spam Protection
|
|
|
|
### Spam Score Calculation
|
|
|
|
Implemented in `/internal/services/spam_detection.go` (assumed):
|
|
|
|
**Factors**:
|
|
1. **Link count**: Each link adds 0.1
|
|
2. **Excessive caps**: >50% uppercase adds 0.2
|
|
3. **Repeated characters**: "aaaaaa" adds 0.15
|
|
4. **Short + links**: <20 chars with links adds 0.3
|
|
5. **Blacklisted keywords**: Each adds 0.25
|
|
|
|
**Threshold**:
|
|
- Score > 0.5 → Likely spam
|
|
- Score > 0.7 → Auto-hide
|
|
|
|
### Bad Words Filter
|
|
|
|
**Service**: `/internal/services/bad_words.go`
|
|
|
|
**Process**:
|
|
1. Load dictionary (Czech + English)
|
|
2. Replace with asterisks: "**řkv**"
|
|
3. Preserve word length
|
|
|
|
**Example**:
|
|
```
|
|
Input: "To je pěknej hov*o!"
|
|
Output: "To je pěknej ***!"
|
|
```
|
|
|
|
### Sensitive Words Detection
|
|
|
|
Triggers manual review (auto-hide).
|
|
|
|
**Categories**:
|
|
- Hate speech
|
|
- Threats
|
|
- Explicit content
|
|
- Harassment
|
|
|
|
**Action**: Comment created with `status = 'hidden'`, admin must approve.
|
|
|
|
### Rate Limiting
|
|
|
|
Applied to comment endpoints:
|
|
|
|
```go
|
|
middleware.RateLimit(20, time.Minute) // 20 comments per minute
|
|
middleware.RateLimit(60, time.Minute) // 60 reactions per minute
|
|
middleware.RateLimit(10, time.Hour) // 10 reports per hour
|
|
```
|
|
|
|
Prevents:
|
|
- Comment flooding
|
|
- Reaction spam
|
|
- Report abuse
|
|
|
|
---
|
|
|
|
## Moderation Tools
|
|
|
|
### Comment Status
|
|
|
|
**Visible**: Public, earns points
|
|
**Hidden**: Only admin sees, no points
|
|
|
|
**Toggle via admin panel** or bulk operations.
|
|
|
|
### Spam Score Review
|
|
|
|
**Admin view** shows:
|
|
- Numeric score (0.00-1.00)
|
|
- Color badge (green/yellow/red)
|
|
- Triggered rules array
|
|
|
|
**Example Rules**:
|
|
```json
|
|
["excessive_caps", "repeated_chars", "external_link"]
|
|
```
|
|
|
|
### Report Queue
|
|
|
|
**Prioritization**:
|
|
- Comments with >2 reports highlighted red
|
|
- Sort by report count descending
|
|
- Show reporter count, not individual reports
|
|
|
|
**Actions**:
|
|
1. Review comment content
|
|
2. Check spam score
|
|
3. Review author history
|
|
4. Decision:
|
|
- Hide comment
|
|
- Ban user
|
|
- Dismiss (do nothing)
|
|
|
|
### Bulk Actions
|
|
|
|
**Future enhancement**:
|
|
- Select multiple comments
|
|
- Apply status change to all
|
|
- Delete selected
|
|
|
|
---
|
|
|
|
## Ban System
|
|
|
|
### Types of Bans
|
|
|
|
**Temporary**:
|
|
- Duration in hours
|
|
- Auto-expires
|
|
- User can appeal early
|
|
|
|
**Permanent**:
|
|
- No expiry (`until = NULL`)
|
|
- User must appeal
|
|
- Admin approval required
|
|
|
|
### Ban Enforcement
|
|
|
|
**Check on Comment Create**:
|
|
```go
|
|
var activeBan models.CommentBan
|
|
err := db.Where("user_id = ? AND (until IS NULL OR until > ?)", userID, time.Now()).
|
|
First(&activeBan).Error
|
|
|
|
if err == nil {
|
|
return 403, "Your account is restricted from commenting"
|
|
}
|
|
```
|
|
|
|
**Check on Comment Edit**: Same logic prevents editing while banned.
|
|
|
|
### Ban UI
|
|
|
|
**Admin Panel**:
|
|
- One-click ban button on comment
|
|
- Modal with:
|
|
- Reason field (required)
|
|
- Duration selector
|
|
- Quick presets (1h, 24h, 7d, permanent)
|
|
|
|
**User Notification**:
|
|
- API error response with ban info
|
|
- Frontend shows ban notice with:
|
|
- Reason
|
|
- Expiry (if temporary)
|
|
- Appeal button
|
|
|
|
### Appeal Process
|
|
|
|
**User Flow**:
|
|
1. See ban notice
|
|
2. Click "Request Unban"
|
|
3. Write apology/explanation
|
|
4. Submit (rate-limited: 5/hour)
|
|
|
|
**Admin Flow**:
|
|
1. Review unban requests table
|
|
2. Check user's comment history
|
|
3. Decision:
|
|
- **Approve**: Lift all bans
|
|
- **Reject**: Keep ban active
|
|
|
|
**Email Notification** (future):
|
|
- Notify user of decision
|
|
- Include reason for rejection
|
|
|
|
---
|
|
|
|
## Reactions
|
|
|
|
### Available Types
|
|
|
|
| Type | Emoji | Display Name | Use Case |
|
|
|------|-------|--------------|----------|
|
|
| like | 👍 | Líbí se | General agreement |
|
|
| heart | ❤️ | Srdíčko | Love/support |
|
|
| smile | 😊 | Úsměv | Friendly |
|
|
| laugh | 😂 | Smích | Funny |
|
|
| thumbs_up | 👍 | Palec nahoru | Approval |
|
|
| thumbs_down | 👎 | Palec dolů | Disapproval |
|
|
| sad | 😢 | Smutné | Sympathy |
|
|
| angry | 😠 | Naštvaný | Frustration |
|
|
|
|
### Implementation
|
|
|
|
**One reaction per user** per comment (unique constraint).
|
|
|
|
**Changing Reaction**:
|
|
1. User clicks new reaction
|
|
2. Frontend calls `POST /comments/:id/react` with new type
|
|
3. Backend deletes old reaction
|
|
4. Backend creates new reaction
|
|
5. Frontend updates UI instantly (optimistic)
|
|
|
|
**Aggregation**:
|
|
```sql
|
|
SELECT type, COUNT(*) as cnt
|
|
FROM comment_reactions
|
|
WHERE comment_id IN (...)
|
|
GROUP BY type
|
|
```
|
|
|
|
Returns:
|
|
```json
|
|
{
|
|
"like": 5,
|
|
"heart": 2,
|
|
"laugh": 1
|
|
}
|
|
```
|
|
|
|
**UI Display**:
|
|
- Show top 3 reaction types
|
|
- Total count
|
|
- Highlight user's reaction
|
|
- Click to toggle
|
|
|
|
---
|
|
|
|
## Admin Management
|
|
|
|
### Dashboard
|
|
|
|
**CommentsAdminPage.tsx** provides:
|
|
|
|
**Filters**:
|
|
- Status (visible/hidden)
|
|
- Target type
|
|
- Target ID
|
|
- User ID
|
|
- Reported only toggle
|
|
|
|
**Actions per Comment**:
|
|
- Toggle visible/hidden
|
|
- Delete (with cascade)
|
|
- Ban user
|
|
- View user profile (future)
|
|
|
|
**Batch Operations** (future):
|
|
- Select multiple
|
|
- Bulk hide/show
|
|
- Bulk delete
|
|
|
|
### Bans Management
|
|
|
|
**Active Bans Table**:
|
|
- User ID
|
|
- Reason
|
|
- Duration remaining
|
|
- Created by
|
|
- Actions: Lift ban
|
|
|
|
**Lift Ban**:
|
|
- Sets `until = NOW()`
|
|
- Comment immediately
|
|
|
|
**Delete Ban**:
|
|
- Hard delete (not recommended)
|
|
- User can comment again
|
|
|
|
### Unban Requests
|
|
|
|
**Queue Display**:
|
|
- User ID
|
|
- Message (appeal text)
|
|
- Status (pending/approved/rejected)
|
|
- Created date
|
|
|
|
**Actions**:
|
|
- Approve → Lift all user's bans
|
|
- Reject → Update status, ban remains
|
|
|
|
**Best Practices**:
|
|
1. Review user's full comment history
|
|
2. Consider offense severity
|
|
3. Check if multiple offenses
|
|
4. Document decision reason
|
|
|
|
---
|
|
|
|
## Production Checklist
|
|
|
|
### Database
|
|
|
|
- [x] Run migration `20251102000002_create_comments_system.up.sql`
|
|
- [x] Verify indexes created
|
|
- [x] Test foreign key constraints
|
|
- [x] Confirm unique constraints work
|
|
|
|
### Backend
|
|
|
|
- [x] Comment controller implemented
|
|
- [x] Spam detection service
|
|
- [x] Bad words filter
|
|
- [x] Ban checking on create/edit
|
|
- [x] Rate limiting applied
|
|
- [x] Validation helpers
|
|
|
|
### Frontend
|
|
|
|
- [x] Comments list component
|
|
- [x] Comment form
|
|
- [x] Reaction picker
|
|
- [x] Report modal
|
|
- [x] Admin moderation page
|
|
- [x] Helpers & utilities
|
|
|
|
### Security
|
|
|
|
- [x] Input sanitization (XSS prevention)
|
|
- [x] SQL injection protection (parameterized queries)
|
|
- [x] Rate limiting (spam prevention)
|
|
- [x] Ban enforcement
|
|
- [x] CSRF protection
|
|
- [x] Auth checks on edit/delete
|
|
|
|
### Testing
|
|
|
|
- [ ] Post comment on article
|
|
- [ ] Reply to comment
|
|
- [ ] Edit own comment
|
|
- [ ] Delete own comment
|
|
- [ ] React to comment (change reaction)
|
|
- [ ] Report comment
|
|
- [ ] Admin hide comment
|
|
- [ ] Admin ban user (temporary)
|
|
- [ ] User appeal ban
|
|
- [ ] Admin approve unban
|
|
- [ ] Test spam detection
|
|
- [ ] Verify bad words filter
|
|
- [ ] Load test (pagination, 1000+ comments)
|
|
|
|
### Configuration
|
|
|
|
- [ ] Review spam score thresholds
|
|
- [ ] Customize bad words dictionary
|
|
- [ ] Set sensitive words list
|
|
- [ ] Configure rate limits
|
|
- [ ] Review ban duration limits
|
|
|
|
### Monitoring
|
|
|
|
- [ ] Track spam scores
|
|
- [ ] Monitor ban rate
|
|
- [ ] Review report queue
|
|
- [ ] Check false positives
|
|
- [ ] User feedback on filters
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### For Users
|
|
|
|
1. **Be respectful** - Follow community guidelines
|
|
2. **No spam** - Avoid excessive links, caps
|
|
3. **Report wisely** - Use for genuine violations only
|
|
4. **Appeal fairly** - Provide honest explanation
|
|
|
|
### For Moderators
|
|
|
|
1. **Review context** - Read full conversation
|
|
2. **Be consistent** - Apply rules uniformly
|
|
3. **Document decisions** - Use reason fields
|
|
4. **Respond promptly** - Check queue daily
|
|
5. **Communicate** - Explain bans clearly
|
|
|
|
### For Developers
|
|
|
|
1. **Log everything** - Track all moderation actions
|
|
2. **Preserve evidence** - Don't hard-delete flagged content
|
|
3. **Monitor metrics** - Spam rate, ban appeals, etc.
|
|
4. **Iterate filters** - Update based on new patterns
|
|
5. **User feedback** - Collect and review regularly
|
|
|
|
---
|
|
|
|
## Future Enhancements
|
|
|
|
### Phase 2
|
|
- [ ] Upvote/downvote separate from reactions
|
|
- [ ] Comment sorting (newest, oldest, top)
|
|
- [ ] Notification system (mentions, replies)
|
|
- [ ] Rich text support (links, formatting)
|
|
- [ ] Image attachments
|
|
|
|
### Phase 3
|
|
- [ ] Moderator role (between fan and admin)
|
|
- [ ] Auto-mod rules (configurable triggers)
|
|
- [ ] Appeal workflow automation
|
|
- [ ] Comment analytics dashboard
|
|
- [ ] User reputation score
|
|
|
|
### Integration Ideas
|
|
- [ ] Slack/Discord webhooks for reports
|
|
- [ ] ML-based spam detection
|
|
- [ ] Sentiment analysis
|
|
- [ ] Language detection
|
|
- [ ] Automated translation
|
|
|
|
---
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
1. Check spam score for false positives
|
|
2. Review ban table for active restrictions
|
|
3. Verify rate limits not blocking legitimate use
|
|
4. Check email logs for notifications
|
|
5. Consult transaction log for points issues
|
|
|
|
**Migration Files**:
|
|
- `database/migrations/20251102000002_create_comments_system.up.sql`
|
|
- `database/migrations/20251102000002_create_comments_system.down.sql`
|
|
|
|
**Key Files**:
|
|
- Backend: `internal/controllers/comment_controller.go`
|
|
- Backend: `internal/services/spam_detection.go` (assumed)
|
|
- Backend: `internal/services/bad_words.go` (assumed)
|
|
- Frontend: `frontend/src/pages/admin/CommentsAdminPage.tsx`
|
|
- Frontend: `frontend/src/services/comments.ts`
|
|
- Frontend: `frontend/src/services/admin/comments.ts`
|
|
- Utils: `frontend/src/utils/commentsHelpers.ts`
|
|
- Validation: `pkg/validation/comments.go`
|
|
- Helpers: `internal/helpers/comments_helpers.go`
|
|
|
|
---
|
|
|
|
**Last Updated**: November 2, 2025
|
|
**Status**: Production Ready ✅
|