# Semi-Automatic Reddit Moderation System Setup

## Prerequisites

- Node.js 18+ and npm/yarn
- PostgreSQL 14+
- Reddit Developer Account
- Anthropic Claude API Access
- Access to subreddits where you have moderation permissions

## Step 1: Reddit API Setup

### 1.1 Create Reddit Application
1. Go to https://www.reddit.com/prefs/apps
2. Click "Create Application" or "Create Another App"
3. Fill in details:
   - **Name**: Your moderation app name
   - **App type**: Web app
   - **Description**: AI-assisted moderation tool
   - **About URL**: Your domain (can be localhost for development)
   - **Redirect URI**: `http://localhost:3000/auth/reddit/callback`

### 1.2 Required OAuth Scopes
Your app needs these scopes for moderation:
```
identity, read, modposts, modflair, modconfig, modcontributors, modwiki, modlog
```

### 1.3 Get Credentials
After creating the app, note down:
- **Client ID** (under the app name)
- **Client Secret** (click "edit" to see)

## Step 2: Anthropic Claude API Setup

### 2.1 Get API Key
1. Sign up at https://console.anthropic.com/
2. Go to API Keys section
3. Create a new API key
4. Note down the key (starts with `sk-ant-api03-...`)

### 2.2 Pricing Considerations
- Claude Sonnet 4: ~$3 per 1M input tokens, ~$15 per 1M output tokens
- Estimated cost: $0.01-0.05 per modqueue item analysis
- Consider setting usage limits and monitoring

## Step 3: Database Setup

### 3.1 Install PostgreSQL
```bash
# Ubuntu/Debian
sudo apt update
sudo apt install postgresql postgresql-contrib

# macOS with Homebrew
brew install postgresql
brew services start postgresql

# Windows
# Download from https://www.postgresql.org/download/windows/
```

### 3.2 Create Database
```bash
sudo -u postgres psql
CREATE DATABASE reddit_moderation;
CREATE USER mod_user WITH PASSWORD 'secure_password';
GRANT ALL PRIVILEGES ON DATABASE reddit_moderation TO mod_user;
\q
```

### 3.3 Run Schema
```bash
psql -U mod_user -d reddit_moderation -f database_schema.sql
```

## Step 4: Environment Variables

Create `.env` file in your project root:

```env
# Database
DATABASE_URL=postgresql://mod_user:secure_password@localhost:5432/reddit_moderation

# Reddit API
REDDIT_CLIENT_ID=your_reddit_client_id
REDDIT_CLIENT_SECRET=your_reddit_client_secret
REDDIT_REDIRECT_URI=http://localhost:3000/auth/reddit/callback
REDDIT_USER_AGENT=YourAppName/1.0.0 by /u/yourusername

# Anthropic Claude
ANTHROPIC_API_KEY=sk-ant-api03-your-key-here

# Application
PORT=3000
NODE_ENV=development
JWT_SECRET=your-jwt-secret-key
SESSION_SECRET=your-session-secret

# Security
CORS_ORIGIN=http://localhost:3000
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100

# AI Configuration
AI_ANALYSIS_TIMEOUT_MS=30000
MAX_BATCH_SIZE=50
DEFAULT_CONFIDENCE_THRESHOLD=7.0
```

## Step 5: Install Dependencies

### 5.1 Backend Dependencies
```bash
npm install express cors helmet morgan
npm install @anthropic-ai/sdk snoowrap axios
npm install pg sequelize
npm install passport passport-reddit
npm install express-rate-limit express-session
npm install jsonwebtoken bcryptjs
npm install dotenv joi
npm install bull redis
```

### 5.2 Frontend Dependencies
```bash
npm install react react-dom @types/react @types/react-dom
npm install @tanstack/react-query wouter
npm install @radix-ui/react-alert-dialog @radix-ui/react-tooltip
npm install lucide-react class-variance-authority
npm install tailwindcss @tailwindcss/typography
npm install vite @vitejs/plugin-react
```

## Step 6: Reddit OAuth Integration

### 6.1 Create OAuth Routes
```javascript
// auth/reddit.js
const passport = require('passport');
const RedditStrategy = require('passport-reddit').Strategy;

passport.use(new RedditStrategy({
  clientID: process.env.REDDIT_CLIENT_ID,
  clientSecret: process.env.REDDIT_CLIENT_SECRET,
  callbackURL: process.env.REDDIT_REDIRECT_URI,
  scope: ['identity', 'read', 'modposts', 'modflair', 'modconfig']
}, (accessToken, refreshToken, profile, done) => {
  // Store tokens securely
  return done(null, { 
    profile, 
    accessToken, 
    refreshToken 
  });
}));

// Routes
app.get('/auth/reddit', passport.authenticate('reddit', {
  state: 'random-state-string',
  duration: 'permanent'
}));

app.get('/auth/reddit/callback', 
  passport.authenticate('reddit', { failureRedirect: '/login' }),
  (req, res) => {
    // Store tokens securely in session or JWT
    const token = jwt.sign({
      userId: req.user.profile.id,
      accessToken: req.user.accessToken,
      refreshToken: req.user.refreshToken
    }, process.env.JWT_SECRET, { expiresIn: '24h' });
    
    res.redirect(`${process.env.CORS_ORIGIN}?token=${token}`);
  }
);
```

