# Development Guide This guide covers development workflows, coding standards, and contribution guidelines for the Discord Teto Bot project. ## ๐Ÿ› ๏ธ Development Environment Setup ### Prerequisites - **Node.js**: Version 20.0.0 or higher - **Docker**: Version 20.10+ with Docker Compose v2+ - **Git**: For version control - **Text Editor**: VS Code recommended with extensions: - ES6 String HTML - Docker - JavaScript (ES6) code snippets - Prettier - Code formatter ### Initial Setup 1. **Clone and Install** ```bash git clone cd discord_teto npm install ``` 2. **Environment Configuration** ```bash # Create .env file cp .env.example .env # Edit with your Discord token export USER_TOKEN="your_discord_user_token" ``` 3. **Development Container** ```bash # Start development environment docker compose -f docker-compose.dev.yml up --build # Or with live reload docker compose -f docker-compose.dev.yml up --build --watch ``` ## ๐Ÿ—๏ธ Project Structure ### Directory Organization ``` discord_teto/ โ”œโ”€โ”€ src/ โ”‚ โ”œโ”€โ”€ config/ # Configuration files โ”‚ โ”‚ โ””โ”€โ”€ videoConfig.js โ”‚ โ”œโ”€โ”€ events/ # Discord event handlers โ”‚ โ”‚ โ””โ”€โ”€ messageCreate.js โ”‚ โ”œโ”€โ”€ services/ # Business logic services โ”‚ โ”‚ โ”œโ”€โ”€ videoRecording.js โ”‚ โ”‚ โ””โ”€โ”€ commandHandler.js โ”‚ โ””โ”€โ”€ utils/ # Utility functions (future) โ”œโ”€โ”€ docs/ # Documentation โ”œโ”€โ”€ output/ # Recording output (gitignored) โ”œโ”€โ”€ test/ # Test files โ””โ”€โ”€ docker-compose*.yml # Container configurations ``` ### File Naming Conventions - **Services**: camelCase (e.g., `videoRecording.js`) - **Events**: camelCase matching Discord.js events - **Config**: camelCase with descriptive names - **Documentation**: kebab-case (e.g., `video-recording.md`) ## ๐Ÿ“ Coding Standards ### JavaScript Style Guide **ES6+ Features**: - Use ES6 modules (`import/export`) - Arrow functions for short functions - Template literals for string interpolation - Destructuring for object/array access - Async/await over Promises **Code Style**: ```javascript // Good: Consistent naming and structure export class VideoRecordingService { constructor() { this.outputDir = VIDEO_CONFIG.OUTPUT_DIR; this.activeRecordings = new Map(); } async startRecording({ client, voiceChannel, user, textChannel }) { try { // Implementation here return { success: true, message: 'Recording started' }; } catch (error) { console.error('Recording error:', error); return { success: false, error: error.message }; } } } // Good: Consistent error handling const result = await videoService.startRecording(options); if (!result.success) { return handleError(result.error); } ``` ### Configuration Management **Centralized Configuration**: ```javascript // In config/videoConfig.js export const VIDEO_CONFIG = { // Group related settings RECORDING_SETTINGS: { AUTO_STOP_TIMEOUT: 30_000, MAX_DURATION: 300_000 }, // Use descriptive names ERROR_MESSAGES: { NO_VOICE_CHANNEL: 'You need to be in a voice channel to record!', ALREADY_RECORDING: 'Already recording in this channel!' } }; // Usage in services import { VIDEO_CONFIG } from '../config/videoConfig.js'; ``` ### Error Handling Patterns **Service Layer Errors**: ```javascript // Return structured error objects async function serviceMethod() { try { const result = await dangerousOperation(); return { success: true, data: result }; } catch (error) { console.error('Service error:', error); return { success: false, error: error.message, code: 'SERVICE_ERROR' }; } } ``` **Command Handler Errors**: ```javascript // Graceful user-facing error handling execute: async (msg, context) => { try { const result = await service.performAction(); if (!result.success) { msg.channel.send(result.error || 'Something went wrong!'); return null; } return { action: { message: 'Success!', icon: 'โœ…' } }; } catch (error) { console.error('Command error:', error); msg.channel.send('An error occurred while processing your command.'); return null; } } ``` ## ๐Ÿงฉ Architecture Patterns ### Service Layer Pattern **Services should be**: - Stateless where possible - Have single responsibilities - Return consistent response formats - Handle their own errors gracefully ```javascript class ExampleService { // Good: Clear method signatures async performAction(requiredParam, options = {}) { // Validate inputs if (!requiredParam) { return { success: false, error: 'Required parameter missing' }; } // Perform action try { const result = await this._internalMethod(requiredParam, options); return { success: true, data: result }; } catch (error) { return { success: false, error: error.message }; } } // Good: Private methods prefixed with underscore _internalMethod(param, options) { // Implementation details } } ``` ### Command Pattern **Commands should**: - Have clear trigger conditions - Return standardized action objects - Handle permissions and validation - Provide helpful error messages ```javascript this.commands.set('example_command', { // Clear trigger logic trigger: (msg) => { return msg.content.toLowerCase().startsWith('example') && msg.member?.voice?.channel; }, // Consistent execution pattern execute: async (msg, context) => { // Validate preconditions if (!this._validateCommand(msg, context)) { return null; } // Execute business logic const result = await service.performAction(msg.author.id); // Handle result if (result.success) { msg.channel.send('Command successful!'); return { action: { message: `Command executed by ${msg.author.tag}`, channel: `#${msg.channel.name}`, icon: 'โœ…' } }; } else { msg.channel.send(result.error); return null; } } }); ``` ## ๐Ÿงช Testing Strategy ### Test Structure ``` test/ โ”œโ”€โ”€ unit/ โ”‚ โ”œโ”€โ”€ services/ โ”‚ โ”‚ โ”œโ”€โ”€ videoRecording.test.js โ”‚ โ”‚ โ””โ”€โ”€ commandHandler.test.js โ”‚ โ””โ”€โ”€ config/ โ”‚ โ””โ”€โ”€ videoConfig.test.js โ”œโ”€โ”€ integration/ โ”‚ โ””โ”€โ”€ recording.test.js โ””โ”€โ”€ fixtures/ โ””โ”€โ”€ mockData.js ``` ### Unit Testing Example ```javascript // test/unit/services/videoRecording.test.js import { describe, it, expect, beforeEach, afterEach } from 'node:test'; import { VideoRecordingService } from '../../../src/services/videoRecording.js'; describe('VideoRecordingService', () => { let service; beforeEach(() => { service = new VideoRecordingService(); }); describe('startRecording', () => { it('should return error when already recording', async () => { // Setup const mockOptions = { voiceChannel: { id: 'test-channel' } }; service.activeRecordings.set('test-channel', {}); // Execute const result = await service.startRecording(mockOptions); // Assert expect(result.success).toBe(false); expect(result.message).toContain('Already recording'); }); }); }); ``` ### Integration Testing ```javascript // test/integration/recording.test.js import { describe, it, expect } from 'node:test'; import { setupTestBot, cleanupTestBot } from '../fixtures/testBot.js'; describe('Recording Integration', () => { let testBot; beforeEach(async () => { testBot = await setupTestBot(); }); afterEach(async () => { await cleanupTestBot(testBot); }); it('should complete full recording workflow', async () => { // Test full workflow from command to file output const result = await testBot.executeCommand('xbox record that'); expect(result.success).toBe(true); // Verify file creation const files = await testBot.getOutputFiles(); expect(files.length).toBeGreaterThan(0); }); }); ``` ## ๐Ÿš€ Development Workflow ### Branch Strategy ```bash # Feature development git checkout -b feature/new-command git checkout -b feature/improve-recording git checkout -b bugfix/voice-connection # Release preparation git checkout -b release/v2.1.0 # Hotfixes git checkout -b hotfix/critical-bug ``` ### Development Process 1. **Create Feature Branch** ```bash git checkout -b feature/my-feature ``` 2. **Develop with Hot Reload** ```bash # Start development environment docker compose -f docker-compose.dev.yml up --build # Code changes automatically restart bot ``` 3. **Test Changes** ```bash # Run unit tests npm test # Run integration tests npm run test:integration # Test in Discord manually ``` 4. **Code Review Preparation** ```bash # Format code npm run format # Lint code npm run lint # Check types (if using TypeScript) npm run type-check ``` ### Adding New Commands 1. **Define Command Logic** ```javascript // In src/services/commandHandler.js this.commands.set('new_command', { trigger: (msg) => msg.content.toLowerCase() === 'new command', execute: async (msg, context) => { // Implementation return { action: { message: 'Command executed', icon: '๐Ÿ†•' } }; } }); ``` 2. **Add Configuration** ```javascript // In src/config/videoConfig.js MESSAGES: { NEW_COMMAND_SUCCESS: 'New command executed successfully!', NEW_COMMAND_ERROR: 'Failed to execute new command.' } ``` 3. **Update Documentation** ```markdown ### `new command` **Description**: Description of what the command does. **Usage**: `new command` **Requirements**: Any special requirements. ``` 4. **Add Tests** ```javascript // In test/unit/services/commandHandler.test.js describe('new_command', () => { it('should execute successfully', async () => { // Test implementation }); }); ``` ### Adding New Services 1. **Create Service File** ```javascript // src/services/newService.js class NewService { constructor() { // Initialize service } async performAction(params) { // Service logic return { success: true, data: result }; } } export const newService = new NewService(); export default newService; ``` 2. **Register with System** ```javascript // Import in relevant files import newService from '../services/newService.js'; ``` 3. **Add Configuration** ```javascript // Add to config/videoConfig.js or create new config file ``` ## ๐Ÿ“Š Performance Considerations ### Resource Management **Memory Management**: ```javascript // Good: Clean up resources class RecordingService { async stopRecording(id) { const recording = this.activeRecordings.get(id); if (recording) { // Clean up streams recording.videoStream?.destroy(); recording.connectionStream?.destroy(); recording.connection?.disconnect(); // Remove from memory this.activeRecordings.delete(id); } } } ``` **CPU Optimization**: ```javascript // Good: Use appropriate FFmpeg settings const FFMPEG_SETTINGS = { video: { preset: 'ultrafast', // Lower CPU usage crf: 23, // Balance quality/performance } }; ``` ### Docker Performance **Development Optimization**: ```yaml # docker-compose.dev.yml services: teto_ai: volumes: - ./src:/opt/bot/src:ro # Read-only mount for security environment: - NODE_ENV=development deploy: resources: limits: memory: 2G cpus: '2.0' ``` ## ๐Ÿ” Debugging ### Development Debugging **Enable Debug Logging**: ```bash # Set debug environment export DEBUG=discord*,bot* # Start with debug info docker compose -f docker-compose.dev.yml up --build ``` **Console Debugging**: ```javascript // Good: Structured logging console.log('[VideoService] Starting recording for user:', userId); console.error('[VideoService] Recording failed:', error.message); // Good: Debug information if (process.env.NODE_ENV === 'development') { console.debug('[VideoService] Recording state:', { activeRecordings: this.activeRecordings.size, voiceChannelId, timestamp: Date.now() }); } ``` ### Container Debugging ```bash # Access running container docker exec -it teto_ai bash # Check processes ps aux | grep node # Check network connectivity curl -s https://discord.com/api/v10/gateway # Monitor resources top df -h ``` ## ๐Ÿ“š Documentation Standards ### Code Documentation **JSDoc Comments**: ```javascript /** * Start recording video in a voice channel * @param {Object} options - Recording options * @param {Client} options.client - Discord client instance * @param {VoiceChannel} options.voiceChannel - Target voice channel * @param {User} options.user - User to record * @param {TextChannel} options.textChannel - Channel for notifications * @returns {Promise} Recording result with success status */ async startRecording({ client, voiceChannel, user, textChannel }) { // Implementation } ``` **README Updates**: - Update command tables when adding new commands - Document configuration changes - Include usage examples for new features - Update troubleshooting section for known issues ## ๐Ÿšข Deployment Preparation ### Pre-deployment Checklist - [ ] All tests passing - [ ] No console errors in production mode - [ ] Environment variables documented - [ ] Docker containers build successfully - [ ] Documentation updated - [ ] Performance tested with expected load - [ ] Security review completed ### Production Build ```bash # Build production image docker compose build --no-cache # Test production image docker compose up -d docker compose logs -f # Verify functionality # Test all commands manually ``` ## ๐Ÿค Contributing Guidelines ### Pull Request Process 1. **Fork and Branch** 2. **Follow Coding Standards** 3. **Add Tests** for new functionality 4. **Update Documentation** 5. **Test Thoroughly** 6. **Submit PR** with clear description ### Code Review Checklist **Functionality**: - [ ] Code works as intended - [ ] Edge cases handled - [ ] Error handling implemented - [ ] Performance considerations addressed **Code Quality**: - [ ] Follows project conventions - [ ] Properly commented - [ ] No console.log in production code - [ ] Consistent naming **Testing**: - [ ] Unit tests added/updated - [ ] Integration tests pass - [ ] Manual testing completed **Documentation**: - [ ] README updated if needed - [ ] API documentation updated - [ ] Comments added for complex logic This development guide should help you contribute effectively to the Discord Teto Bot project. For specific technical details, refer to the [architecture documentation](architecture.md).