# SerpentRace Backend API Documentation for Frontend Developers ## Complete API Reference with All Endpoints ## Table of Contents 1. [Test User Credentials](#test-user-credentials) 2. [Data Structures & Entities](#data-structures--entities) 3. [Base URL & Service Info](#base-url--service-info) 4. [Authentication Endpoints](#authentication-endpoints) 5. [User Management](#user-management) 6. [Deck Management](#deck-management) 7. [Organization Management](#organization-management) 8. [Chat System](#chat-system) 9. [Contact Management](#contact-management) 10. [Import/Export Functionality](#importexport-functionality) 11. [Admin Endpoints](#admin-endpoints) 12. [Error Handling](#error-handling) 13. [WebSocket Real-Time Communication](#websocket-real-time-communication) --- ## Test User Credentials For development and testing, use these pre-configured user accounts: ### Regular User (Verified) - **Username:** `john_doe` - **Password:** `password123` - **Email:** `john.doe@email.com` - **Type:** Regular user (state: 1 - VERIFIED_REGULAR) - **Organization:** None ### Premium User (Organization Member) - **Username:** `jane_premium` - **Password:** `password123` - **Email:** `jane.smith@email.com` - **Type:** Premium user (state: 2 - VERIFIED_PREMIUM) - **Organization:** Tech Solutions Inc ### Teacher (Premium Organization Member) - **Username:** `teacher_bob` - **Password:** `password123` - **Email:** `bob.teacher@eduinst.edu` - **Type:** Premium user (state: 2 - VERIFIED_PREMIUM) - **Organization:** Educational Institute ### Admin User - **Username:** `admin_user` - **Password:** `password123` - **Email:** `admin@serpentrace.com` - **Type:** Admin (state: 5 - ADMIN) - **Organization:** None ### Unverified User - **Username:** `new_user` - **Password:** `password123` - **Email:** `newuser@email.com` - **Type:** Unverified (state: 0 - REGISTERED_NOT_VERIFIED) - **Organization:** None --- ## Data Structures & Entities ### User DTOs ```typescript interface ShortUserDto { id: string; // UUID username: string; // Username state: number; // UserState enum authLevel: 0 | 1; // 0 = regular, 1 = admin } interface DetailUserDto { id: string; // UUID orgid: string | null; // Organization ID (if member) username: string; // Unique username email: string; // Email address fname: string; // First name lname: string; // Last name code: string | null; // Verification code type: string; // 'personal' | 'premium' | 'admin' phone: string | null; // Phone number state: number; // UserState enum value } enum UserState { REGISTERED_NOT_VERIFIED = 0, // Email not verified VERIFIED_REGULAR = 1, // Regular verified user VERIFIED_PREMIUM = 2, // Premium verified user SOFT_DELETE = 3, // Soft deleted DEACTIVATED = 4, // Account deactivated ADMIN = 5 // Admin user } ``` ### Deck DTOs ```typescript interface ShortDeckDto { id: string; // UUID name: string; // Deck name type: number; // DeckType enum value playedNumber: number; // Times played ctype: number; // DeckVisibility enum value } interface DetailDeckDto { id: string; // UUID name: string; // Deck name type: number; // DeckType enum value userid: string; // Owner's user ID creationdate: Date; // Creation timestamp cards: Card[]; // Array of cards playedNumber: number; // Times played ctype: number; // DeckVisibility enum value } interface Card { text: string; // Question/prompt text type?: number; // CardType enum (optional) answer?: string | null; // Answer (varies by type) } enum DeckType { LUCK = 0, // Luck-based cards JOKER = 1, // Joker/wild cards QUESTION = 2 // Question-based cards } enum DeckVisibility { PUBLIC = 0, // Public to all PRIVATE = 1, // Private to owner ORGANIZATION = 2 // Shared within organization } enum DeckState { ACTIVE = 0, // Active deck SOFT_DELETE = 1 // Soft deleted } enum CardType { QUIZ = 0, // Multiple choice question SENTENCE_PAIRING = 1, // Sentence completion OWN_ANSWER = 2, // Custom answer TRUE_FALSE = 3, // True/False question CLOSER = 4 // Closer to answer } ``` ### Organization DTOs ```typescript interface ShortOrganizationDto { id: string; // UUID name: string; // Organization name contactfname: string; // Contact first name contactlname: string; // Contact last name contactemail: string; // Contact email state: number; // OrganizationState enum regdate: Date; // Registration date maxOrganizationalDecks: number | null; // Max org decks allowed } enum OrganizationState { REGISTERED = 0, // Just registered ACTIVE = 1, // Active organization SOFT_DELETE = 2 // Soft deleted } ``` ### Chat DTOs ```typescript interface ShortChatDto { id: string; // UUID userCount: number; // Number of participants state: number; // ChatState enum value } interface DetailChatDto { id: string; // UUID users: string[]; // Participant user IDs messages: Message[]; // Message history updateDate: Date; // Last update state: number; // ChatState enum value } interface Message { id: string; // Message UUID date: Date; // Message timestamp userid: string; // Sender user ID text: string; // Message content } enum ChatType { DIRECT = 'direct', // Direct message GROUP = 'group', // Group chat GAME = 'game' // Game-specific chat } enum ChatState { ACTIVE = 0, // Active chat ARCHIVE = 1, // Archived chat SOFT_DELETE = 2 // Soft deleted } ``` ### Contact DTOs ```typescript interface ContactDto { id: string; // UUID name: string; // Contact name email: string; // Contact email userid: string | null; // User ID if logged in type: number; // ContactType enum txt: string; // Message content state: number; // ContactState enum createDate: Date; // Creation date updateDate: Date; // Last update adminResponse: string | null; // Admin response responseDate: Date | null; // Response date respondedBy: string | null; // Responding admin ID } enum ContactType { BUG = 0, // Bug report PROBLEM = 1, // Problem report QUESTION = 2, // General question SALES = 3, // Sales inquiry OTHER = 4 // Other type } enum ContactState { ACTIVE = 0, // Active/unresolved RESOLVED = 1, // Resolved SOFT_DELETE = 2 // Soft deleted } ``` --- ## Base URL & Service Info **Base URL:** `http://localhost:3000` (development) ### Service Information **Endpoint:** `GET /` **Authentication:** None required **Response Data:** ```typescript { service: "SerpentRace Backend API"; status: "running"; version: "1.0.0"; endpoints: { swagger: "/api-docs"; users: "/api/users"; organizations: "/api/organizations"; decks: "/api/decks"; chats: "/api/chats"; contacts: "/api/contacts"; admin: "/api/admin"; deckImportExport: "/api/deck-import-export"; health: "/health"; }; websocket: { enabled: true; events: string[]; // WebSocket event names }; } ``` ### Health Check **Endpoint:** `GET /health` **Authentication:** None required **Response Data:** ```typescript { status: "healthy" | "unhealthy"; timestamp: string; // ISO timestamp service: "SerpentRace Backend API"; version: "1.0.0"; environment: string; // "development" | "production" database: { connected: boolean; // Database connection status type: string; // Database type }; websocket: { enabled: boolean; // WebSocket status }; uptime: number; // Process uptime in seconds } ``` --- ## Authentication Endpoints ### User Login **Endpoint:** `POST /api/users/login` **Authentication:** None required **Validation Rules:** - `username`: 3-50 characters - `password`: 6-100 characters **Request Data:** ```typescript { username: string; // Username or email password: string; // Password } ``` **Response Data (Success):** ```typescript { token: string; // JWT token (also set as cookie) user: ShortUserDto; // User information organizationName?: string; // Organization name (if member) } ``` **Error Responses:** - `400`: Validation error - `401`: Invalid credentials, unverified email, or account restrictions - `500`: Internal server error ### User Registration **Endpoint:** `POST /api/users/create` **Authentication:** None required **Validation Rules:** - `username`: 3-50 characters, unique - `email`: valid email format, unique - `password`: 6-100 characters **Request Data:** ```typescript { username: string; // Unique username email: string; // Valid email password: string; // Password fname?: string; // First name (optional) lname?: string; // Last name (optional) phone?: string; // Phone number (optional) type?: string; // User type (optional) } ``` **Response Data (Success):** ```typescript { id: string; // User UUID username: string; // Username email: string; // Email regdate: Date; // Registration date } ``` **Error Responses:** - `400`: Validation error - `409`: Username or email already exists - `500`: Internal server error --- ## User Management ### Get User Profile **Endpoint:** `GET /api/users/profile` **Authentication:** Required **Response Data:** `DetailUserDto` ### Update User Profile **Endpoint:** `PATCH /api/users/profile` **Authentication:** Required **Request Data:** Partial `DetailUserDto` fields to update **Response Data:** Updated `DetailUserDto` **Error Responses:** - `400`: Validation error - `404`: User not found - `409`: Email already exists - `500`: Internal server error --- ## Deck Management ### Get Decks (Paginated) - RECOMMENDED **Endpoint:** `GET /api/decks/page/{from}/{to}` **Authentication:** Required **URL Parameters:** - `from`: Start index (0-based, ≥ 0) - `to`: End index (inclusive, ≥ from) **Response Data:** ```typescript { decks: ShortDeckDto[]; // Array of deck summaries totalCount: number; // Total available decks } ``` ### Create Deck **Endpoint:** `POST /api/decks` **Authentication:** Required **Request Data:** ```typescript { name: string; // Deck name (required) type?: number; // DeckType enum (optional) cards?: Card[]; // Initial cards (optional) ctype?: number; // DeckVisibility enum (optional) } ``` **Response Data:** `ShortDeckDto` ### Search Decks **Endpoint:** `GET /api/decks/search` **Authentication:** Required **Query Parameters:** - `query`: Search query (required, non-empty) - `limit`: Results limit (1-100, default: 20) - `offset`: Results offset (≥ 0, default: 0) **Response Data:** Array of matching `ShortDeckDto` ### Get Deck by ID **Endpoint:** `GET /api/decks/{id}` **Authentication:** Required **URL Parameters:** - `id`: Deck UUID **Response Data:** `DetailDeckDto` ### Update Deck **Endpoint:** `PUT /api/decks/{id}` **Authentication:** Required (owner only) **URL Parameters:** - `id`: Deck UUID **Request Data:** Partial `DetailDeckDto` fields to update **Response Data:** Updated `ShortDeckDto` ### Delete Deck (Soft Delete) **Endpoint:** `DELETE /api/decks/{id}` **Authentication:** Required (owner only) **URL Parameters:** - `id`: Deck UUID **Response Data:** ```typescript { success: boolean; // Deletion success status } ``` --- ## Organization Management ### Get Organizations (Paginated) - RECOMMENDED **Endpoint:** `GET /api/organizations/page/{from}/{to}` **Authentication:** Required **URL Parameters:** - `from`: Start index (0-based, ≥ 0) - `to`: End index (inclusive, ≥ from) **Response Data:** ```typescript { organizations: ShortOrganizationDto[]; totalCount: number; } ``` ### Search Organizations **Endpoint:** `GET /api/organizations/search` **Authentication:** Required **Query Parameters:** - `query`: Search query (required, non-empty) - `limit`: Results limit (1-100, default: 20) - `offset`: Results offset (≥ 0, default: 0) **Response Data:** Array of matching organizations ### Get Organization Login URL **Endpoint:** `GET /api/organizations/{orgId}/login-url` **Authentication:** Required **URL Parameters:** - `orgId`: Organization UUID **Response Data:** ```typescript { loginUrl: string; // Organization login URL organizationName: string; // Organization name } ``` ### Process Organization Auth Callback **Endpoint:** `POST /api/organizations/auth-callback` **Authentication:** Required **Request Data:** ```typescript { organizationId: string; // Organization UUID status: "ok" | "not_ok"; // Authentication status authToken?: string; // Authentication token (optional) } ``` **Response Data:** ```typescript { success: boolean; // Processing success message: string; // Result message updatedFields?: string[]; // Fields that were updated } ``` --- ## Chat System ### Get User Chats **Endpoint:** `GET /api/chats/user-chats` **Authentication:** Required **Query Parameters:** - `includeArchived`: boolean (default: false) **Response Data:** Array of `ShortChatDto` ### Get Chat History **Endpoint:** `GET /api/chats/history/{chatId}` **Authentication:** Required **URL Parameters:** - `chatId`: Chat UUID (validated) **Response Data:** ```typescript { id: string; // Chat UUID users: string[]; // Participants messages: Message[]; // Message history isArchived: boolean; // Archive status state: number; // Chat state } ``` ### Create Chat **Endpoint:** `POST /api/chats/create` **Authentication:** Required **Validation Rules:** - `type`: must be 'direct' or 'group' - `userIds`: non-empty array - `name`: required for groups **Request Data:** ```typescript { type: 'direct' | 'group'; // Chat type userIds: string[]; // Participant user IDs name?: string; // Group name (required for groups) } ``` **Response Data:** ```typescript { id: string; // Chat UUID type: ChatType; // Chat type name: string | null; // Chat name users: string[]; // Participants messages: Message[]; // Empty initially } ``` ### Send Message (REST - for testing) **Endpoint:** `POST /api/chats/message` **Authentication:** Required **Validation Rules:** - `chatId`: valid UUID - `message`: 1-2000 characters **Request Data:** ```typescript { chatId: string; // Chat UUID message: string; // Message content } ``` **Response Data:** `Message` object ### Archive Chat **Endpoint:** `POST /api/chats/archive/{chatId}` **Authentication:** Required **URL Parameters:** - `chatId`: Chat UUID (validated) **Response Data:** ```typescript { success: boolean; message: string; } ``` ### Restore Chat from Archive **Endpoint:** `POST /api/chats/restore/{chatId}` **Authentication:** Required **URL Parameters:** - `chatId`: Chat UUID (validated) **Response Data:** ```typescript { success: boolean; message: string; } ``` ### Get Archived Game Chats **Endpoint:** `GET /api/chats/archived/game/{gameId}` **Authentication:** Required **URL Parameters:** - `gameId`: Game UUID (validated) **Response Data:** Array of archived chat objects --- ## Contact Management ### Create Contact **Endpoint:** `POST /api/contact` **Authentication:** Optional **Validation Rules:** - `name`, `email`, `type`, `txt`: required fields - `type`: must be 0-4 (ContactType enum) **Request Data:** ```typescript { name: string; // Contact name (required) email: string; // Contact email (required) type: ContactType; // Contact type (0-4) txt: string; // Message content (required) } ``` **Response Data:** `ContactDto` **Error Responses:** - `400`: Missing fields or invalid contact type - `500`: Internal server error --- ## Import/Export Functionality ### Export Deck **Endpoint:** `GET /api/deck-import-export/export/{deckId}` **Authentication:** Required (deck owner only) **URL Parameters:** - `deckId`: Deck UUID **Response:** Binary .spr file download **Headers:** - `Content-Type`: `application/octet-stream` - `Content-Disposition`: `attachment; filename="deckname.spr"` ### Import Deck **Endpoint:** `POST /api/deck-import-export/import` **Authentication:** Required **Request:** Multipart form data - `file`: .spr or JSON file (max 10MB) **Response Data:** ```typescript { success: boolean; message: string; deckId: string; // Created deck ID } ``` --- ## Admin Endpoints All admin endpoints require authentication with admin role (UserState.ADMIN = 5). ### User Management (Admin) #### Get Users (Paginated) - RECOMMENDED **Endpoint:** `GET /api/admin/users/page/{from}/{to}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **URL Parameters:** - `from`: Start index (0-based) - `to`: End index (inclusive, max page size: 100) **Response Data:** ```typescript { users: DetailUserDto[]; // Array of detailed user objects pagination: { from: number; // Start index to: number; // End index returned: number; // Actual returned count totalCount: number; // Total user count includeDeleted: boolean; // Include deleted flag }; } ``` #### Get User by ID (Admin) **Endpoint:** `GET /api/admin/users/{userId}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** `DetailUserDto` or null #### Search Users (Admin) **Endpoint:** `GET /api/admin/users/search/{searchTerm}` **URL Parameters:** - `searchTerm`: Search term (2-100 characters) **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** Array of matching users #### Update User (Admin) **Endpoint:** `PATCH /api/admin/users/{userId}` **Request Data:** Partial user fields to update **Response Data:** Updated `DetailUserDto` #### Deactivate User (Admin) **Endpoint:** `POST /api/admin/users/{userId}/deactivate` **Response Data:** ```typescript { message: string; user: DetailUserDto; } ``` #### Delete User (Admin) **Endpoint:** `DELETE /api/admin/users/{userId}` **Response Data:** ```typescript { message: string; } ``` ### Deck Management (Admin) #### Get Decks (Paginated, Admin) **Endpoint:** `GET /api/admin/decks/page/{from}/{to}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** Same as regular deck pagination but unrestricted #### Get Deck by ID (Admin) **Endpoint:** `GET /api/admin/decks/{id}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** `DetailDeckDto` #### Search Decks (Admin) **Endpoint:** `GET /api/admin/decks/search/{searchTerm}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** Array of matching decks #### Hard Delete Deck (Admin) **Endpoint:** `DELETE /api/admin/decks/{id}/hard` **Response Data:** ```typescript { success: boolean; } ``` ### Organization Management (Admin) #### Create Organization (Admin) **Endpoint:** `POST /api/admin/organizations` **Request Data:** Organization creation data **Response Data:** Created organization object #### Update Organization (Admin) **Endpoint:** `PATCH /api/admin/organizations/{id}` **Request Data:** Partial organization fields to update **Response Data:** Updated organization object #### Get Organizations (Paginated, Admin) **Endpoint:** `GET /api/admin/organizations/page/{from}/{to}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** Organization pagination with unrestricted access #### Get Organization by ID (Admin) **Endpoint:** `GET /api/admin/organizations/{id}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** Organization object #### Search Organizations (Admin) **Endpoint:** `GET /api/admin/organizations/search/{searchTerm}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** Array of matching organizations #### Soft Delete Organization (Admin) **Endpoint:** `DELETE /api/admin/organizations/{id}` **Response Data:** ```typescript { success: boolean; } ``` #### Hard Delete Organization (Admin) **Endpoint:** `DELETE /api/admin/organizations/{id}/hard` **Response Data:** ```typescript { success: boolean; } ``` ### Chat Management (Admin) #### Get Chats (Paginated, Admin) **Endpoint:** `GET /api/admin/chats/page/{from}/{to}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** ```typescript { chats: DetailChatDto[]; pagination: { from: number; to: number; returned: number; totalCount: number; includeDeleted: boolean; }; } ``` #### Get Chat by ID (Admin) **Endpoint:** `GET /api/admin/chats/{id}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** `DetailChatDto` ### Contact Management (Admin) #### Get Contacts (Paginated, Admin) **Endpoint:** `GET /api/admin/contacts/page/{from}/{to}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** Contact pagination with full access #### Get Contact by ID (Admin) **Endpoint:** `GET /api/admin/contacts/{id}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** `ContactDto` #### Search Contacts (Admin) **Endpoint:** `GET /api/admin/contacts/search/{searchTerm}` **Query Parameters:** - `includeDeleted`: boolean (default: false) **Response Data:** Array of matching contacts #### Respond to Contact (Admin) **Endpoint:** `PUT /api/admin/contacts/{id}/respond` **Request Data:** ```typescript { adminResponse: string; // Admin response (required) sendEmail?: boolean; // Send email to contact (optional) language?: string; // Response language (optional) } ``` **Response Data:** ```typescript { success: boolean; message: string; contact: ContactDto; emailSent: boolean; emailError: string | null; } ``` #### Resend Contact Email (Admin) **Endpoint:** `POST /api/admin/contacts/{id}/resend-email` **Request Data:** ```typescript { language?: string; // Email language (optional) } ``` **Response Data:** ```typescript { success: boolean; message: string; } ``` #### Soft Delete Contact (Admin) **Endpoint:** `DELETE /api/admin/contacts/{id}` **Response Data:** ```typescript { success: boolean; } ``` #### Hard Delete Contact (Admin) **Endpoint:** `DELETE /api/admin/contacts/{id}/hard` **Response Data:** ```typescript { success: boolean; } ``` ### Import/Export (Admin) #### Import Deck from JSON (Admin) **Endpoint:** `POST /api/admin/decks/import` **Request:** Multipart form data - `file`: JSON file (max 10MB) **Response Data:** ```typescript { success: boolean; message: string; deckId: string; } ``` #### Export Deck as JSON (Admin) **Endpoint:** `GET /api/admin/decks/{deckId}/export` **Response:** JSON file download **Headers:** - `Content-Type`: `application/json` - `Content-Disposition`: `attachment; filename="deckname.json"` --- ## Error Handling ### Standard Error Response Format ```typescript { error: string; // Error message details?: string; // Additional details (development only) timestamp?: string; // Error timestamp } ``` ### HTTP Status Codes - `200` - Success - `201` - Created - `204` - No Content - `400` - Bad Request (validation error) - `401` - Unauthorized (authentication required) - `403` - Forbidden (insufficient permissions) - `404` - Not Found - `409` - Conflict (duplicate data) - `500` - Internal Server Error - `503` - Service Unavailable ### Common Error Scenarios **Authentication Errors:** ```typescript // Missing or invalid token { error: "Authentication required" } // Account state restrictions { error: "Please verify your email address" } { error: "Account has been deactivated" } // Admin access required { error: "Admin access required" } ``` **Validation Errors:** ```typescript // Missing required fields { error: "Missing required fields: username, password" } // Invalid field length { error: "Username must be between 3 and 50 characters" } // Invalid parameters { error: "Invalid page parameters. \"from\" and \"to\" must be valid numbers with to >= from >= 0" } // Invalid file type { error: "Only JSON and .spr files are allowed" } ``` **Business Logic Errors:** ```typescript // Ownership restrictions { error: "Access denied - you can only export your own decks" } // Feature restrictions { error: "Premium subscription required to create groups" } // Duplicate data { error: "Deck with this name already exists" } { error: "Username or email already exists" } ``` --- ## WebSocket Real-Time Communication ### Connection & Authentication Connect to WebSocket server with JWT authentication: ```typescript import io from 'socket.io-client'; // Option 1: JWT token in auth const socket = io('http://localhost:3000', { auth: { token: 'your-jwt-token' } }); // Option 2: Cookie authentication const socket = io('http://localhost:3000', { withCredentials: true }); ``` ### Connection Events ```typescript // Connection successful socket.on('connect', () => { console.log('Connected to WebSocket server'); }); // Authentication failed socket.on('connect_error', (error) => { console.error('Connection failed:', error.message); }); // Disconnected socket.on('disconnect', (reason) => { console.log('Disconnected:', reason); }); // General errors socket.on('error', (error: { message: string }) => { console.error('WebSocket error:', error.message); }); ``` ### Chat Management Events **Initial Chat List:** ```typescript // Automatically sent on connection socket.on('chats:list', (chats: Array<{ id: string; type: ChatType; name: string | null; users: string[]; lastActivity: Date | null; isArchived: boolean; }>) => { // Update chat list in UI }); ``` **Join/Leave Chat:** ```typescript // Join a chat room socket.emit('chat:join', { chatId: 'chat-uuid' }); // Confirmation of joining socket.on('chat:joined', (data: { chatId: string; messages: Message[]; users: string[]; }) => { // Load chat messages }); // Leave a chat room socket.emit('chat:leave', { chatId: 'chat-uuid' }); // Confirmation of leaving socket.on('chat:left', (data: { chatId: string }) => { // Update UI }); ``` ### Real-time Messaging **Send/Receive Messages:** ```typescript // Send message socket.emit('message:send', { chatId: 'chat-uuid', message: 'Hello everyone!' }); // Receive message socket.on('message:received', (data: { chatId: string; message: Message; senderInfo?: { username: string; fname: string; lname: string; }; }) => { // Add message to chat UI }); // Message sent confirmation socket.on('message:sent', (data: { chatId: string; messageId: string; timestamp: Date; }) => { // Update UI }); ``` **Rate Limiting:** 100 messages per user per minute ### Chat Creation Events **Create Group Chat (Premium Only):** ```typescript // Create group socket.emit('group:create', { name: 'Study Group', userIds: ['user-uuid-1', 'user-uuid-2'] }); // Group created socket.on('group:created', (data: { chat: { id: string; type: 'group'; name: string; users: string[]; createdBy: string; }; }) => { // Add to chat list }); // Creation failed socket.on('group:creation:failed', (data: { error: string; }) => { // Show error }); ``` **Create Direct Chat:** ```typescript // Create or get direct chat socket.emit('chat:direct', { targetUserId: 'user-uuid' }); // Chat created socket.on('chat:direct:created', (data: { chat: { id: string; type: 'direct'; users: string[]; }; }) => { // Add to list }); // Chat already exists socket.on('chat:direct:exists', (data: { chatId: string; }) => { // Navigate to existing chat }); ``` **Create Game Chat:** ```typescript // Create game chat socket.emit('game:chat:create', { gameId: 'game-uuid', gameName: 'Quiz Game #123', playerIds: ['player-uuid-1', 'player-uuid-2'] }); // Game chat created socket.on('game:chat:created', (data: { chat: { id: string; type: 'game'; name: string; gameId: string; users: string[]; }; }) => { // Show game chat }); ``` ### Chat History Management **Get Chat History:** ```typescript // Request full history socket.emit('chat:history', { chatId: 'chat-uuid' }); // Receive active chat history socket.on('chat:history', (data: { chatId: string; messages: Message[]; users: string[]; type: ChatType; name: string | null; }) => { // Display full history }); // Receive archived chat history socket.on('chat:history:archived', (data: { chatId: string; messages: Message[]; isGameChat: boolean; archiveDate: Date; }) => { // Display as read-only }); ``` ### Message Retention Rules - **All chats**: Messages older than 2 weeks are deleted - **Direct & Game chats**: Max 10 messages per user (FIFO) - **Group chats**: Time limit only (no per-user limit) - **Archive**: Inactive chats (30 minutes) are archived - **Cleanup**: Archived messages cleaned after 4 weeks ### Complete Implementation Example ```typescript // hooks/useWebSocket.ts import { useEffect, useRef, useState } from 'react'; import io, { Socket } from 'socket.io-client'; export const useWebSocket = (token: string | null) => { const socketRef = useRef(null); const [isConnected, setIsConnected] = useState(false); const [chats, setChats] = useState([]); useEffect(() => { if (!token) return; socketRef.current = io('http://localhost:3000', { auth: { token }, withCredentials: true }); const socket = socketRef.current; socket.on('connect', () => setIsConnected(true)); socket.on('connect_error', () => setIsConnected(false)); socket.on('disconnect', () => setIsConnected(false)); socket.on('chats:list', (chatList) => { setChats(chatList); }); socket.on('message:received', (data) => { setChats(prev => prev.map(chat => chat.id === data.chatId ? { ...chat, messages: [...chat.messages, data.message] } : chat )); }); return () => { socket.disconnect(); }; }, [token]); const sendMessage = (chatId: string, message: string) => { socketRef.current?.emit('message:send', { chatId, message }); }; const joinChat = (chatId: string) => { socketRef.current?.emit('chat:join', { chatId }); }; const createDirectChat = (targetUserId: string) => { socketRef.current?.emit('chat:direct', { targetUserId }); }; const createGroup = (name: string, userIds: string[]) => { socketRef.current?.emit('group:create', { name, userIds }); }; return { socket: socketRef.current, isConnected, chats, sendMessage, joinChat, createDirectChat, createGroup }; }; ``` --- This documentation provides a complete reference for all 50+ endpoints available in the SerpentRace backend API, with accurate data structures, validation rules, and implementation examples derived directly from the TypeScript source code.