## Step 7: Background Job Processing

### 7.1 Install Redis (for job queue)
```bash
# Ubuntu/Debian
sudo apt install redis-server

# macOS
brew install redis
brew services start redis

# Windows
# Use WSL or download from Redis website
```

### 7.2 Setup Job Queue
```javascript
// jobs/queue.js
const Queue = require('bull');
const redis = require('redis');

const redisClient = redis.createClient();
const moderationQueue = new Queue('moderation analysis', {
  redis: { port: 6379, host: '127.0.0.1' }
});

// Process AI analysis jobs
moderationQueue.process('analyze-item', async (job) => {
  const { item, rulesAnalysis, subreddit } = job.data;
  
  try {
    const analysis = await analyzeWithClaude(item, rulesAnalysis);
    await saveAnalysisToDatabase(item.id, analysis);
    return { success: true, analysis };
  } catch (error) {
    console.error('Analysis failed:', error);
    throw error;
  }
});

// Process batch analysis
moderationQueue.process('batch-analyze', async (job) => {
  const { subreddit, items, rulesAnalysis } = job.data;
  const results = [];
  
  for (const item of items) {
    try {
      const analysis = await analyzeWithClaude(item, rulesAnalysis);
      results.push({ item, analysis });
      await job.progress((results.length / items.length) * 100);
    } catch (error) {
      results.push({ item, error: error.message });
    }
  }
  
  return results;
});

module.exports = { moderationQueue };
```

## Step 8: Error Handling & Logging

### 8.1 Setup Logging
```javascript
// utils/logger.js
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  defaultMeta: { service: 'reddit-moderation' },
  transports: [
    new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
    new winston.transports.File({ filename: 'logs/combined.log' }),
    new winston.transports.Console({
      format: winston.format.simple()
    })
  ]
});

module.exports = logger;
```

### 8.2 Error Middleware
```javascript
// middleware/errorHandler.js
const logger = require('../utils/logger');

const errorHandler = (err, req, res, next) => {
  logger.error(err.stack);
  
  if (err.name === 'ValidationError') {
    return res.status(400).json({ 
      error: 'Validation Error', 
      details: err.message 
    });
  }
  
  if (err.name === 'UnauthorizedError') {
    return res.status(401).json({ 
      error: 'Unauthorized', 
      message: 'Invalid or expired token' 
    });
  }
  
  if (err.response?.status === 429) {
    return res.status(429).json({ 
      error: 'Rate Limited', 
      message: 'Too many requests, please try again later' 
    });
  }
  
  res.status(500).json({ 
    error: 'Internal Server Error',
    message: process.env.NODE_ENV === 'development' ? err.message : 'Something went wrong'
  });
};

module.exports = errorHandler;
```

## Step 9: Security Configuration

### 9.1 Rate Limiting
```javascript
// middleware/rateLimiter.js
const rateLimit = require('express-rate-limit');

const createRateLimiter = (windowMs, max, message) => rateLimit({
  windowMs,
  max,
  message: { error: message },
  standardHeaders: true,
  legacyHeaders: false,
});

const apiLimiter = createRateLimiter(
  15 * 60 * 1000, // 15 minutes
  100, // limit each IP to 100 requests per windowMs
  'Too many API requests'
);

const aiAnalysisLimiter = createRateLimiter(
  60 * 1000, // 1 minute
  10, // limit AI analysis requests
  'Too many AI analysis requests'
);

module.exports = { apiLimiter, aiAnalysisLimiter };
```

### 9.2 Security Headers
```javascript
// middleware/security.js
const helmet = require('helmet');

const securityConfig = helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", "data:", "https:"],
      connectSrc: ["'self'", "https://api.anthropic.com", "https://oauth.reddit.com"]
    },
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  }
});

module.exports = securityConfig;
```

## Step 10: Testing Setup

### 10.1 Unit Tests
```javascript
// tests/api.test.js
const request = require('supertest');
const app = require('../app');

describe('Moderation API', () => {
  test('GET /api/subreddits/moderated', async () => {
    const response = await request(app)
      .get('/api/subreddits/moderated')
      .set('Authorization', 'Bearer test-token')
      .expect(200);
      
    expect(response.body).toHaveProperty('subreddits');
  });
  
  test('POST /api/ai/analyze-item', async () => {
    const mockItem = {
      id: 'test123',
      type: 'submission',
      title: 'Test post',
      author: 'testuser'
    };
    
    const response = await request(app)
      .post('/api/ai/analyze-item')
      .send({ item: mockItem, rules_analysis: {} })
      .expect(200);
      
    expect(response.body).toHaveProperty('analysis');
  });
});
```

