Files
Bentlybro fe521cb9ac Revise documentation and remove unused utils init
Expanded and reorganized CLAUDE.md for improved onboarding, architecture, and API clarity. Updated docs to standardize endpoint naming, improve examples, and clarify model relationships. Deleted unused app/utils/__init__.py to clean up the codebase.
2025-08-26 07:32:03 +01:00

11 KiB

WebSocket Real-time Updates

AutoModerate provides real-time updates through WebSocket connections using Socket.IO, allowing you to receive instant notifications about moderation results.

Connection

Endpoint

ws://localhost:6217/socket.io/

AutoModerate uses Socket.IO for WebSocket communication, which provides automatic fallback options and reconnection.

JavaScript Client

<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
<script>
const socket = io('http://localhost:6217');

socket.on('connect', function() {
    console.log('Connected to AutoModerate');
});

socket.on('disconnect', function() {
    console.log('Disconnected from AutoModerate');
});
</script>

Python Client

import socketio

sio = socketio.Client()

@sio.event
def connect():
    print('Connected to AutoModerate')

@sio.event
def disconnect():
    print('Disconnected from AutoModerate')

sio.connect('http://localhost:6217')

Authentication

WebSocket connections require authentication. You must be logged in to the web dashboard to establish a connection.

Session-based Authentication

WebSocket connections require authentication via the web dashboard session. Users must be logged in to establish a connection and can only join project rooms for projects they have access to.

Project Rooms

AutoModerate uses "rooms" to organize real-time updates by project. You must join a project room to receive updates for that specific project.

Join Project Room

socket.emit('join_project', {
    project_id: 'your-project-id'
});

// Listen for successful join
socket.on('joined_project', function(data) {
    console.log(`Joined project: ${data.project_id}`);
    console.log(`Room: ${data.room}`);
});

// Handle errors
socket.on('error', function(error) {
    console.error('Error:', error.message);
});

Leave Project Room

socket.emit('leave_project', {
    project_id: 'your-project-id'
});

socket.on('left_project', function(data) {
    console.log(`Left project: ${data.project_id}`);
});

Event Types

1. Connection Events

Event: connect

Triggered when the client connects to the server.

socket.on('connect', function() {
    console.log('Connected to AutoModerate');
    // You can now join project rooms
});

Event: connected

Server confirmation of successful connection (only for authenticated users).

socket.on('connected', function(data) {
    console.log('Server message:', data.message);
});

Event: disconnect

Triggered when the client disconnects from the server.

socket.on('disconnect', function() {
    console.log('Disconnected from AutoModerate');
    // Handle reconnection logic if needed
});

2. Project Room Events

Event: joined_project

Confirmation that you've successfully joined a project room.

socket.on('joined_project', function(data) {
    console.log('Joined project:', data.project_id);
    console.log('Room name:', data.room);
    // You'll now receive updates for this project
});

Event: left_project

Confirmation that you've left a project room.

socket.on('left_project', function(data) {
    console.log('Left project:', data.project_id);
    // You'll no longer receive updates for this project
});

3. Error Events

Event: error

Error messages from the server.

socket.on('error', function(error) {
    console.error('WebSocket error:', error.message);
    
    // Common error messages:
    // - "Authentication required"
    // - "Project ID required"
    // - "Project not found"
    // - "Access denied - you are not a member of this project"
});

4. Moderation Update Events

Event: moderation_update

Receive real-time updates when content is moderated in your project.

// First, join a project room
socket.emit('join_project', {project_id: 'your-project-id'});

// Then listen for moderation updates
socket.on('moderation_update', function(data) {
    console.log('Content moderated:', data);
    // data contains: content_id, status, decision, processing_time, etc.
    updateUI(data);
});

Event Data Structure:

{
  "content_id": "uuid-here",
  "status": "approved|rejected|flagged",
  "decision": "approved",
  "confidence": 0.95,
  "processing_time": 0.23,
  "moderator_type": "rule|ai|manual"
}

Complete Implementation Example

Frontend Dashboard

<!DOCTYPE html>
<html>
<head>
    <title>AutoModerate Dashboard</title>
    <script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