### 10.2 Integration Tests
```javascript
// tests/integration.test.js
const { analyzeWithClaude } = require('../services/aiService');

describe('AI Integration', () => {
  test('Should analyze rule violations correctly', async () => {
    const mockItem = {
      type: 'submission',
      title: 'SPAM CONTENT BUY NOW!!!',
      selftext: 'Click here to buy amazing products'
    };
    
    const mockRules = {
      rule_categories: { spam: ['promotional content'] }
    };
    
    const result = await analyzeWithClaude(mockItem, mockRules);
    
    expect(result.violations_found.length).toBeGreaterThan(0);
    expect(result.suggested_action).toBe('remove');
  });
});
```

## Step 11: Deployment Configuration

### 11.1 Production Environment Variables
```bash
# .env.production
NODE_ENV=production
PORT=80
DATABASE_URL=postgresql://user:pass@prod-db:5432/reddit_moderation
REDIS_URL=redis://prod-redis:6379
ANTHROPIC_API_KEY=your-production-key

# Security
JWT_SECRET=very-secure-production-secret
SESSION_SECRET=another-secure-secret
CORS_ORIGIN=https://your-domain.com

# Monitoring
SENTRY_DSN=https://your-sentry-dsn
LOG_LEVEL=warn
```

### 11.2 Docker Configuration
```dockerfile
# Dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]
```

```yaml
# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - postgres
      - redis
    restart: unless-stopped

  postgres:
    image: postgres:14
    environment:
      POSTGRES_DB: reddit_moderation
      POSTGRES_USER: mod_user
      POSTGRES_PASSWORD: secure_password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./database_schema.sql:/docker-entrypoint-initdb.d/schema.sql
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  postgres_data:
```

## Step 12: Monitoring & Analytics

### 12.1 Health Check Endpoint
```javascript
// routes/health.js
app.get('/health', async (req, res) => {
  const health = {
    status: 'OK',
    timestamp: new Date().toISOString(),
    services: {}
  };
  
  try {
    // Check database
    await db.query('SELECT 1');
    health.services.database = 'UP';
  } catch (error) {
    health.services.database = 'DOWN';
    health.status = 'ERROR';
  }
  
  try {
    // Check Redis
    await redisClient.ping();
    health.services.redis = 'UP';
  } catch (error) {
    health.services.redis = 'DOWN';
    health.status = 'ERROR';
  }
  
  // Check AI API
  try {
    await anthropic.messages.create({
      model: "claude-sonnet-4-20250514",
      max_tokens: 10,
      messages: [{ role: "user", content: "ping" }]
    });
    health.services.ai = 'UP';
  } catch (error) {
    health.services.ai = 'DOWN';
  }
  
  res.status(health.status === 'OK' ? 200 : 503).json(health);
});
```

### 12.2 Performance Metrics
```javascript
// middleware/metrics.js
const prometheus = require('prom-client');

const httpRequestDuration = new prometheus.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status']
});

const aiAnalysisCounter = new prometheus.Counter({
  name: 'ai_analysis_total',
  help: 'Total number of AI analyses performed',
  labelNames: ['subreddit', 'action']
});

module.exports = { httpRequestDuration, aiAnalysisCounter };
```

## Step 13: Final Setup Steps

### 13.1 Start Services
```bash
# Development
npm run dev

# Production
docker-compose up -d
```

### 13.2 Verify Installation
1. Navigate to `http://localhost:3000`
2. Click "Login with Reddit"
3. Authorize the application
4. Select a moderated subreddit
5. View the moderation queue
6. Test AI analysis on a queue item

### 13.3 Initial Configuration
1. Set your moderation preferences in the UI
2. Configure removal reason templates
3. Set confidence thresholds for auto-actions
4. Test batch analysis with a small set

## Troubleshooting

### Common Issues

**Reddit API 403 Forbidden**
- Verify you have moderation permissions
- Check OAuth scopes include `modposts`
- Ensure access token is fresh

**Claude API Rate Limits**
- Implement request queuing
- Add exponential backoff
- Monitor usage in Anthropic console

**Database Connection Issues**
- Check DATABASE_URL format
- Verify PostgreSQL is running
- Ensure user has proper permissions

**High AI Costs**
- Implement caching for similar content
- Use confidence thresholds to reduce API calls
- Monitor and set spending limits

## Performance Optimization

1. **Caching Strategy**
   - Redis for session data
   - Database caching for rules analysis
   - CDN for static assets

2. **Database Optimization**
   - Regular VACUUM and ANALYZE
   - Proper indexing on query columns
   - Connection pooling

3. **AI Optimization**
   - Batch similar requests
   - Cache analysis results
   - Use shorter prompts when possible

## Security Best Practices

1. **Token Security**
   - Rotate tokens regularly
   - Use HTTPS in production
   - Implement token refresh logic

2. **Data Protection**
   - Encrypt sensitive data at rest
   - Implement data retention policies
   - Regular security audits

3. **Access Control**
   - Implement role-based permissions
   - Audit moderation actions
   - Rate limiting and abuse detection