</head>
<body>
    <div id="dashboard">
        <div id="status">Status: <span id="connection-status">Connecting...</span></div>
        <div id="project-info"></div>
        <div id="notifications"></div>
    </div>

    <script>
        const socket = io('http://localhost:6217');
        const projectId = 'your-project-id'; // Replace with actual project ID

        // Connection handling
        socket.on('connect', function() {
            document.getElementById('connection-status').textContent = 'Connected';
            console.log('Connected to AutoModerate');
            
            // Join project room after connecting
            socket.emit('join_project', {project_id: projectId});
        });

        socket.on('disconnect', function() {
            document.getElementById('connection-status').textContent = 'Disconnected';
            console.log('Disconnected from AutoModerate');
        });

        // Authentication confirmation
        socket.on('connected', function(data) {
            console.log('Authenticated:', data.message);
        });

        // Project room events
        socket.on('joined_project', function(data) {
            console.log('Joined project:', data.project_id);
            document.getElementById('project-info').innerHTML = 
                `<p>Joined project: ${data.project_id}</p><p>Room: ${data.room}</p>`;
        });

        socket.on('left_project', function(data) {
            console.log('Left project:', data.project_id);
            document.getElementById('project-info').innerHTML = 
                `<p>Left project: ${data.project_id}</p>`;
        });

        // Error handling
        socket.on('error', function(error) {
            console.error('WebSocket error:', error.message);
            showNotification('Error: ' + error.message, 'error');
        });

        // Moderation updates (if implemented)
        socket.on('moderation_update', function(data) {
            console.log('Moderation update:', data);
            showNotification(`Content ${data.content_id}: ${data.status}`, 'info');
        });

        function showNotification(message, type) {
            const notifications = document.getElementById('notifications');
            const notification = document.createElement('div');
            notification.className = `notification ${type}`;
            notification.textContent = message;
            notifications.appendChild(notification);
            
            // Auto-remove after 5 seconds
            setTimeout(() => {
                if (notification.parentNode) {
                    notifications.removeChild(notification);
                }
            }, 5000);
        }

        // Handle page unload
        window.addEventListener('beforeunload', function() {
            if (projectId) {
                socket.emit('leave_project', {project_id: projectId});
            }
        });
    </script>
</body>
</html>

Error Handling

Connection Errors

socket.on('connect_error', function(error) {
    console.error('Connection failed:', error);
    document.getElementById('connection-status').textContent = 'Connection Failed';
});

socket.on('disconnect', function(reason) {
    console.log('Disconnected:', reason);
    document.getElementById('connection-status').textContent = 'Disconnected';
    
    if (reason === 'io server disconnect') {
        // Server disconnected, attempt manual reconnection
        socket.connect();
    }
});

Authentication Errors

socket.on('error', function(error) {
    console.error('Socket error:', error);
    
    if (error.message === 'Authentication required') {
        // Redirect to login page
        window.location.href = '/auth/login';
    } else if (error.message.includes('Access denied')) {
        // User doesn't have access to the project
        showNotification('You do not have access to this project', 'error');
    }
});

Access Control

Project Membership

Only users who are members of a project can join that project's room. The server checks:

  1. Authentication: User must be logged in
  2. Project Existence: Project must exist in the database
  3. Membership: User must be either:
    • The project owner, OR
    • A project member

Error Messages

  • "Authentication required": User is not logged in
  • "Project ID required": No project_id provided in join_project event
  • "Project not found": Project doesn't exist
  • "Access denied - you are not a member of this project": User lacks permission

Performance Considerations

Connection Management

// Configure reconnection
const socket = io('http://localhost:6217', {
    reconnection: true,
    reconnectionDelay: 1000,
    reconnectionAttempts: 5,
    timeout: 20000
});

// Track connection state
let isConnected = false;
socket.on('connect', () => isConnected = true);
socket.on('disconnect', () => isConnected = false);

Room Management

// Keep track of joined rooms
let joinedProjects = new Set();

function joinProject(projectId) {
    if (!joinedProjects.has(projectId)) {
        socket.emit('join_project', {project_id: projectId});
        joinedProjects.add(projectId);
    }
}

function leaveProject(projectId) {
    if (joinedProjects.has(projectId)) {
        socket.emit('leave_project', {project_id: projectId});
        joinedProjects.delete(projectId);
    }
}

// Clean up on disconnect
socket.on('disconnect', () => {
    joinedProjects.clear();
});

Security Considerations

Authentication

  • WebSocket connections require web dashboard authentication
  • No API key authentication is currently supported for WebSocket connections
  • Users can only join rooms for projects they have access to

Input Validation

// Always validate project IDs
function joinProject(projectId) {
    if (!projectId || typeof projectId !== 'string') {
        console.error('Invalid project ID');
        return;
    }
    
    socket.emit('join_project', {project_id: projectId});
}

Next Steps