diff --git a/.doc/Application_Specification.md b/.doc/Application_Specification.md new file mode 100644 index 0000000..0d84ca7 --- /dev/null +++ b/.doc/Application_Specification.md @@ -0,0 +1,1930 @@ +*** +# SIDEL ScriptsManager - Multi-Language Script Manager Application Specification + +## Overview +A Python Flask web application for Linux environments that automatically discovers and executes scripts from a backend directory structure. The SIDEL ScriptsManager provides user management, multi-language support, dark/light mode themes, SIDEL corporate branding, and advanced script metadata management with automatic header parsing and web interface lifecycle management. + +## Basic Concepts + +### Script Architecture +Each script in SIDEL ScriptsManager follows a standardized architecture pattern: + +1. **Individual Flask Servers**: Every script runs its own Flask server instance +2. **Port Management**: SIDEL ScriptsManager assigns unique ports to each script instance +3. **Parameter Injection**: Scripts receive essential parameters from SIDEL ScriptsManager: + - **Data Directory**: Path to persistent data storage for the script + - **User Level**: Current user's permission level (`admin`, `developer`, `operator`, `viewer`) + - **Flask Port**: Assigned port number for the script's web interface + - **Project ID**: Current project identifier for data isolation + - **Project Name**: Human-readable project name for display purposes + - **Theme**: Current user's selected theme (`light`, `dark`) + - **Language**: Current user's selected language (`en`, `es`, `it`, `fr`) +4. **SIDEL Branding Integration**: Scripts receive SIDEL logo path and must display corporate branding +5. **Consistent User Experience**: All script interfaces maintain SIDEL visual identity, theme, and language + +### Data Persistence Architecture +``` +data/ +├── script_groups/ +│ ├── group1/ +│ │ ├── user1/ +│ │ │ ├── project_default/ +│ │ │ │ ├── config.json +│ │ │ │ ├── settings.json +│ │ │ │ └── custom_data.json +│ │ │ └── project_alpha/ +│ │ │ ├── config.json +│ │ │ └── results.json +│ │ └── user2/ +│ │ └── project_default/ +│ │ └── config.json +│ └── group2/ +│ └── user1/ +│ └── project_beta/ +│ └── workflow.json +├── logs/ +│ ├── executions/ +│ │ ├── user1/ +│ │ │ ├── 2025-09-12/ +│ │ │ │ ├── execution_abc123.log +│ │ │ │ ├── execution_def456.log +│ │ │ │ └── execution_ghi789.log +│ │ │ └── 2025-09-11/ +│ │ │ └── execution_jkl012.log +│ │ └── user2/ +│ │ └── 2025-09-12/ +│ │ └── execution_mno345.log +│ ├── system/ +│ │ ├── application.log +│ │ ├── error.log +│ │ └── access.log +│ └── audit/ +│ ├── user_actions.log +│ └── admin_actions.log +``` + +### Multi-User & Multi-Project Management +- **User Isolation**: Each user maintains separate configuration and data files +- **Project Segregation**: Users can work on multiple projects with independent settings +- **Default Project**: Every user automatically gets a `project_default` for immediate use +- **Port Allocation**: Dynamic port assignment prevents conflicts between users and scripts + +### Script Lifecycle +1. **Initialization**: ScriptsManager discovers and registers the script +2. **Execution Request**: User requests script execution through ScriptsManager interface +3. **Parameter Injection**: ScriptsManager passes data directory, user level, and port +4. **Flask Startup**: Script starts its own Flask server on assigned port +5. **Interface Opening**: ScriptsManager opens browser tab to script's interface +6. **Session Management**: Script maintains user session and project context +7. **Log Generation**: Comprehensive logging throughout script execution with user context +8. **Graceful Shutdown**: Script terminates when tab is closed or session expires + +### User-Centric Logging Architecture +- **User Isolation**: Each user can only access their own execution logs +- **Project Context**: Logs are associated with specific user projects for better organization +- **Real-time Streaming**: Live log updates during script execution via WebSocket +- **Persistent Storage**: All execution logs are permanently stored for future reference +- **Comprehensive Capture**: Logs include: + - **Standard Output**: All script output and results + - **Error Output**: Error messages and stack traces + - **Debug Information**: Internal system messages and performance metrics + - **Execution Context**: Parameters, environment, duration, and exit codes + - **Session Metadata**: User, project, script, and interface information +- **Post-Execution Access**: Users can review logs after script completion +- **Retention Management**: Configurable log retention based on user level and storage policies +- **Export Capabilities**: Download logs in multiple formats for external analysis + +## Core Features + +### 1. Automatic Script Discovery +- **Directory Structure**: Scans `app/backend/script_groups/` for script collections +- **⚠️ Important**: Scripts must be located ONLY in `app/backend/script_groups/` - there should be NO separate `backend/script_groups/` directory +- **Metadata Support**: Reads JSON configuration files for script descriptions and parameters +- **Header Parsing**: Automatically extracts script metadata from file headers on first discovery +- **Dynamic Loading**: Automatically detects new scripts without application restart +- **File Types**: Supports Python scripts (.py) +- **Conda Environment Management**: Each script group can use a different conda environment +- **Environment Auto-Detection**: Automatically detects available conda environments on Windows/Linux +- **Script Metadata Editing**: Developers and administrators can edit script descriptions and execution levels +- **Web Interface Management**: Automatically manages Flask server lifecycle for each script + +### 2. User Management & Access Control +- **User Levels**: + - `admin`: Full access to all scripts, user management, and script metadata editing + - `developer`: Access to development and testing scripts, script metadata editing capabilities + - `operator`: Access to production and operational scripts + - `viewer`: Read-only access to logs and documentation +- **Authentication**: Simple login system with session management +- **Permission System**: Script-level permissions based on user roles + +### 3. Multi-Language Support +- **Primary Language**: English (default) +- **Supported Languages**: + - Spanish (es) + - Italian (it) + - French (fr) +- **Translation Files**: JSON-based language files in `translations/` directory +- **Dynamic Switching**: Language can be changed without logout + +### 4. User Interface +- **Theme Support**: Light/Dark mode toggle with user preference persistence +- **Responsive Design**: Bootstrap-based responsive layout +- **Real-time Updates**: WebSocket integration for live log streaming +- **Modern UI**: Clean, intuitive interface with icons and visual feedback +- **Script Metadata Editor**: Inline editing capabilities for script descriptions and execution levels (developer+) +- **Web Interface Lifecycle**: Automatic management of script Flask servers with tab monitoring + +## Technical Architecture + +### ⚠️ Directory Structure Clarification +**IMPORTANT**: All scripts must be located in `app/backend/script_groups/` only. There should be NO separate `backend/script_groups/` directory at the root level. + +**Correct Structure:** +- ✅ `app/backend/script_groups/` - Contains all script groups and scripts +- ❌ `backend/script_groups/` - Should NOT exist + +**Rationale**: This ensures a clean separation of concerns and prevents confusion between the application backend and the scripts directory. + +### Backend Structure +``` +app/ +├── app.py # Main Flask application +├── config/ +│ ├── config.py # Application configuration +│ ├── database.py # Database models and setup +│ └── permissions.py # Permission management +├── backend/ +│ └── script_groups/ # Auto-discovered script directories +│ ├── group1/ +│ │ ├── metadata.json # Group description and settings +│ │ ├── script1.py +│ │ ├── script2.sh +│ │ ├── docs/ # Markdown documentation files +│ │ │ ├── script1.md +│ │ │ ├── script1_es.md +│ │ │ ├── script1_it.md +│ │ │ └── script1_fr.md +│ │ └── scripts/ +│ │ └── script_metadata.json +│ └── group2/ +│ ├── metadata.json +│ └── scripts/ +├── translations/ +│ ├── en.json # English (default) +│ ├── es.json # Spanish +│ ├── it.json # Italian +│ └── fr.json # French +├── static/ +│ ├── css/ +│ │ ├── main.css +│ │ ├── themes.css # Light/dark themes +│ │ ├── responsive.css +│ │ └── markdown-viewer.css # Markdown styling +│ ├── js/ +│ │ ├── main.js +│ │ ├── websocket.js # Real-time log updates +│ │ ├── theme-manager.js # Theme switching +│ │ ├── language-manager.js # Language switching +│ │ ├── markdown-viewer.js # Markdown rendering +│ │ └── markdown-editor.js # Markdown editing +│ ├── images/ +│ │ └── SIDEL.png # SIDEL corporate logo +│ └── icons/ +├── templates/ +│ ├── base.html # Base template with theme/language support +│ ├── login.html # Authentication +│ ├── dashboard.html # Main script discovery interface +│ ├── script_group.html # Individual group view +│ ├── logs.html # User log viewer with filtering and search +│ ├── log_detail.html # Detailed log view for specific execution +│ └── admin/ +│ ├── users.html # User management +│ ├── permissions.html # Permission management +│ └── system_logs.html # System-wide log management (admin only) +├── models/ +│ ├── user.py # User model +│ ├── script.py # Script metadata model +│ └── execution_log.py # Enhanced execution log model with user context +├── services/ +│ ├── script_discovery.py # Auto-discovery service with header parsing +│ ├── script_executor.py # Script execution service with comprehensive logging +│ ├── user_service.py # User management +│ ├── translation_service.py # Multi-language support +│ ├── conda_service.py # Conda environment management +│ ├── metadata_service.py # Script metadata management and editing +│ ├── web_interface_manager.py # Flask server lifecycle management +│ ├── data_manager.py # Data persistence and project management +│ ├── port_manager.py # Port allocation and management +│ ├── markdown_service.py # Markdown processing and editing +│ ├── log_service.py # User-centric log management service +│ ├── websocket_service.py # Real-time log streaming service +│ ├── tags_service.py # User tags management +│ └── backup_service.py # System backup management +└── utils/ + ├── permissions.py # Permission decorators + ├── validators.py # Input validation + └── helpers.py # Utility functions +``` + +### Database Schema +```sql +-- Users table +CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(100) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + user_level VARCHAR(20) NOT NULL, + preferred_language VARCHAR(5) DEFAULT 'en', + preferred_theme VARCHAR(10) DEFAULT 'light', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_login TIMESTAMP, + is_active BOOLEAN DEFAULT TRUE +); + +-- Script groups table +CREATE TABLE script_groups ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR(100) NOT NULL, + directory_path VARCHAR(255) NOT NULL, + description TEXT, + required_level VARCHAR(20) NOT NULL, + conda_environment VARCHAR(100), + is_active BOOLEAN DEFAULT TRUE, + discovered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Scripts table +CREATE TABLE scripts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + group_id INTEGER REFERENCES script_groups(id), + filename VARCHAR(100) NOT NULL, + display_name VARCHAR(100), + description TEXT, + description_long_path VARCHAR(255), + tags TEXT, -- Comma-separated tags + required_level VARCHAR(20) NOT NULL, + parameters JSON, + is_active BOOLEAN DEFAULT TRUE, + last_modified TIMESTAMP +); + +-- User script tags table (for user-specific tagging) +CREATE TABLE user_script_tags ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER REFERENCES users(id), + script_id INTEGER REFERENCES scripts(id), + tags TEXT, -- Comma-separated user-specific tags + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(user_id, script_id) +); + +-- Conda environments table +CREATE TABLE conda_environments ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR(100) UNIQUE NOT NULL, + path VARCHAR(255) NOT NULL, + python_version VARCHAR(20), + is_available BOOLEAN DEFAULT TRUE, + detected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_verified TIMESTAMP +); + +-- User projects table +CREATE TABLE user_projects ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER REFERENCES users(id), + project_name VARCHAR(100) NOT NULL, + group_id INTEGER REFERENCES script_groups(id), + description TEXT, + is_default BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_accessed TIMESTAMP, + UNIQUE(user_id, project_name, group_id) +); + +-- Port allocations table +CREATE TABLE port_allocations ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + port_number INTEGER UNIQUE NOT NULL, + script_id INTEGER REFERENCES scripts(id), + user_id INTEGER REFERENCES users(id), + project_id INTEGER REFERENCES user_projects(id), + process_id INTEGER, + status VARCHAR(20) NOT NULL, -- 'allocated', 'active', 'released' + allocated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + released_at TIMESTAMP +); + +-- Script execution processes table +CREATE TABLE script_processes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + script_id INTEGER REFERENCES scripts(id), + user_id INTEGER REFERENCES users(id), + process_id INTEGER NOT NULL, + flask_port INTEGER, + tab_session_id VARCHAR(100), + status VARCHAR(20) NOT NULL, + started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_ping TIMESTAMP, + ended_at TIMESTAMP +); + +-- Execution logs table (User-centric logging) +CREATE TABLE execution_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + script_id INTEGER REFERENCES scripts(id), + user_id INTEGER REFERENCES users(id), + project_id INTEGER REFERENCES user_projects(id), + session_id VARCHAR(100), -- Links to script interface session + execution_uuid VARCHAR(36) UNIQUE NOT NULL, -- Unique execution identifier + status VARCHAR(20) NOT NULL, -- 'running', 'completed', 'failed', 'terminated' + start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + end_time TIMESTAMP, + duration_seconds INTEGER, + output TEXT, -- Standard output from script execution + error_output TEXT, -- Error output from script execution + debug_output TEXT, -- Debug information and internal logs + exit_code INTEGER, + parameters JSON, -- Execution parameters for reference + conda_environment VARCHAR(100), -- Environment used for execution + flask_port INTEGER, -- Port used for script interface + log_level VARCHAR(10) DEFAULT 'INFO', -- DEBUG, INFO, WARNING, ERROR + tags TEXT, -- Comma-separated tags for log categorization + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +## JSON Configuration Files + +### Script Header Format for Auto-Discovery +```python +""" +ScriptsManager Metadata: +@description: Creates a complete system backup with compression options +@description_long: docs/backup_system.md +@description_es: Crea una copia de seguridad completa del sistema con opciones de compresión +@description_long_es: docs/backup_system_es.md +@description_it: Crea un backup completo del sistema con opzioni di compressione +@description_long_it: docs/backup_system_it.md +@description_fr: Crée une sauvegarde complète du système avec options de compression +@description_long_fr: docs/backup_system_fr.md +@required_level: admin +@category: backup +@tags: system,maintenance,storage +@parameters: [ + { + "name": "destination", + "type": "path", + "required": true, + "description": "Backup destination directory" + }, + { + "name": "compression", + "type": "select", + "options": ["none", "gzip", "bzip2"], + "default": "gzip" + } +] +@execution_timeout: 3600 +@flask_port: 5200 +""" +# Your script code here... +``` + +### Group Metadata (metadata.json) +```json +{ + "name": "System Administration", + "description": { + "en": "System administration and maintenance scripts", + "es": "Scripts de administración y mantenimiento del sistema", + "it": "Script di amministrazione e manutenzione del sistema", + "fr": "Scripts d'administration et de maintenance du système" + }, + "icon": "server", + "required_level": "operator", + "category": "system", + "conda_environment": "base", + "auto_discovery": true, + "execution_timeout": 300 +} +``` + +### Script Metadata (script_metadata.json) +```json +{ + "backup_system.py": { + "display_name": { + "en": "System Backup", + "es": "Copia de Seguridad del Sistema", + "it": "Backup del Sistema", + "fr": "Sauvegarde du Système" + }, + "description": { + "en": "Creates a complete system backup", + "es": "Crea una copia de seguridad completa del sistema", + "it": "Crea un backup completo del sistema", + "fr": "Crée une sauvegarde complète du système" + }, + "description_long": { + "en": "docs/backup_system.md", + "es": "docs/backup_system_es.md", + "it": "docs/backup_system_it.md", + "fr": "docs/backup_system_fr.md" + }, + "tags": ["system", "maintenance", "storage"], + "required_level": "admin", + "category": "backup", + "parameters": [ + { + "name": "destination", + "type": "path", + "required": true, + "description": { + "en": "Backup destination directory", + "es": "Directorio de destino de la copia", + "it": "Directory di destinazione del backup", + "fr": "Répertoire de destination de la sauvegarde" + } + }, + { + "name": "compression", + "type": "select", + "options": ["none", "gzip", "bzip2"], + "default": "gzip", + "description": { + "en": "Compression method", + "es": "Método de compresión", + "it": "Metodo di compressione", + "fr": "Méthode de compression" + } + } + ], + "execution_timeout": 3600, + "flask_port": 5200, + "auto_open_interface": true, + "requires_parameters": true + } +} +``` + +## API Endpoints + +### Authentication +- `POST /api/auth/login` - User login +- `POST /api/auth/logout` - User logout +- `GET /api/auth/user` - Get current user info + +### Script Discovery & Management +- `GET /api/script-groups` - List all discovered script groups +- `GET /api/script-groups/{group_id}/scripts` - List scripts in group +- `POST /api/scripts/{script_id}/execute` - Execute script +- `GET /api/scripts/{script_id}/status` - Get script execution status +- `POST /api/scripts/{script_id}/stop` - Stop running script +- `GET /api/scripts/{script_id}/metadata` - Get script metadata +- `PUT /api/scripts/{script_id}/metadata` - Update script metadata (developer+) +- `POST /api/scripts/{script_id}/refresh-metadata` - Re-parse script header +- `GET /api/script-groups/{group_id}/refresh` - Refresh all scripts in group + +### Conda Environment Management +- `GET /api/conda/environments` - List all available conda environments +- `POST /api/conda/refresh` - Refresh conda environment detection +- `GET /api/conda/environments/{env_name}/info` - Get environment details +- `POST /api/script-groups/{group_id}/conda` - Set conda environment for group + +### User Management (Admin only) +- `GET /api/admin/users` - List all users +- `POST /api/admin/users` - Create new user +- `PUT /api/admin/users/{user_id}` - Update user +- `DELETE /api/admin/users/{user_id}` - Delete user +- `GET /api/admin/users/{user_id}/projects` - Get user's projects +- `POST /api/admin/users/{user_id}/reset-data` - Reset user's data directories + +### Project Management +- `GET /api/projects` - List current user's projects +- `POST /api/projects` - Create new project for current user +- `PUT /api/projects/{project_id}` - Update project details +- `DELETE /api/projects/{project_id}` - Delete project and associated data +- `POST /api/projects/{project_id}/set-active` - Set active project for session +- `GET /api/projects/active` - Get current active project + +### Data Management +- `GET /api/data/{group_id}/{project_id}/files` - List data files for project +- `GET /api/data/{group_id}/{project_id}/{filename}` - Get specific data file +- `POST /api/data/{group_id}/{project_id}/{filename}` - Create/Update data file +- `DELETE /api/data/{group_id}/{project_id}/{filename}` - Delete data file +- `POST /api/data/{group_id}/{project_id}/backup` - Create project data backup + +### Script Documentation & Tags +- `GET /api/scripts/{script_id}/description-long` - Get script long description (Markdown) +- `PUT /api/scripts/{script_id}/description-long` - Update script long description (developer+) +- `GET /api/scripts/{script_id}/tags` - Get script tags +- `PUT /api/scripts/{script_id}/tags` - Update user-specific script tags +- `GET /api/scripts/search-tags` - Search scripts by tags +- `GET /api/user/tags` - Get all user's tags across scripts + +### System Backup +- `POST /api/system/backup` - Create immediate system backup +- `GET /api/system/backups` - List available system backups +- `DELETE /api/system/backups/{backup_date}` - Delete specific backup +- `GET /api/system/backup-status` - Get backup service status + +### Logs & Monitoring (User-Centric) +- `GET /api/logs/execution` - Get current user's execution logs (paginated) +- `GET /api/logs/execution/{execution_id}` - Get specific execution log details +- `GET /api/logs/execution/{execution_id}/download` - Download execution log file +- `GET /api/logs/script/{script_id}` - Get user's logs for specific script +- `GET /api/logs/project/{project_id}` - Get user's logs for specific project +- `GET /api/logs/search` - Search user's logs with filters (script, date, status, text) +- `DELETE /api/logs/execution/{execution_id}` - Delete specific execution log (user owns) +- `POST /api/logs/cleanup` - Clean up old logs based on retention policy +- `GET /api/logs/stats` - Get user's logging statistics and usage +- `WebSocket /ws/logs/{execution_id}` - Real-time log streaming for specific execution +- `WebSocket /ws/logs/user` - Real-time log streaming for all user executions + +### Admin Logs & Monitoring (Admin only) +- `GET /api/admin/logs/execution` - Get all users' execution logs +- `GET /api/admin/logs/system` - Get system-wide logs +- `GET /api/admin/logs/user/{user_id}` - Get specific user's logs +- `DELETE /api/admin/logs/user/{user_id}` - Delete all logs for specific user +- `GET /api/admin/logs/audit` - Get system audit logs +- `POST /api/admin/logs/export` - Export system logs in various formats + +### Web Interface Management +- `POST /api/scripts/{script_id}/open-interface` - Open script web interface +- `GET /api/scripts/{script_id}/interface-status` - Check interface status +- `POST /api/scripts/{script_id}/ping-interface` - Ping from tab to keep alive +- `POST /api/scripts/{script_id}/close-interface` - Close script interface +- `GET /api/active-interfaces` - List all active script interfaces + +### Internationalization +- `GET /api/i18n/languages` - Get available languages +- `GET /api/i18n/{language}` - Get translations for language +- `POST /api/user/preferences` - Update user preferences + +## Features Implementation + +### 1. Script Auto-Discovery Service with Header Parsing +```python +# Pseudo-code for auto-discovery with header parsing +class ScriptDiscoveryService: + def scan_script_groups(self): + # Scan app/backend/script_groups/ directory + # Read metadata.json files + # Detect script files + # Parse script headers for metadata on first discovery + # Update database with discovered scripts + # Handle permission assignments + # Validate conda environment assignments + + def parse_script_header(self, script_path): + # Extract metadata from script comments/docstrings + # Parse description, required_level, parameters + # Return structured metadata + + def watch_for_changes(self): + # File system watcher for real-time discovery + # Hot-reload capability + # Re-parse headers when files change +``` + +### 2. Conda Environment Service +```python +# Pseudo-code for conda management +class CondaService: + def detect_environments(self): + # Scan for conda installations (Windows/Linux) + # Parse conda environment list + # Validate environment availability + # Update database with environment info + + def get_environment_info(self, env_name): + # Get Python version and packages + # Verify environment is functional + # Return environment details + + def execute_in_environment(self, env_name, command, args): + # Activate conda environment + # Execute command with proper environment + # Handle cross-platform differences +``` + +### 3. Script Execution Service with Multi-User Support +```python +# Pseudo-code for script execution with multi-user management +class ScriptExecutor: + def execute_script(self, script_id, parameters, user_id, project_id=None): + # Validate user permissions + # Get or create user project (default if none specified) + # Get user preferences (theme, language) + # Allocate unique port for user/script combination + # Get script group conda environment + # Prepare execution environment with conda + # Create user-specific data directory + # Handle parameter injection including: + # - Data directory path + # - User level + # - Flask port + # - Project ID + # - Project name + # - Theme preference + # - Language preference + # Start Flask server for script interface + # Register process with port and user info + # Open new browser tab with user session + # Execute with timeout in specified environment + # Stream output via WebSocket + # Log execution details with user context + # Monitor tab session for closure + + def start_script_with_params(self, script_path, data_dir, user_level, port, project_id, project_name, theme, language): + # Execute script with standardized parameters: + # python script.py --data-dir {data_dir} --user-level {user_level} --port {port} --project-id {project_id} --project-name {project_name} --theme {theme} --language {language} + + def manage_multi_user_interface(self, script_id, user_id, project_id, port): + # Start Flask server process with user context including theme and language + # Register in active interfaces with user/project info + # Monitor user-specific tab session + # Handle graceful shutdown maintaining user data +``` +``` + +### 4. Multi-Language Support +```python +# Pseudo-code for translations +class TranslationService: + def get_translation(self, key, language='en'): + # Load translation file for language + # Return translated string + # Fall back to English if not found + + def get_user_language(self, user): + # Return user's preferred language +``` + +### 5. Script Metadata Management Service +```python +# Pseudo-code for metadata management +class MetadataService: + def update_script_metadata(self, script_id, metadata, user): + # Validate user permissions (developer+) + # Update script description, required_level, etc. + # Maintain version history + # Validate required_level values + + def parse_and_update_from_header(self, script_id): + # Re-parse script file header + # Update metadata from parsed content + # Preserve user-edited fields + + def get_editable_fields(self, user_level): + # Return list of fields user can edit + # Based on permission level +``` + +### 6. Web Interface Manager Service +```python +# Pseudo-code for web interface lifecycle +class WebInterfaceManager: + def start_script_interface(self, script_id, user_id): + # Allocate port from available pool + # Start Flask process for script + # Register in active interfaces table + # Generate session ID for tab tracking + # Return interface URL and session ID + + def monitor_tab_session(self, session_id): + # Monitor tab heartbeat via JavaScript + # Detect tab closure + # Trigger graceful script shutdown + + def cleanup_inactive_interfaces(self): + # Periodic cleanup of orphaned processes + # Check for unresponsive tabs + # Terminate associated script processes + + def get_available_port(self): + # Find available port in configured range + # Avoid conflicts with existing interfaces + # Return available port number + +### 8. Data Management Service +```python +# Pseudo-code for data persistence management +class DataManager: + def __init__(self, base_data_path): + self.base_path = base_data_path + + def get_user_project_path(self, user_id, group_id, project_name): + # Returns: data/script_groups/group_{group_id}/user_{user_id}/{project_name}/ + return os.path.join( + self.base_path, + "script_groups", + f"group_{group_id}", + f"user_{user_id}", + project_name + ) + + def ensure_project_directory(self, user_id, group_id, project_name): + # Create directory structure if it doesn't exist + # Initialize default configuration files + # Set proper permissions + + def get_config_file(self, user_id, group_id, project_name, filename): + # Load JSON configuration file + # Return parsed data or default values + + def save_config_file(self, user_id, group_id, project_name, filename, data): + # Save JSON data to configuration file + # Validate data structure + # Handle concurrent access + + def list_user_projects(self, user_id, group_id): + # List all projects for user in specific group + # Return project metadata + + def create_default_project(self, user_id, group_id): + # Create 'project_default' for new users + # Initialize with default settings + + def backup_project_data(self, user_id, group_id, project_name): + # Create timestamped backup of project data + # Compress and store in backups directory +``` + +### 9. Port Management Service +```python +# Pseudo-code for port allocation management +class PortManager: + def __init__(self, port_range_start=5200, port_range_end=5400): + self.port_range = range(port_range_start, port_range_end + 1) + self.allocated_ports = set() + + def allocate_port(self, script_id, user_id, project_id): + # Find available port in range (5200+) + # Verify port is not in use by system before allocation + # Mark as allocated in database + # Return port number or None if none available + + def release_port(self, port_number): + # Mark port as released + # Clean up database entry + # Add back to available pool + + def get_active_ports(self): + # Return list of currently active ports + # With associated script/user information + + def cleanup_orphaned_ports(self): + # Release ports from terminated processes + # Clean up stale allocations + + def is_port_available(self, port_number): + # Check if specific port is available + # Validate against system and allocated ports + # Verify port is not currently bound to any process + + def check_system_port_usage(self, port_number): + # Use system tools to verify port availability + # Check for any existing bindings on the port + # Return True if port is free for use + +## Port Management Architecture + +### Port Range Allocation +- **Reserved Range**: Ports 5200-5400 are exclusively reserved for script Flask interfaces +- **System Protection**: Ports below 5200 remain available for system services and main application +- **Dynamic Assignment**: Ports are allocated dynamically based on availability +- **Conflict Prevention**: Each allocation is verified against system port usage + +### Port Availability Verification +The system implements comprehensive port checking before allocation: + +1. **Database Check**: Verify port is not already allocated to another script +2. **System Check**: Use system tools to confirm port is not in use +3. **Binding Test**: Attempt temporary binding to confirm availability +4. **Retry Logic**: If port is unavailable, try next available port in range + +### Port Lifecycle Management +- **Allocation**: Port assigned when script interface starts +- **Monitoring**: Regular health checks to ensure script is still running +- **Cleanup**: Automatic release when script terminates or tab closes +- **Recovery**: Orphaned port detection and automatic cleanup + +```python +# Enhanced port checking implementation +import socket +import subprocess +import psutil + +def is_port_available(port): + """Comprehensive port availability check""" + # Check if port is in our allocated range + if port < 5200 or port > 5400: + return False + + # Try to bind to the port + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(1) + result = sock.connect_ex(('127.0.0.1', port)) + return result != 0 # Port is available if connection fails + except Exception: + return False + +def find_available_port(start_port=5200, end_port=5400): + """Find first available port in range""" + for port in range(start_port, end_port + 1): + if is_port_available(port): + return port + return None # No available ports +``` +``` + +### 11. Markdown Processing Service +```python +# Pseudo-code for markdown management +class MarkdownService: + def __init__(self, script_groups_path): + self.base_path = script_groups_path + + def get_script_long_description(self, script_id, language='en'): + # Get script metadata and long description path + # Load markdown file for specified language + # Return markdown content or fallback to English + + def update_script_long_description(self, script_id, markdown_content, language='en'): + # Validate user permissions (developer+) + # Save markdown content to appropriate file + # Update script metadata with new path + + def render_markdown_to_html(self, markdown_content): + # Convert markdown to HTML + # Apply syntax highlighting for code blocks + # Handle mathematical formulas if needed + # Return rendered HTML + + def get_available_languages_for_script(self, script_id): + # Return list of available language versions + # Check for existing markdown files +``` + +### 12. User Tags Service +```python +# Pseudo-code for user tags management +class TagsService: + def get_user_script_tags(self, user_id, script_id): + # Get user-specific tags for a script + # Return list of tags + + def update_user_script_tags(self, user_id, script_id, tags): + # Update user-specific tags for a script + # Validate and clean tag format + # Save to database + + def search_scripts_by_tags(self, user_id, tags, match_all=False): + # Search scripts by user tags + # match_all: True for AND operation, False for OR + # Return list of matching script IDs + + def get_all_user_tags(self, user_id): + # Get all unique tags used by user + # Return sorted list of tags with usage count + + def get_script_system_tags(self, script_id): + # Get system-defined tags from script metadata + # Return list of system tags + + def merge_script_tags(self, user_id, script_id): + # Combine system tags and user tags + # Return unified tag list with source indication +``` + +### 13. System Backup Service +```python +# Pseudo-code for system backup management +class BackupService: + def __init__(self, data_path, backup_path): + self.data_path = data_path + self.backup_path = backup_path + + def create_daily_backup(self): + # Create compressed backup of entire /data/ directory + # Use current date as backup name: /backup/2025-09-11/ + # Compress using gzip or zip + # Clean up old backups based on retention policy + + def schedule_daily_backup(self): + # Set up automatic daily backup at configured time + # Use threading.Timer or scheduling library + # Handle backup rotation and cleanup + + def list_available_backups(self): + # Return list of available backup dates + # Include backup size and creation time + + def delete_backup(self, backup_date): + # Delete specific backup by date + # Validate backup exists before deletion + + def get_backup_status(self): + # Return current backup service status + # Include last backup time, next scheduled backup + # Disk usage information + + def restore_from_backup(self, backup_date, target_path=None): + # Restore data from specific backup + # Optional: restore to different location + # Admin-only operation + +### 14. Log Management Service +```python +# Pseudo-code for user-centric log management +class LogService: + def __init__(self, base_log_path, database): + self.base_path = base_log_path + self.db = database + + def create_execution_log(self, script_id, user_id, project_id, session_id): + # Create new execution log entry in database + # Generate unique execution UUID + # Set up log file path: logs/executions/user_{user_id}/YYYY-MM-DD/execution_{uuid}.log + # Return execution log ID and file path + + def log_execution_start(self, execution_id, parameters, conda_env, port): + # Log execution start with full context + # Record parameters, environment, and execution setup + # Start real-time log streaming setup + + def append_log_output(self, execution_id, output_type, content): + # Append output to log file and database + # output_type: 'stdout', 'stderr', 'debug', 'system' + # Handle real-time streaming to connected WebSocket clients + # Update database with latest output + + def log_execution_end(self, execution_id, exit_code, duration): + # Mark execution as completed + # Calculate final statistics + # Close log file and update database + # Notify connected clients of completion + + def get_user_logs(self, user_id, filters=None, page=1, per_page=50): + # Get paginated list of user's execution logs + # Apply filters: script_id, project_id, date_range, status + # Return logs with metadata (script name, project, duration, etc.) + + def get_execution_log_detail(self, execution_id, user_id): + # Get detailed log information for specific execution + # Validate user owns the log + # Return full log content and metadata + + def search_user_logs(self, user_id, search_query, filters=None): + # Full-text search across user's log content + # Search in output, parameters, and metadata + # Return matching executions with highlighted snippets + + def delete_user_log(self, execution_id, user_id): + # Delete specific execution log (user validation) + # Remove from database and file system + # Update storage statistics + + def export_user_logs(self, user_id, format='json', filters=None): + # Export user's logs in specified format (json, csv, txt) + # Apply optional filters + # Return file path or stream for download + + def cleanup_old_logs(self, retention_days=30): + # Clean up logs older than retention period + # Respect user-level retention policies + # Update storage statistics + + def get_user_log_statistics(self, user_id): + # Return user's logging statistics + # Total executions, success rate, storage usage + # Most used scripts and projects + +### 15. WebSocket Log Streaming Service +```python +# Pseudo-code for real-time log streaming +class WebSocketLogService: + def __init__(self, socketio_instance): + self.socketio = socketio_instance + self.active_connections = {} # execution_id -> [client_sessions] + + def connect_to_execution_log(self, client_session, execution_id, user_id): + # Validate user access to execution log + # Add client to active connections for this execution + # Send initial log content to client + # Set up real-time streaming + + def broadcast_log_update(self, execution_id, log_content, output_type): + # Send log update to all connected clients for this execution + # Format message with timestamp and output type + # Handle client disconnections gracefully + + def disconnect_from_execution_log(self, client_session, execution_id): + # Remove client from active connections + # Clean up resources if no more clients connected + + def connect_to_user_logs(self, client_session, user_id): + # Connect to all active executions for user + # Send updates for any of user's running scripts + # Useful for dashboard real-time updates + + def get_active_connections_count(self, execution_id): + # Return number of clients watching this execution + # Used for resource management decisions +``` +```python +# Pseudo-code for multi-user session handling +class SessionManager: + def create_user_session(self, user_id, active_project_id=None): + # Create session context for user + # Set active project (default if none specified) + # Initialize user-specific settings + + def get_user_context(self, session_id): + # Return user context including: + # - User ID and level + # - Active project + # - Permissions + # - Preferences + + def switch_project(self, session_id, project_id): + # Change active project for session + # Validate user access to project + # Update session context + + def cleanup_inactive_sessions(self): + # Remove expired sessions + # Release associated resources +``` +```python +# Pseudo-code for permissions +def require_permission(required_level): + def decorator(func): + def wrapper(*args, **kwargs): + # Check user authentication + # Validate user level + # Allow or deny access + return wrapper + return decorator + +def can_edit_metadata(user_level): + # Returns True if user can edit script metadata + return user_level in ['developer', 'admin'] +``` + +## Conda Environment Management + +### Environment Detection +- **Automatic Discovery**: Scans system for conda installations +- **Cross-Platform Support**: Works on both Windows and Linux environments +- **Environment Validation**: Verifies each environment is functional +- **Python Version Detection**: Identifies Python version for each environment +- **Package Information**: Optional package listing for environment details + +### Environment Assignment +- **Group-Level Configuration**: Each script group can use a different conda environment +- **Default Environment**: Falls back to 'base' environment if none specified +- **Environment Validation**: Ensures assigned environment exists before script execution +- **Dynamic Updates**: Environment assignments can be changed without restart + +### Execution Integration +- **Seamless Activation**: Scripts execute within their assigned conda environment +- **Cross-Platform Commands**: Handles conda activation differences between Windows/Linux +- **Error Handling**: Graceful fallback if environment becomes unavailable +- **Logging**: Environment activation and execution logged for troubleshooting + +### Management Interface +- **Environment List**: Visual display of all detected conda environments +- **Assignment Interface**: Dropdown selection for script group environment assignment +- **Status Indicators**: Visual indicators for environment availability +- **Refresh Capability**: Manual refresh of environment detection + +## User Interface Components + +### SIDEL Corporate Branding Integration +- **SIDEL Logo**: `app/static/images/SIDEL.png` displayed prominently in application header +- **Corporate Identity**: Consistent SIDEL branding across all pages and script interfaces +- **Logo Propagation**: SIDEL logo passed to script interfaces for consistent branding +- **Responsive Logo**: Logo adapts to different screen sizes and theme modes + +### 1. Dashboard (Multi-User) +- **SIDEL Header**: SIDEL logo and corporate branding in main navigation +- **User Context**: Display current user information and active project +- **Script Group Cards**: Visual representation of script groups with icons +- **Project Selector**: Dropdown to switch between user's projects +- **Quick Actions**: Recently used scripts and favorites (user-specific) +- **System Status**: System health indicators and conda environment status +- **User Info**: Current user, language, theme settings, and active project +- **Environment Selector**: Quick conda environment overview per group +- **Active Sessions**: List of user's currently running script interfaces + +### 2. Script Group View (Project-Aware with Enhanced Documentation) +- **SIDEL Branding**: Consistent SIDEL logo and corporate identity +- **Project Context**: Display current active project at top +- **Script List**: Filterable and searchable script listing with tag filtering +- **Tag Management**: Add/edit user-specific tags for scripts +- **Documentation Viewer**: Integrated Markdown viewer for long descriptions +- **Multi-Language Documentation**: Switch between available language versions +- **Execution Forms**: Dynamic forms based on script parameters +- **Inline Help**: Short descriptions with expandable long descriptions +- **Execution History**: Previous runs for current user/project +- **Environment Info**: Display active conda environment for the group +- **Environment Management**: Change conda environment (admin/developer only) +- **Metadata Editor**: Inline editing for script descriptions and levels (developer+) +- **Markdown Editor**: Edit long descriptions in Markdown format (developer+) +- **Header Re-parsing**: Refresh metadata from script headers +- **Active Interfaces**: List of currently running script web interfaces for user +- **Project Management**: Create, switch, or manage projects (inline controls) + +### 3. Log Viewer (User-Centric) +- **User-Isolated Logs**: Each user can only view their own script execution logs +- **Project-Specific Logs**: Logs are organized by user projects for better context +- **Real-time Logs**: Live log streaming via WebSocket during script execution +- **Post-Execution Logs**: Persistent log storage for reviewing past script executions +- **Execution Status Indicators**: Visual status badges (Running, Completed, Failed, Terminated) +- **Log Filtering & Search**: + - Filter by script name, project, execution date range + - Filter by execution status and duration + - Full-text search across log content and parameters + - Save and reuse filter presets +- **Log List View**: + - Paginated table with execution summary + - Columns: Script Name, Project, Start Time, Duration, Status, Actions + - Sortable by any column + - Quick preview of output and errors +- **Detailed Log View**: + - Full execution log with syntax highlighting + - Tabbed interface: Output, Errors, Debug, Parameters, Environment + - Execution timeline and performance metrics + - Download individual log files +- **Real-time Monitoring**: + - Live updates during script execution + - Progress indicators and execution timeline + - Auto-scroll with pause/resume controls + - Multiple execution monitoring in tabs +- **Export & Management**: + - Download logs in various formats (TXT, JSON, CSV, PDF) + - Bulk operations: select multiple logs for export or deletion + - Log retention settings per user + - Storage usage statistics and cleanup recommendations +- **Integration Features**: + - Quick navigation to script or project from log entry + - Re-run script with same parameters from log + - Share log details with developers (admin only) + - Log bookmarking and notes + +### 4. Admin Panel (Enhanced) +- **User Management**: CRUD operations for users +- **User Data Management**: View and manage user projects and data +- **Permission Matrix**: Visual permission assignment +- **System Configuration**: Application settings +- **Discovery Management**: Manual script discovery triggers +- **Environment Management**: Conda environment detection and assignment +- **Interface Monitoring**: Active script web interfaces management (all users) +- **Metadata Audit**: Track metadata changes +- **Port Allocation**: Monitor and manage port usage across users +- **Data Directory Overview**: System-wide view of user data usage +- **Backup Management**: System backup configuration and monitoring +- **Documentation Management**: Overview of script documentation status + +## Engineering-Focused Features + +### Multi-Language Technical Documentation +- **Markdown Support**: Full Markdown rendering with syntax highlighting for code blocks +- **Multi-Language Documentation**: Support for technical documentation in multiple languages +- **Mathematical Formulas**: Support for LaTeX/MathJax mathematical expressions in documentation +- **Technical Diagrams**: Embedding of diagrams and flowcharts in Markdown +- **Code Examples**: Syntax-highlighted code examples in documentation + +### User-Centric Organization +- **Personal Tagging System**: Each user can tag scripts with custom labels for personal organization +- **Search by Tags**: Quick filtering and searching of scripts using personal tags +- **Algorithm Categorization**: Organize engineering algorithms by domain, complexity, or use case +- **Long-Term Accessibility**: Documentation designed for easy understanding after extended periods + +### Documentation Structure +``` +app/backend/script_groups/thermal_analysis/ +├── metadata.json +├── heat_transfer.py +├── thermal_stress.py +├── docs/ +│ ├── heat_transfer.md # English documentation +│ ├── heat_transfer_es.md # Spanish documentation +│ ├── heat_transfer_it.md # Italian documentation +│ ├── heat_transfer_fr.md # French documentation +│ ├── thermal_stress.md +│ ├── thermal_stress_es.md +│ ├── thermal_stress_it.md +│ └── thermal_stress_fr.md +└── examples/ + ├── heat_exchanger_example.json + └── stress_analysis_case.json +``` + +### Backup and Data Integrity +- **Daily System Backup**: Automatic compression and backup of entire data directory +- **Simple Backup Structure**: `/backup/YYYY-MM-DD/` format for easy manual recovery +- **Data Persistence**: All configurations and results preserved across sessions +- **Project Isolation**: Each engineering project maintains independent configurations + +### Engineering Workflow Integration +- **Parameter Persistence**: Engineering calculations and configurations saved per project +- **Result Documentation**: Integration with script-generated reports and outputs +- **Configuration Templates**: Reusable parameter sets for common engineering scenarios +- **Cross-Reference Documentation**: Link related algorithms and reference implementations + +## System Backup Architecture + +### Backup Directory Structure +``` +backup/ +├── 2025-09-11/ +│ └── data_backup_20250911_020000.tar.gz +├── 2025-09-10/ +│ └── data_backup_20250910_020000.tar.gz +├── 2025-09-09/ +│ └── data_backup_20250909_020000.tar.gz +└── backup_logs/ + ├── backup_20250911.log + ├── backup_20250910.log + └── backup_20250909.log +``` + +### Backup Service Configuration +```json +{ + "backup": { + "enabled": true, + "schedule_time": "02:00", + "retention_days": 30, + "compression": "gzip", + "backup_path": "./backup", + "exclude_patterns": ["*.tmp", "*.log", "__pycache__"], + "max_backup_size_gb": 10 + } +} +``` + +## User-Centric Log Management System + +### Log Organization Structure +- **User-Isolated Storage**: Each user's logs stored separately to ensure privacy +- **Project-Based Organization**: Logs grouped by user projects for better context +- **Date-Based Hierarchy**: Daily directories for efficient log retrieval +- **Unique Execution IDs**: Each script execution gets a UUID for precise tracking + +### Log Content Structure +```json +{ + "execution_id": "abc123-def456-ghi789", + "script_id": 42, + "script_name": "data_analysis.py", + "user_id": 5, + "username": "john_doe", + "project_id": 12, + "project_name": "monthly_reports", + "execution_start": "2025-09-12T10:30:00Z", + "execution_end": "2025-09-12T10:35:30Z", + "duration_seconds": 330, + "status": "completed", + "exit_code": 0, + "parameters": { + "input_file": "data/reports/raw_data.csv", + "output_format": "excel", + "date_range": "2025-09-01_to_2025-09-11" + }, + "environment": { + "conda_env": "data_analysis", + "python_version": "3.11.4", + "flask_port": 5023 + }, + "output": { + "stdout": "Processing 1000 records...\nAnalysis complete.\nReport saved to output/monthly_report_2025-09.xlsx", + "stderr": "", + "debug": "Memory usage: 45MB\nExecution time breakdown: Data loading (2.3s), Processing (4.1s), Export (1.2s)" + }, + "session_info": { + "browser_session": "sess_xyz789", + "interface_url": "http://127.0.0.1:5023", + "real_time_viewers": 1 + } +} +``` + +### Real-time Log Streaming +- **WebSocket Integration**: Live updates during script execution +- **Multiple Viewer Support**: Multiple users can monitor same execution (admin) +- **Selective Streaming**: Choose which output types to stream (stdout, stderr, debug) +- **Bandwidth Optimization**: Compress and buffer log updates for efficiency + +### Log Retention & Cleanup +- **User Level Based Retention**: + - `viewer`: 7 days + - `operator`: 30 days + - `developer`: 90 days + - `admin`: 365 days (configurable) +- **Automatic Cleanup**: Daily maintenance job removes expired logs +- **Manual Management**: Users can delete their own logs before expiration +- **Storage Quotas**: Per-user storage limits with notifications + +### Log Search & Analytics +- **Full-Text Search**: Search across all log content using database indexing +- **Advanced Filters**: Combine multiple criteria (date, script, status, duration) +- **Execution Statistics**: Success rates, average durations, most used scripts +- **Trend Analysis**: Execution patterns and performance trends over time + +### Log Security & Privacy +- **User Isolation**: Strict access control - users see only their own logs +- **Admin Override**: Administrators can access any user's logs for debugging +- **Audit Trail**: Log access events are recorded for security auditing +- **Data Protection**: Sensitive parameters can be masked in log storage + +## Script Standard and Interface Contract + +### Required Script Parameters +Every script must accept the following command-line parameters: + +```bash +python script.py --data-dir --user-level --port --project-id --project-name --theme --language +``` + +**Parameter Details:** +- `--data-dir`: Absolute path to user/project data directory +- `--user-level`: User permission level (`admin`, `developer`, `operator`, `viewer`) +- `--port`: Assigned Flask port number for the script's web interface +- `--project-id`: Current project identifier for data isolation +- `--project-name`: Human-readable project name for display in script frontend +- `--theme`: Current user theme (`light`, `dark`) for consistent UI appearance +- `--language`: Current user language (`en`, `es`, `it`, `fr`) for localized interfaces + +### Script Implementation Template +```python +import argparse +import os +import json +from flask import Flask, render_template, request, jsonify + +def parse_arguments(): + parser = argparse.ArgumentParser(description='SIDEL ScriptsManager Script') + parser.add_argument('--data-dir', required=True, help='Data directory path') + parser.add_argument('--user-level', required=True, choices=['admin', 'developer', 'operator', 'viewer']) + parser.add_argument('--port', type=int, required=True, help='Flask port number') + parser.add_argument('--project-id', required=True, help='Project identifier') + parser.add_argument('--project-name', required=True, help='Project display name') + parser.add_argument('--theme', required=True, choices=['light', 'dark'], help='Current user theme') + parser.add_argument('--language', required=True, choices=['en', 'es', 'it', 'fr'], help='Current user language') + return parser.parse_args() + +class ScriptDataManager: + def __init__(self, data_dir, project_id, project_name): + self.data_dir = data_dir + self.project_id = project_id + self.project_name = project_name + self.ensure_data_structure() + + def ensure_data_structure(self): + """Create data directory structure if it doesn't exist""" + os.makedirs(self.data_dir, exist_ok=True) + + def load_config(self, filename='config.json'): + """Load configuration from JSON file""" + config_path = os.path.join(self.data_dir, filename) + if os.path.exists(config_path): + with open(config_path, 'r') as f: + return json.load(f) + return {} + + def save_config(self, config, filename='config.json'): + """Save configuration to JSON file""" + config_path = os.path.join(self.data_dir, filename) + with open(config_path, 'w') as f: + json.dump(config, f, indent=2) + +def create_flask_app(data_manager, user_level, project_id, project_name, theme, language): + app = Flask(__name__) + + # SIDEL logo path for consistent branding + sidel_logo = '/static/images/SIDEL.png' + + @app.route('/') + def index(): + config = data_manager.load_config() + return render_template('index.html', + config=config, + user_level=user_level, + project_id=project_id, + project_name=project_name, + theme=theme, + language=language, + sidel_logo=sidel_logo) + + @app.route('/api/config', methods=['GET', 'POST']) + def handle_config(): + if request.method == 'GET': + return jsonify(data_manager.load_config()) + else: + config = request.json + data_manager.save_config(config) + return jsonify({'status': 'success'}) + + @app.route('/api/project-info') + def get_project_info(): + return jsonify({ + 'project_id': project_id, + 'project_name': project_name, + 'user_level': user_level, + 'theme': theme, + 'language': language, + 'sidel_logo': sidel_logo + }) + + return app + +if __name__ == '__main__': + args = parse_arguments() + + # Initialize data manager with project information + data_manager = ScriptDataManager(args.data_dir, args.project_id, args.project_name) + + # Create Flask application with SIDEL branding, project context, theme and language + app = create_flask_app(data_manager, args.user_level, args.project_id, args.project_name, args.theme, args.language) + + # Run Flask server + print(f"Starting SIDEL script for project: {args.project_name} (Theme: {args.theme}, Language: {args.language})") + app.run(host='127.0.0.1', port=args.port, debug=False) +``` + +### Data Management Guidelines +1. **Use Provided Data Directory**: Always use the `--data-dir` parameter for persistent storage +2. **JSON Configuration**: Store settings in JSON files for easy management +3. **User Level Awareness**: Adapt interface based on user permission level +4. **Project Isolation**: Use project ID to separate data when needed +5. **Project Display**: Use project name for user-friendly display in interfaces +6. **SIDEL Branding**: Include SIDEL logo and corporate branding in all interfaces +7. **Theme Consistency**: Apply the provided theme (`light`/`dark`) to maintain visual consistency +8. **Language Localization**: Use the provided language parameter for interface localization +9. **Error Handling**: Gracefully handle missing or corrupted data files + +### Flask Interface Requirements +1. **Port Binding**: Must bind to the exact port provided by SIDEL ScriptsManager +2. **Host Restriction**: Bind only to `127.0.0.1` for security +3. **Graceful Shutdown**: Handle SIGTERM for clean shutdown +4. **Session Management**: Maintain user context throughout session +5. **Error Reporting**: Report errors through standard logging +6. **SIDEL Branding**: Include SIDEL logo and consistent visual identity +7. **Project Context**: Display project name prominently in interface +8. **Theme Consistency**: Apply the provided theme (light/dark) throughout the interface +9. **Language Support**: Use the provided language for interface localization and messages + +## Multi-User Data Architecture + +### Data Directory Structure +``` +data/ +├── script_groups/ +│ ├── group_analytics/ +│ │ ├── user_john/ +│ │ │ ├── project_default/ +│ │ │ │ ├── config.json +│ │ │ │ ├── datasets.json +│ │ │ │ └── analysis_results.json +│ │ │ ├── project_monthly_report/ +│ │ │ │ ├── config.json +│ │ │ │ └── report_data.json +│ │ │ └── project_customer_analysis/ +│ │ │ └── config.json +│ │ └── user_mary/ +│ │ ├── project_default/ +│ │ │ └── config.json +│ │ └── project_experimental/ +│ │ ├── config.json +│ │ └── experiments.json +│ └── group_automation/ +│ ├── user_john/ +│ │ └── project_default/ +│ │ ├── workflows.json +│ │ └── schedules.json +│ └── user_admin/ +│ └── project_system_maintenance/ +│ └── maintenance_config.json +├── backups/ +│ ├── user_john_project_monthly_report_20250911_143022.zip +│ └── user_mary_project_experimental_20250910_091545.zip +└── system/ + ├── port_allocations.json + └── active_sessions.json +``` + +### Project Management Workflow +1. **User Login**: ScriptsManager creates user session +2. **Project Selection**: User selects or creates project +3. **Script Execution**: ScriptsManager passes project-specific data directory +4. **Data Persistence**: Script manages its own JSON files within provided directory +5. **Session Continuity**: Project context maintained across script executions +6. **Data Backup**: Automatic and manual backup capabilities + +## Web Interface Lifecycle Management + +### Interface Startup +- **Port Allocation**: Automatically assigns available ports from configured range (5200-5400) +- **Process Registration**: Tracks script processes with PID, port, and session ID +- **Tab Session Tracking**: Generates unique session IDs for browser tab monitoring +- **Automatic Opening**: Opens script interface in new browser tab upon execution + +### Session Monitoring +- **Heartbeat System**: JavaScript in each tab sends periodic pings to maintain session +- **Tab Detection**: Detects when browser tabs are closed or become inactive +- **Process Linking**: Links browser sessions to running script processes +- **Timeout Management**: Configurable timeout for inactive sessions + +### Graceful Shutdown +- **Tab Closure Detection**: Monitors for tab closure events via JavaScript +- **Process Termination**: Gracefully terminates script processes when tabs close +- **Resource Cleanup**: Frees allocated ports and removes database records +- **Orphan Prevention**: Periodic cleanup of abandoned processes + +### Configuration Options +```json +{ + "web_interface": { + "port_range": {"start": 5200, "end": 5400}, + "session_timeout": 1800, + "heartbeat_interval": 30, + "cleanup_interval": 300, + "max_concurrent_interfaces": 20, + "max_interfaces_per_user": 5, + "port_availability_check": true, + "port_check_retries": 3 + }, + "data_management": { + "base_data_path": "./data", + "auto_backup": true, + "backup_interval_hours": 24, + "max_backup_versions": 30, + "compress_backups": true, + "backup_schedule_time": "02:00" + }, + "documentation": { + "markdown_extensions": ["codehilite", "tables", "toc", "math"], + "supported_languages": ["en", "es", "it", "fr"], + "default_language": "en", + "enable_math_rendering": true, + "enable_diagram_rendering": false + }, + "tagging": { + "max_tags_per_script": 20, + "max_tag_length": 30, + "allowed_tag_chars": "alphanumeric_underscore_dash", + "enable_tag_suggestions": true + }, + "multi_user": { + "max_projects_per_user": 50, + "default_project_name": "project_default", + "auto_create_default_project": true, + "user_data_isolation": true + }, + "security": { + "data_directory_permissions": "755", + "config_file_permissions": "644", + "enable_project_sharing": false, + "admin_can_access_all_data": true + } +} +``` + +## Script Metadata Management + +### Header Parsing Rules +- **First Discovery**: Automatically extracts metadata from script docstring/comments +- **Precedence**: User-edited metadata takes precedence over header-parsed data +- **Re-parsing**: Manual refresh option to update from modified headers +- **Validation**: Validates required_level values against allowed user levels + +### Editable Fields (Developer+ Only) +- **Description**: Multi-language script descriptions (short) +- **Long Description**: Multi-language Markdown documentation (long) +- **Required Level**: Minimum user level required for script execution/viewing +- **Category**: Script categorization for filtering and organization +- **System Tags**: Script tags for classification and searching +- **Parameters**: Script parameter definitions and validation rules +- **Execution Settings**: Timeout, conda environment, interface settings + +### Documentation Management +- **Markdown Files**: Automatic creation and management of documentation files +- **Language Versions**: Support for multiple language versions of documentation +- **Template Generation**: Auto-generate documentation templates for new scripts +- **Content Validation**: Basic validation of Markdown syntax and structure + +## Security Considerations + +### 1. Authentication & Authorization +- Secure password hashing (bcrypt) +- Session management with timeout +- CSRF protection +- Input validation and sanitization + +### 2. Script Execution Security +- Sandboxed execution environment +- Resource limits (CPU, memory, time) +- Whitelist of allowed script locations +- Parameter validation and escaping +- Web interface port isolation +- Process monitoring and automatic cleanup + +### 3. Access Control +- Role-based access control (RBAC) +- Principle of least privilege +- Audit logging for all actions +- Secure file path handling +- Metadata editing permissions (developer+ only) +- Web interface session security + +## Installation & Deployment + +### Requirements +- **Python 3.12+** (minimum required version) +- **Operating System**: Linux (primary) with Windows support +- **Conda/Miniconda**: Required for environment management +- **WebSocket support**: For real-time log streaming + +### Database Engine +**SQLite** (Recommended for cross-platform deployment) +- **Rationale**: + - Zero-configuration setup + - Cross-platform compatibility (Linux/Windows) + - Single file database for easy backup + - Built-in Python support + - Sufficient performance for engineering script management + - No additional server requirements +- **File-based storage**: Simplifies deployment and maintenance +- **Automatic backup integration**: Single file backup with system data +- **Migration path**: Can upgrade to PostgreSQL if needed in future + +### Python Dependencies +```bash +# Core Framework +flask>=3.0.0 +flask-sqlalchemy>=3.1.0 +flask-login>=0.6.0 +flask-wtf>=1.2.0 +flask-socketio>=5.3.0 + +# Database +sqlite3 # Built-in with Python 3.12+ + +# Web Server +gunicorn>=21.2.0 # Production WSGI server +eventlet>=0.33.0 # WebSocket support + +# Conda Environment Management +conda-pack>=0.7.0 # Conda environment utilities +subprocess32>=3.5.4 # Enhanced subprocess handling + +# Markdown Processing +markdown>=3.5.0 +markdown-extensions>=0.1.0 +pygments>=2.16.0 # Syntax highlighting + +# File Management & Compression +watchdog>=3.0.0 # File system monitoring +zipfile36>=0.1.0 # Enhanced zip functionality + +# Utilities +pyyaml>=6.0.1 # YAML configuration support +python-dateutil>=2.8.2 # Date/time utilities +psutil>=5.9.0 # Process management +requests>=2.31.0 # HTTP client for health checks + +# Development & Testing (optional) +pytest>=7.4.0 +pytest-flask>=1.3.0 +black>=23.9.0 # Code formatting +flake8>=6.1.0 # Code linting +``` + +### Installation Script +```bash +# Create Python 3.12+ virtual environment +python3.12 -m venv scriptsmanager_env +source scriptsmanager_env/bin/activate # Linux +# scriptsmanager_env\Scripts\activate # Windows + +# Install dependencies +pip install --upgrade pip +pip install -r requirements.txt + +# Initialize database +python init_db.py + +# Create initial admin user +python create_admin.py --username admin --password + +# Start application +python app.py +``` + +### Database Setup +```python +# Database initialization with SQLite +import sqlite3 +import os +from datetime import datetime + +def initialize_database(db_path="data/scriptsmanager.db"): + """Initialize SQLite database with required tables""" + + # Ensure data directory exists + os.makedirs(os.path.dirname(db_path), exist_ok=True) + + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # Create all tables from schema + with open('sql/create_tables.sql', 'r') as f: + schema_sql = f.read() + cursor.executescript(schema_sql) + + # Create default admin user + admin_password = hash_password("admin123") # Change in production + cursor.execute(""" + INSERT OR IGNORE INTO users + (username, email, password_hash, user_level, is_active) + VALUES (?, ?, ?, ?, ?) + """, ("admin", "admin@localhost", admin_password, "admin", True)) + + conn.commit() + conn.close() + print(f"Database initialized at: {db_path}") + +if __name__ == "__main__": + initialize_database() +``` + +### Configuration Management +```python +# config/app_config.py +import os +from pathlib import Path + +class Config: + # Database Configuration + DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///data/scriptsmanager.db') + + # Application Settings + SECRET_KEY = os.getenv('SECRET_KEY', 'your-secret-key-change-in-production') + DEBUG = os.getenv('DEBUG', 'False').lower() == 'true' + + # Multi-user Settings + BASE_DATA_PATH = Path(os.getenv('BASE_DATA_PATH', './data')) + MAX_PROJECTS_PER_USER = int(os.getenv('MAX_PROJECTS_PER_USER', '50')) + + # Port Management + PORT_RANGE_START = int(os.getenv('PORT_RANGE_START', '5200')) + PORT_RANGE_END = int(os.getenv('PORT_RANGE_END', '5400')) + PORT_AVAILABILITY_CHECK = os.getenv('PORT_AVAILABILITY_CHECK', 'True').lower() == 'true' + PORT_CHECK_RETRIES = int(os.getenv('PORT_CHECK_RETRIES', '3')) + + # Backup Configuration + BACKUP_ENABLED = os.getenv('BACKUP_ENABLED', 'True').lower() == 'true' + BACKUP_SCHEDULE_TIME = os.getenv('BACKUP_SCHEDULE_TIME', '02:00') + BACKUP_RETENTION_DAYS = int(os.getenv('BACKUP_RETENTION_DAYS', '30')) + + # Conda Environment + CONDA_AUTO_DETECT = os.getenv('CONDA_AUTO_DETECT', 'True').lower() == 'true' + + # Supported Languages + SUPPORTED_LANGUAGES = ['en', 'es', 'it', 'fr'] + DEFAULT_LANGUAGE = os.getenv('DEFAULT_LANGUAGE', 'en') +``` + +### Conda Environment Detection +```python +# services/conda_service.py +import subprocess +import json +import os +from pathlib import Path + +class CondaService: + def __init__(self): + self.conda_executable = self.find_conda_executable() + + def find_conda_executable(self): + """Find conda executable on Windows/Linux""" + possible_paths = [ + 'conda', + '/opt/conda/bin/conda', + '/usr/local/bin/conda', + os.path.expanduser('~/miniconda3/bin/conda'), + os.path.expanduser('~/anaconda3/bin/conda'), + # Windows paths + r'C:\ProgramData\Miniconda3\Scripts\conda.exe', + r'C:\ProgramData\Anaconda3\Scripts\conda.exe', + os.path.expanduser(r'~\Miniconda3\Scripts\conda.exe'), + os.path.expanduser(r'~\Anaconda3\Scripts\conda.exe'), + ] + + for path in possible_paths: + try: + result = subprocess.run([path, '--version'], + capture_output=True, text=True, timeout=10) + if result.returncode == 0: + return path + except (FileNotFoundError, subprocess.TimeoutExpired): + continue + + raise RuntimeError("Conda executable not found. Please install Miniconda or Anaconda.") + + def list_environments(self): + """List all available conda environments""" + try: + result = subprocess.run([self.conda_executable, 'env', 'list', '--json'], + capture_output=True, text=True, timeout=30) + if result.returncode == 0: + env_data = json.loads(result.stdout) + return env_data.get('envs', []) + except Exception as e: + print(f"Error listing conda environments: {e}") + ### Production Deployment +```bash +# Production deployment with Gunicorn +gunicorn --bind 0.0.0.0:8000 \ + --workers 4 \ + --worker-class eventlet \ + --timeout 300 \ + --keep-alive 30 \ + --access-logfile logs/access.log \ + --error-logfile logs/error.log \ + app:app + +# Systemd service file (Linux) +# /etc/systemd/system/scriptsmanager.service +[Unit] +Description=ScriptsManager Web Application +After=network.target + +[Service] +Type=simple +User=scriptsmanager +Group=scriptsmanager +WorkingDirectory=/opt/scriptsmanager +Environment=PATH=/opt/scriptsmanager/venv/bin +ExecStart=/opt/scriptsmanager/venv/bin/gunicorn --config gunicorn.conf.py app:app +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +``` + +### Development Setup +```bash +# Development environment setup +git clone scriptsmanager +cd scriptsmanager + +# Create virtual environment with Python 3.12+ +python3.12 -m venv venv +source venv/bin/activate # Linux/Mac +# venv\Scripts\activate # Windows + +# Install development dependencies +pip install -r requirements-dev.txt + +# Initialize development database +python scripts/init_dev_db.py + +# Start development server +flask run --debug --host=127.0.0.1 --port=5000 +``` + +### Cross-Platform Considerations +- **Path Handling**: Use `pathlib.Path` for cross-platform file operations +- **Process Management**: Platform-specific conda activation commands +- **Service Installation**: Different approaches for Linux (systemd) vs Windows (Windows Service) +- **File Permissions**: Appropriate permission handling for each OS +- **Environment Variables**: Platform-specific environment variable handling + +### Monitoring & Health Checks +```python +# Health check endpoint +@app.route('/health') +def health_check(): + return { + 'status': 'healthy', + 'timestamp': datetime.utcnow().isoformat(), + 'database': check_database_connection(), + 'conda': check_conda_availability(), + 'active_scripts': get_active_script_count(), + 'port_usage': get_port_allocation_stats() + } +``` +``` + + diff --git a/SIDELManagerScripts/CORRECCIONES_HAMMER_SIMULATOR.md b/.doc/CORRECCIONES_HAMMER_SIMULATOR.md similarity index 100% rename from SIDELManagerScripts/CORRECCIONES_HAMMER_SIMULATOR.md rename to .doc/CORRECCIONES_HAMMER_SIMULATOR.md diff --git a/SIDELManagerScripts/SIDEL_LOGO_IMPLEMENTATION.md b/.doc/SIDEL_LOGO_IMPLEMENTATION.md similarity index 100% rename from SIDELManagerScripts/SIDEL_LOGO_IMPLEMENTATION.md rename to .doc/SIDEL_LOGO_IMPLEMENTATION.md diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c49bddd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,91 @@ +# Docker ignore file para SIDEL Manager Scripts +# Evita copiar archivos innecesarios al contexto de construcción + +# Archivos de desarrollo y temporales +*.pyc +*.pyo +*.pyd +__pycache__/ +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Entornos virtuales +venv/ +ENV/ +env/ +.venv/ + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Archivos de configuración local +.env +.env.local +.env.*.local + +# Logs +*.log +logs/ +*.out + +# Base de datos de desarrollo +*.db +*.sqlite +*.sqlite3 +!data/scriptsmanager.db + +# Backups locales +backup/ +*.tar.gz +*.zip + +# Archivos del sistema +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore + +# Docker +Dockerfile.dev +docker-compose.override.yml + +# Cache de pytest +.pytest_cache/ +.coverage + +# Archivos de Node.js (si los hay) +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Archivos temporales de la aplicación +instance/ +temp/ +tmp/ + +# Certificados SSL (si los hay) +*.pem +*.crt +*.key \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c4d3701 --- /dev/null +++ b/.env.example @@ -0,0 +1,30 @@ +# Variables de entorno para Docker +# Copia este archivo a .env y modifica los valores según tus necesidades + +# Configuración de la aplicación +DEBUG=false +SECRET_KEY=change-this-to-a-secure-random-string-in-production +FLASK_ENV=production + +# Base de datos +DATABASE_URL=sqlite:///app/data/scriptsmanager.db +# Para PostgreSQL (descomenta si usas el perfil postgres): +# DATABASE_URL=postgresql://scriptsmanager:scriptsmanager_password@postgres:5432/scriptsmanager + +# Configuración de datos +BASE_DATA_PATH=/app/data +MAX_PROJECTS_PER_USER=50 + +# Configuración de puertos +PORT_RANGE_START=5200 +PORT_RANGE_END=5400 + +# Backup +BACKUP_ENABLED=true + +# Configuración de conda +CONDA_DEFAULT_ENV=scriptsmanager + +# Configuración de red (opcional) +# EXTERNAL_PORT=5000 +# DEV_EXTERNAL_PORT=5001 \ No newline at end of file diff --git a/SIDELManagerScripts/.gitignore b/.gitignore similarity index 100% rename from SIDELManagerScripts/.gitignore rename to .gitignore diff --git a/SIDELManagerScripts/.playwright-mcp/dashboard-admin-menu.png b/.playwright-mcp/dashboard-admin-menu.png similarity index 100% rename from SIDELManagerScripts/.playwright-mcp/dashboard-admin-menu.png rename to .playwright-mcp/dashboard-admin-menu.png diff --git a/SIDELManagerScripts/.playwright-mcp/dashboard-empty.png b/.playwright-mcp/dashboard-empty.png similarity index 100% rename from SIDELManagerScripts/.playwright-mcp/dashboard-empty.png rename to .playwright-mcp/dashboard-empty.png diff --git a/SIDELManagerScripts/.playwright-mcp/final-dashboard-state.png b/.playwright-mcp/final-dashboard-state.png similarity index 100% rename from SIDELManagerScripts/.playwright-mcp/final-dashboard-state.png rename to .playwright-mcp/final-dashboard-state.png diff --git a/SIDELManagerScripts/.playwright-mcp/hammer-analysis-2025-09-12T19-30-36.pdf b/.playwright-mcp/hammer-analysis-2025-09-12T19-30-36.pdf similarity index 100% rename from SIDELManagerScripts/.playwright-mcp/hammer-analysis-2025-09-12T19-30-36.pdf rename to .playwright-mcp/hammer-analysis-2025-09-12T19-30-36.pdf diff --git a/SIDELManagerScripts/.playwright-mcp/hammer-analysis-2025-09-12T19-30-36.pdf:Zone.Identifier b/.playwright-mcp/hammer-analysis-2025-09-12T19-30-36.pdf:Zone.Identifier similarity index 100% rename from SIDELManagerScripts/.playwright-mcp/hammer-analysis-2025-09-12T19-30-36.pdf:Zone.Identifier rename to .playwright-mcp/hammer-analysis-2025-09-12T19-30-36.pdf:Zone.Identifier diff --git a/SIDELManagerScripts/.playwright-mcp/hammer-analysis-2025-09-12T19-31-05.pdf b/.playwright-mcp/hammer-analysis-2025-09-12T19-31-05.pdf similarity index 100% rename from SIDELManagerScripts/.playwright-mcp/hammer-analysis-2025-09-12T19-31-05.pdf rename to .playwright-mcp/hammer-analysis-2025-09-12T19-31-05.pdf diff --git a/SIDELManagerScripts/.playwright-mcp/hammer-analysis-2025-09-12T19-31-05.pdf:Zone.Identifier b/.playwright-mcp/hammer-analysis-2025-09-12T19-31-05.pdf:Zone.Identifier similarity index 100% rename from SIDELManagerScripts/.playwright-mcp/hammer-analysis-2025-09-12T19-31-05.pdf:Zone.Identifier rename to .playwright-mcp/hammer-analysis-2025-09-12T19-31-05.pdf:Zone.Identifier diff --git a/SIDELManagerScripts/.playwright-mcp/login-page.png b/.playwright-mcp/login-page.png similarity index 100% rename from SIDELManagerScripts/.playwright-mcp/login-page.png rename to .playwright-mcp/login-page.png diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7142b3b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,151 @@ +# Dockerfile para SIDEL Manager Scripts con Miniconda +# Compatible con las especificaciones del proyecto SIDEL ScriptsManager +FROM continuumio/miniconda3:latest + +# Metadatos del container +LABEL maintainer="SIDEL Manager Scripts" +LABEL description="Multi-user script manager with conda environments" +LABEL version="1.0.0" + +# Variables de entorno según especificaciones SIDEL +ENV PYTHONUNBUFFERED=1 +ENV CONDA_ENV_NAME=scriptsmanager +ENV TSNET_ENV_NAME=tsnet +ENV APP_HOME=/app +ENV DATA_HOME=/app/data +ENV BACKUP_HOME=/app/backup +ENV LOGS_HOME=/app/logs + +# Variables específicas del proyecto SIDEL +ENV SECRET_KEY=change-this-in-production +ENV DEBUG=false +ENV BASE_DATA_PATH=/app/data +ENV PORT_RANGE_START=5200 +ENV PORT_RANGE_END=5400 +ENV MAX_PROJECTS_PER_USER=50 +ENV BACKUP_ENABLED=true +ENV DEFAULT_LANGUAGE=en + +# Actualizar sistema y instalar dependencias del sistema +RUN apt-get update && apt-get install -y \ + build-essential \ + curl \ + git \ + sqlite3 \ + vim \ + nano \ + htop \ + procps \ + wget \ + unzip \ + libsqlite3-dev \ + && rm -rf /var/lib/apt/lists/* + +# Crear estructura de directorios según especificaciones SIDEL +RUN mkdir -p $APP_HOME $DATA_HOME $BACKUP_HOME $LOGS_HOME && \ + mkdir -p $DATA_HOME/script_groups \ + $DATA_HOME/system \ + $LOGS_HOME/executions \ + $LOGS_HOME/system \ + $LOGS_HOME/audit \ + $BACKUP_HOME/daily + +# Establecer directorio de trabajo +WORKDIR $APP_HOME + +# Copiar archivos de configuración de dependencias +COPY requirements.txt requirements-dev.txt ./ +COPY app/backend/script_groups/hammer/requirements.txt ./tsnet_requirements.txt + +# Crear entorno conda principal para SIDEL ScriptsManager (Frontend Flask) +RUN conda create -n $CONDA_ENV_NAME python=3.12 -y + +# Activar entorno principal y configurar PATH +RUN echo "source activate $CONDA_ENV_NAME" > ~/.bashrc +ENV PATH /opt/conda/envs/$CONDA_ENV_NAME/bin:$PATH + +# Instalar dependencias Python en el entorno principal (ScriptsManager) +RUN /opt/conda/envs/$CONDA_ENV_NAME/bin/pip install --no-cache-dir -r requirements.txt + +# Crear entorno específico para TSNet (Water Hammer Simulator) +RUN conda create -n $TSNET_ENV_NAME python=3.12 -y + +# Instalar dependencias de TSNet en su entorno específico +RUN /opt/conda/envs/$TSNET_ENV_NAME/bin/pip install --no-cache-dir -r tsnet_requirements.txt + +# Copiar código de la aplicación +COPY . . + +# Crear estructura de directorios necesaria según especificaciones SIDEL +RUN mkdir -p \ + app/backend/script_groups/hammer \ + app/backend/script_groups/data_processing \ + app/backend/script_groups/system_utilities \ + app/backend/logs/executions \ + data/script_groups/group_2 \ + data/script_groups/group_3 \ + data/script_groups/group_5 \ + data/script_groups/logs \ + data/system \ + instance \ + logs/executions \ + logs/system \ + logs/audit \ + backup/daily + +# Verificar que NO existe backend/script_groups/ (solo app/backend/script_groups/) +RUN if [ -d "backend/script_groups" ]; then \ + echo "ERROR: Found backend/script_groups/ - This should NOT exist!"; \ + echo "All scripts must be in app/backend/script_groups/ only"; \ + exit 1; \ + fi + +# Establecer permisos correctos +RUN chmod +x scripts/*.py && \ + chown -R root:root $APP_HOME && \ + chmod 755 $DATA_HOME $BACKUP_HOME $LOGS_HOME + +# Crear script de inicialización específico para SIDEL ScriptsManager +RUN echo '#!/bin/bash\n\ +set -e\n\ +echo "=== SIDEL ScriptsManager Initialization ==="\n\ +source activate scriptsmanager\n\ +cd /app\n\ +\n\ +# Verificar estructura de directorios\n\ +echo "Checking directory structure..."\n\ +if [ ! -d "app/backend/script_groups" ]; then\n\ + echo "ERROR: app/backend/script_groups directory not found!"\n\ + exit 1\n\ +fi\n\ +\n\ +# Inicializar base de datos SQLite\n\ +echo "Initializing SQLite database..."\n\ +python scripts/init_db.py\n\ +\n\ +# Verificar entornos conda\n\ +echo "Available conda environments:"\n\ +conda env list\n\ +\n\ +echo "ScriptsManager environment packages:"\n\ +conda list -n scriptsmanager | grep -E "(flask|sqlalchemy)" || true\n\ +\n\ +echo "TSNet environment packages:"\n\ +conda list -n tsnet | grep -E "(tsnet|numpy|matplotlib)" || true\n\ +\n\ +echo "=== Starting SIDEL ScriptsManager ==="\n\ +exec "$@"' > /app/docker-entrypoint.sh + +RUN chmod +x /app/docker-entrypoint.sh + +# Exponer puertos (puerto principal del frontend y rango para scripts) +EXPOSE 5002 5200-5400 + +# Volúmenes para persistencia de datos +VOLUME ["$DATA_HOME", "$BACKUP_HOME", "$LOGS_HOME"] + +# Punto de entrada +ENTRYPOINT ["/app/docker-entrypoint.sh"] + +# Comando por defecto (usa el puerto correcto del frontend) +CMD ["/opt/conda/envs/scriptsmanager/bin/python", "scripts/run_app.py"] \ No newline at end of file diff --git a/MIGRATION-GUIDE.md b/MIGRATION-GUIDE.md new file mode 100644 index 0000000..3d64fe0 --- /dev/null +++ b/MIGRATION-GUIDE.md @@ -0,0 +1,254 @@ +# Guía de Migración a Docker - SIDEL ScriptsManager + +## Resumen de la Configuración Creada + +Se ha creado una configuración Docker completa para SIDEL ScriptsManager que incluye: + +### ✅ Archivos Creados/Actualizados + +1. **Dockerfile** - Imagen base con dos entornos conda +2. **docker-compose.yml** - Orquestación de servicios +3. **docker-manage.sh** - Script de gestión completo +4. **verify-environments.sh** - Script de verificación +5. **.env.example** - Plantilla de variables de entorno +6. **.dockerignore** - Exclusiones para construcción +7. **conda-environments.md** - Documentación de entornos + +### 🐍 Entornos Conda Configurados + +#### Entorno Principal: `scriptsmanager` +- **Python**: 3.12 +- **Puerto**: 5002 +- **Propósito**: Frontend Flask (run_app.py) +- **Dependencias**: Flask, SocketIO, SQLAlchemy, Gunicorn + +#### Entorno TSNet: `tsnet` +- **Python**: 3.12 +- **Puertos**: 5200-5400 (dinámicos) +- **Propósito**: Scripts Water Hammer Simulator +- **Dependencias**: TSNet, WNTR, NumPy, Matplotlib, ReportLab + +## 🔧 Próximos Pasos para Implementación + +### 1. Preparación del Entorno +```bash +cd /home/miguefin/scriptmanager/SIDELManagerScripts + +# Verificar que todos los archivos están presentes +ls -la | grep -E "(Dockerfile|docker-compose|docker-manage)" + +# Dar permisos de ejecución (si no se hizo) +chmod +x docker-manage.sh verify-environments.sh +``` + +### 2. Configuración Inicial +```bash +# Crear archivo de entorno +cp .env.example .env + +# Editar configuraciones específicas +nano .env +``` + +### 3. Construcción de la Imagen +```bash +# Construir la imagen Docker +./docker-manage.sh build + +# Este proceso: +# - Instala miniconda como base +# - Crea entorno 'scriptsmanager' con Python 3.12 +# - Instala dependencias del requirements.txt principal +# - Crea entorno 'tsnet' con Python 3.12 +# - Instala dependencias específicas de TSNet +# - Configura estructura de directorios +``` + +### 4. Primera Ejecución +```bash +# Iniciar en modo producción +./docker-manage.sh start + +# Verificar que todo funciona +./verify-environments.sh +``` + +## 🏗️ Arquitectura Implementada + +### Estructura de Directorios Docker +``` +SIDELManagerScripts/ +├── Dockerfile # ✅ Imagen con 2 entornos conda +├── docker-compose.yml # ✅ Servicios y volúmenes +├── docker-manage.sh # ✅ Script de gestión +├── verify-environments.sh # ✅ Verificación de entornos +├── .env.example # ✅ Variables de entorno +├── .dockerignore # ✅ Exclusiones +├── conda-environments.md # ✅ Documentación +└── README-Docker.md # ✅ Guía completa existente +``` + +### Volúmenes Persistentes +``` +./data/ → /app/data/ # Base de datos y datos de usuario +./backup/ → /app/backup/ # Backups automáticos +./logs/ → /app/logs/ # Logs de aplicación +./app/backend/ → /app/app/backend/ # Scripts (modo desarrollo) +``` + +### Puertos Configurados +- **5002**: Frontend principal (producción) +- **5003**: Frontend desarrollo (perfil dev) +- **5200-5400**: Rango para scripts TSNet dinámicos +- **5432**: PostgreSQL (perfil opcional) + +## 🔍 Verificaciones Post-Instalación + +### 1. Verificar Entornos Conda +```bash +# Listar entornos disponibles +./docker-manage.sh envs + +# Debería mostrar: +# scriptsmanager +# tsnet +``` + +### 2. Verificar Dependencias +```bash +# Ejecutar script de verificación completo +./verify-environments.sh + +# Verificaciones que realiza: +# ✓ Contenedor ejecutándose +# ✓ Python 3.12 en ambos entornos +# ✓ Flask en scriptsmanager +# ✓ TSNet en entorno tsnet +# ✓ NumPy, Matplotlib, WNTR +# ✓ Conectividad del frontend +``` + +### 3. Verificar Aplicación +```bash +# Verificar salud de la aplicación +./docker-manage.sh health + +# Acceder a la aplicación +curl http://localhost:5002 +``` + +## 🛠️ Comandos de Gestión Disponibles + +### Gestión Principal +```bash +./docker-manage.sh build # Construir imagen +./docker-manage.sh start # Iniciar producción +./docker-manage.sh start-dev # Iniciar desarrollo +./docker-manage.sh stop # Detener contenedores +./docker-manage.sh restart # Reiniciar +./docker-manage.sh status # Estado actual +``` + +### Monitoreo y Debug +```bash +./docker-manage.sh logs # Ver logs +./docker-manage.sh logs -f # Seguir logs en tiempo real +./docker-manage.sh shell # Acceder al contenedor +./docker-manage.sh envs # Listar entornos conda +./docker-manage.sh health # Verificar salud +``` + +### Gestión de Datos +```bash +./docker-manage.sh backup # Backup manual +./docker-manage.sh init-admin # Crear admin (cuando esté implementado) +./docker-manage.sh init-db # Inicializar BD +``` + +## 🚨 Consideraciones Importantes + +### 1. Compatibilidad con WSL +- La configuración está optimizada para Linux/WSL +- Funciona perfectamente en tu entorno WSL actual +- Los volúmenes se mapean correctamente al sistema de archivos WSL + +### 2. Gestión de Puertos +- Puerto 5002 para el frontend (cambio desde el 5002 original de run_app.py) +- El ScriptsManager asignará puertos dinámicos 5200-5400 para scripts TSNet +- Configuración compatible con la arquitectura multiusuario + +### 3. Persistencia de Datos +- Todos los datos de usuario se mantienen en `./data/` +- Logs organizados por usuario en `./logs/` +- Backups automáticos en `./backup/` + +### 4. Entornos Conda Isolados +- `scriptsmanager`: Solo dependencias del frontend +- `tsnet`: Solo dependencias de simulación +- Sin conflictos entre bibliotecas + +## 🔧 Personalización Avanzada + +### Variables de Entorno Clave (.env) +```bash +# Configuración de la aplicación +DEBUG=false +SECRET_KEY=cambiar-en-produccion + +# Base de datos +DATABASE_URL=sqlite:///app/data/scriptsmanager.db + +# Gestión de puertos +PORT_RANGE_START=5200 +PORT_RANGE_END=5400 + +# Entornos conda +CONDA_DEFAULT_ENV=scriptsmanager +TSNET_ENV=tsnet +``` + +### Perfiles Docker Compose Disponibles +```bash +# Perfil por defecto (producción) +./docker-manage.sh start + +# Perfil de desarrollo +./docker-manage.sh start-dev + +# Con PostgreSQL (en lugar de SQLite) +docker-compose --profile postgres up -d + +# Con backup automático diario +docker-compose --profile backup up -d +``` + +## 📋 Lista de Verificación Final + +- [ ] Archivos Docker creados correctamente +- [ ] Permisos de ejecución configurados +- [ ] Archivo .env configurado +- [ ] Imagen Docker construida: `./docker-manage.sh build` +- [ ] Aplicación iniciada: `./docker-manage.sh start` +- [ ] Entornos verificados: `./verify-environments.sh` +- [ ] Frontend accesible en http://localhost:5002 +- [ ] Logs funcionando: `./docker-manage.sh logs` + +## ⚡ Comando de Inicio Rápido + +Para usuarios experimentados, secuencia completa de inicio: + +```bash +cd /home/miguefin/scriptmanager/SIDELManagerScripts +cp .env.example .env +./docker-manage.sh build +./docker-manage.sh start +./verify-environments.sh +``` + +--- + +**🎯 Resultado Esperado**: +- SIDEL ScriptsManager ejecutándose en http://localhost:5002 +- Dos entornos conda funcionales (scriptsmanager, tsnet) +- Gestión completa a través de `./docker-manage.sh` +- Datos persistentes en volúmenes Docker \ No newline at end of file diff --git a/README-Docker.md b/README-Docker.md new file mode 100644 index 0000000..cc81ae4 --- /dev/null +++ b/README-Docker.md @@ -0,0 +1,372 @@ +# SIDEL ScriptsManager - Docker Setup + +![SIDEL ScriptsManager](https://img.shields.io/badge/SIDEL-ScriptsManager-blue) ![Docker](https://img.shields.io/badge/docker-ready-green) ![Python](https://img.shields.io/badge/python-3.12-blue) + +Sistema de gestión de scripts multiusuario con entornos conda aislados, desarrollado para SIDEL. + +## 🏗️ Arquitectura del Sistema + +### Componentes Principales + +- **Frontend Flask**: Puerto 5002 (entorno `scriptsmanager`) +- **Scripts TSNet**: Puertos 5200-5400 (entorno `tsnet`) +- **Base de datos**: SQLite con esquema multiusuario completo +- **Persistencia**: Volúmenes Docker para datos, logs y backups + +### Entornos Conda + +| Entorno | Propósito | Puerto | Dependencias Principales | +|---------|-----------|--------|--------------------------| +| `scriptsmanager` | Frontend Flask multiusuario | 5002 | Flask 3.0+, SQLAlchemy, SocketIO | +| `tsnet` | Water Hammer Simulator | 5200-5400 | TSNet, WNTR, NumPy, Matplotlib | + +## 🚀 Inicio Rápido + +### 1. Construcción e Inicio + +```bash +# Dar permisos de ejecución +chmod +x docker-manage.sh + +# Construir la imagen +./docker-manage.sh build + +# Inicializar base de datos +./docker-manage.sh init-db + +# Iniciar en producción +./docker-manage.sh start +``` + +**Acceso**: http://localhost:5002 + +**Credenciales por defecto**: +- Usuario: `admin` +- Contraseña: `admin123` + +⚠️ **IMPORTANTE**: Cambiar estas credenciales en producción. + +### 2. Desarrollo + +```bash +# Iniciar en modo desarrollo +./docker-manage.sh start-dev +``` + +**Acceso desarrollo**: http://localhost:5003 + +## 📋 Comandos Principales + +### Gestión de Contenedores + +```bash +# Construcción e inicio +./docker-manage.sh build # Construir imagen +./docker-manage.sh start # Iniciar producción +./docker-manage.sh start-dev # Iniciar desarrollo +./docker-manage.sh stop # Detener contenedores +./docker-manage.sh restart # Reiniciar principal + +# Estado y monitoreo +./docker-manage.sh status # Estado de contenedores +./docker-manage.sh health # Verificar salud de la app +./docker-manage.sh verify # Verificación completa +./docker-manage.sh ports # Estado de puertos +``` + +### Gestión de Datos + +```bash +# Base de datos +./docker-manage.sh init-db # Inicializar BD SIDEL +./docker-manage.sh backup # Backup manual +./docker-manage.sh users # Gestión de usuarios + +# Logs y depuración +./docker-manage.sh logs # Logs de producción +./docker-manage.sh logs-dev # Logs de desarrollo +./docker-manage.sh shell # Shell en contenedor +./docker-manage.sh envs # Listar entornos conda +``` + +### Servicios Adicionales + +```bash +# Servicios opcionales +./docker-manage.sh start-backup # Backup automático diario +./docker-manage.sh start-monitoring # Monitoreo de logs + +# Limpieza y mantenimiento +./docker-manage.sh clean # Limpiar imágenes no usadas +./docker-manage.sh reset # Reset completo (¡PELIGROSO!) +``` + +## 📁 Estructura de Datos + +### Directorios Principales + +``` +📁 data/ +├── 📁 script_groups/ # Datos por usuario/proyecto +│ ├── 📁 group_hammer/ +│ │ ├── 📁 user_1/ +│ │ │ ├── 📁 project_default/ +│ │ │ └── 📁 project_simulation_a/ +│ │ └── 📁 user_2/ +│ └── 📁 group_analytics/ +├── 📄 scriptsmanager.db # Base de datos SQLite +└── 📁 system/ # Configuración del sistema + +📁 logs/ +├── 📁 executions/ # Logs de ejecución por usuario +├── 📁 system/ # Logs del sistema +└── 📁 audit/ # Logs de auditoría + +📁 backup/ +└── 📁 daily/ # Backups automáticos diarios + +📁 app/backend/script_groups/ # Scripts del sistema +├── 📁 hammer/ # Scripts TSNet +├── 📁 data_processing/ # Scripts de análisis +└── 📁 system_utilities/ # Utilidades de sistema +``` + +## 🔧 Configuración + +### Variables de Entorno + +Archivo `.env` (copia desde `.env.example`): + +```bash +# Aplicación +DEBUG=false +SECRET_KEY=tu-clave-secreta-de-produccion +DATABASE_URL=sqlite:///app/data/scriptsmanager.db + +# Multiusuario +BASE_DATA_PATH=/app/data +MAX_PROJECTS_PER_USER=50 +PORT_RANGE_START=5200 +PORT_RANGE_END=5400 + +# Internacionalización +DEFAULT_LANGUAGE=en +SUPPORTED_LANGUAGES=en,es,it,fr +DEFAULT_THEME=light + +# SIDEL Branding +SIDEL_LOGO_PATH=/app/app/static/images/SIDEL.png +CORPORATE_BRANDING=true + +# Backup +BACKUP_ENABLED=true +``` + +### Docker Compose Profiles + +```bash +# Desarrollo con hot-reload +docker-compose --profile dev up -d + +# Backup automático +docker-compose --profile backup up -d + +# Monitoreo de logs +docker-compose --profile monitoring up -d + +# Todos los servicios +docker-compose --profile dev --profile backup --profile monitoring up -d +``` + +## 👥 Gestión de Usuarios + +### Niveles de Usuario + +| Nivel | Permisos | Descripción | +|-------|----------|-------------| +| `admin` | Completos | Gestión total del sistema | +| `developer` | Desarrollo | Edición de metadatos y scripts | +| `operator` | Operación | Ejecución de scripts de producción | +| `viewer` | Solo lectura | Consulta de logs y documentación | + +### Crear Usuarios + +```bash +# Acceder al shell del contenedor +./docker-manage.sh shell + +# Crear usuario administrador +python scripts/create_admin.py --username miusuario --password mipassword --email mi@email.com + +# Crear usuario operador +python scripts/create_user.py --username operador1 --password pass123 --level operator + +# Listar usuarios +python scripts/list_users.py +``` + +## 🔍 Verificación y Depuración + +### Verificación Completa + +```bash +./docker-manage.sh verify +``` + +Esto verifica: +- ✅ Estructura de directorios correcta +- ✅ Entornos conda funcionando +- ✅ Dependencias instaladas +- ✅ Puertos accesibles +- ✅ Base de datos inicializada + +### Depuración Común + +#### Error: "app/backend/script_groups not found" + +```bash +# Crear estructura correcta +mkdir -p app/backend/script_groups/hammer +mkdir -p app/backend/script_groups/data_processing +mkdir -p app/backend/script_groups/system_utilities + +# Verificar que NO exista backend/script_groups/ +ls -la backend/ # No debería existir +``` + +#### Error: "Port 5002 already in use" + +```bash +# Verificar puertos en uso +./docker-manage.sh ports + +# Detener otros servicios +./docker-manage.sh stop +sudo lsof -ti:5002 | xargs kill -9 # Solo si es necesario +``` + +#### Error: "Conda environment not found" + +```bash +# Verificar entornos en contenedor +./docker-manage.sh shell +conda env list +conda activate scriptsmanager +conda activate tsnet +``` + +## 📊 Monitoreo y Logs + +### Logs en Tiempo Real + +```bash +# Logs de producción +./docker-manage.sh logs -f + +# Logs de desarrollo +./docker-manage.sh logs-dev -f + +# Logs de servicios específicos +docker-compose logs -f backup +docker-compose logs -f log-monitor +``` + +### Acceso a Logs de Usuario + +Los logs de ejecución están disponibles en la interfaz web: +- **URL**: http://localhost:5002/logs +- **Filtros**: Por usuario, script, proyecto, fecha +- **Tiempo Real**: WebSocket para actualizaciones en vivo +- **Exportación**: Descarga en varios formatos + +## 🔄 Backup y Recuperación + +### Backup Automático + +```bash +# Activar servicio de backup +./docker-manage.sh start-backup + +# El backup se ejecuta diariamente y guarda: +# - Base de datos SQLite completa +# - Todos los datos de usuario +# - Configuraciones del sistema +``` + +### Backup Manual + +```bash +# Backup inmediato +./docker-manage.sh backup + +# Los backups se guardan en: +# backup/daily/data_backup_YYYYMMDD_HHMMSS.tar.gz +``` + +### Recuperación + +```bash +# 1. Detener servicios +./docker-manage.sh stop + +# 2. Restaurar desde backup +cd backup/daily/ +tar -xzf data_backup_YYYYMMDD_HHMMSS.tar.gz -C ../../ + +# 3. Reiniciar servicios +./docker-manage.sh start +``` + +## 🚨 Troubleshooting + +### Problemas Comunes + +1. **Contenedor no inicia** + ```bash + ./docker-manage.sh verify + docker-compose logs scriptsmanager + ``` + +2. **Base de datos corrupta** + ```bash + ./docker-manage.sh stop + cp data/scriptsmanager.db data/scriptsmanager.db.backup + ./docker-manage.sh init-db + ./docker-manage.sh start + ``` + +3. **Permisos de archivos** + ```bash + sudo chown -R $USER:$USER data/ logs/ backup/ + chmod -R 755 data/ logs/ backup/ + ``` + +4. **Reset completo** (⚠️ Borra todos los datos) + ```bash + ./docker-manage.sh reset + ``` + +### Obtener Ayuda + +```bash +# Ver todos los comandos disponibles +./docker-manage.sh help + +# Verificar configuración +./docker-manage.sh verify + +# Estado del sistema +./docker-manage.sh status +``` + +## 📄 Documentación Adicional + +- **Especificaciones**: `.doc/Application_Specification.md` +- **Entornos Conda**: `conda-environments.yml` +- **Configuración**: `.env.example` +- **API**: Documentación en la aplicación web + +--- + +**SIDEL ScriptsManager** - Sistema de gestión de scripts multiusuario con Docker y conda +Versión: 1.0.0 | Soporte: [Issues](../../issues) \ No newline at end of file diff --git a/SIDELManagerScripts/README.md b/README.md similarity index 100% rename from SIDELManagerScripts/README.md rename to README.md diff --git a/SIDELManagerScripts/app/__init__.py b/app/__init__.py similarity index 100% rename from SIDELManagerScripts/app/__init__.py rename to app/__init__.py diff --git a/SIDELManagerScripts/app/app.py b/app/app.py similarity index 100% rename from SIDELManagerScripts/app/app.py rename to app/app.py diff --git a/SIDELManagerScripts/app/backend/script_groups/data_processing/data_analyzer.py b/app/backend/script_groups/data_processing/data_analyzer.py similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/data_processing/data_analyzer.py rename to app/backend/script_groups/data_processing/data_analyzer.py diff --git a/SIDELManagerScripts/app/backend/script_groups/data_processing/metadata.json b/app/backend/script_groups/data_processing/metadata.json similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/data_processing/metadata.json rename to app/backend/script_groups/data_processing/metadata.json diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/.gitignore b/app/backend/script_groups/hammer/.gitignore similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/.gitignore rename to app/backend/script_groups/hammer/.gitignore diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/.playwright-mcp/hammer-simulator-initial.png b/app/backend/script_groups/hammer/.playwright-mcp/hammer-simulator-initial.png similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/.playwright-mcp/hammer-simulator-initial.png rename to app/backend/script_groups/hammer/.playwright-mcp/hammer-simulator-initial.png diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/.playwright-mcp/hammer-simulator-spanish-final.png b/app/backend/script_groups/hammer/.playwright-mcp/hammer-simulator-spanish-final.png similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/.playwright-mcp/hammer-simulator-spanish-final.png rename to app/backend/script_groups/hammer/.playwright-mcp/hammer-simulator-spanish-final.png diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/README.md b/app/backend/script_groups/hammer/README.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/README.md rename to app/backend/script_groups/hammer/README.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/conceptos_golpe_ariete.md b/app/backend/script_groups/hammer/conceptos_golpe_ariete.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/conceptos_golpe_ariete.md rename to app/backend/script_groups/hammer/conceptos_golpe_ariete.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/docs/export_features.md b/app/backend/script_groups/hammer/docs/export_features.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/docs/export_features.md rename to app/backend/script_groups/hammer/docs/export_features.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/docs/export_instructions_es.md b/app/backend/script_groups/hammer/docs/export_instructions_es.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/docs/export_instructions_es.md rename to app/backend/script_groups/hammer/docs/export_instructions_es.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/docs/hammer_simulator.md b/app/backend/script_groups/hammer/docs/hammer_simulator.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/docs/hammer_simulator.md rename to app/backend/script_groups/hammer/docs/hammer_simulator.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/docs/hammer_simulator_es.md b/app/backend/script_groups/hammer/docs/hammer_simulator_es.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/docs/hammer_simulator_es.md rename to app/backend/script_groups/hammer/docs/hammer_simulator_es.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/docs/hammer_simulator_fr.md b/app/backend/script_groups/hammer/docs/hammer_simulator_fr.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/docs/hammer_simulator_fr.md rename to app/backend/script_groups/hammer/docs/hammer_simulator_fr.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/docs/hammer_simulator_it.md b/app/backend/script_groups/hammer/docs/hammer_simulator_it.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/docs/hammer_simulator_it.md rename to app/backend/script_groups/hammer/docs/hammer_simulator_it.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/docs/test_configurations.md b/app/backend/script_groups/hammer/docs/test_configurations.md similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/docs/test_configurations.md rename to app/backend/script_groups/hammer/docs/test_configurations.md diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/examples/advanced_damper_config.json b/app/backend/script_groups/hammer/examples/advanced_damper_config.json similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/examples/advanced_damper_config.json rename to app/backend/script_groups/hammer/examples/advanced_damper_config.json diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/examples/basic_water_hammer.json b/app/backend/script_groups/hammer/examples/basic_water_hammer.json similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/examples/basic_water_hammer.json rename to app/backend/script_groups/hammer/examples/basic_water_hammer.json diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/hammer_simulator.py b/app/backend/script_groups/hammer/hammer_simulator.py similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/hammer_simulator.py rename to app/backend/script_groups/hammer/hammer_simulator.py diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/metadata.json b/app/backend/script_groups/hammer/metadata.json similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/metadata.json rename to app/backend/script_groups/hammer/metadata.json diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/requirements.txt b/app/backend/script_groups/hammer/requirements.txt similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/requirements.txt rename to app/backend/script_groups/hammer/requirements.txt diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/simulador_hammer_interactivo.py b/app/backend/script_groups/hammer/simulador_hammer_interactivo.py similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/simulador_hammer_interactivo.py rename to app/backend/script_groups/hammer/simulador_hammer_interactivo.py diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/static/css/hammer_simulator.css b/app/backend/script_groups/hammer/static/css/hammer_simulator.css similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/static/css/hammer_simulator.css rename to app/backend/script_groups/hammer/static/css/hammer_simulator.css diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/static/images/SIDEL.png b/app/backend/script_groups/hammer/static/images/SIDEL.png similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/static/images/SIDEL.png rename to app/backend/script_groups/hammer/static/images/SIDEL.png diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/static/images/SIDEL.png:Zone.Identifier b/app/backend/script_groups/hammer/static/images/SIDEL.png:Zone.Identifier similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/static/images/SIDEL.png:Zone.Identifier rename to app/backend/script_groups/hammer/static/images/SIDEL.png:Zone.Identifier diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/static/js/hammer_simulator.js b/app/backend/script_groups/hammer/static/js/hammer_simulator.js similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/static/js/hammer_simulator.js rename to app/backend/script_groups/hammer/static/js/hammer_simulator.js diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/static/js/translations.js b/app/backend/script_groups/hammer/static/js/translations.js similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/static/js/translations.js rename to app/backend/script_groups/hammer/static/js/translations.js diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/templates/hammer_simulator.html b/app/backend/script_groups/hammer/templates/hammer_simulator.html similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/templates/hammer_simulator.html rename to app/backend/script_groups/hammer/templates/hammer_simulator.html diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/test_data/hammer_config.json b/app/backend/script_groups/hammer/test_data/hammer_config.json similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/test_data/hammer_config.json rename to app/backend/script_groups/hammer/test_data/hammer_config.json diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/test_data/hammer_results.json b/app/backend/script_groups/hammer/test_data/hammer_results.json similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/test_data/hammer_results.json rename to app/backend/script_groups/hammer/test_data/hammer_results.json diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/test_diagram.png b/app/backend/script_groups/hammer/test_diagram.png similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/test_diagram.png rename to app/backend/script_groups/hammer/test_diagram.png diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/test_plantuml.html b/app/backend/script_groups/hammer/test_plantuml.html similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/test_plantuml.html rename to app/backend/script_groups/hammer/test_plantuml.html diff --git a/SIDELManagerScripts/app/backend/script_groups/hammer/test_plantuml.py b/app/backend/script_groups/hammer/test_plantuml.py similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/hammer/test_plantuml.py rename to app/backend/script_groups/hammer/test_plantuml.py diff --git a/SIDELManagerScripts/app/backend/script_groups/system_utilities/backup_system.py b/app/backend/script_groups/system_utilities/backup_system.py similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/system_utilities/backup_system.py rename to app/backend/script_groups/system_utilities/backup_system.py diff --git a/SIDELManagerScripts/app/backend/script_groups/system_utilities/metadata.json b/app/backend/script_groups/system_utilities/metadata.json similarity index 100% rename from SIDELManagerScripts/app/backend/script_groups/system_utilities/metadata.json rename to app/backend/script_groups/system_utilities/metadata.json diff --git a/SIDELManagerScripts/app/config/config.py b/app/config/config.py similarity index 100% rename from SIDELManagerScripts/app/config/config.py rename to app/config/config.py diff --git a/SIDELManagerScripts/app/config/database.py b/app/config/database.py similarity index 100% rename from SIDELManagerScripts/app/config/database.py rename to app/config/database.py diff --git a/SIDELManagerScripts/app/config/permissions.py b/app/config/permissions.py similarity index 100% rename from SIDELManagerScripts/app/config/permissions.py rename to app/config/permissions.py diff --git a/SIDELManagerScripts/app/models/__init__.py b/app/models/__init__.py similarity index 100% rename from SIDELManagerScripts/app/models/__init__.py rename to app/models/__init__.py diff --git a/SIDELManagerScripts/app/models/script.py b/app/models/script.py similarity index 100% rename from SIDELManagerScripts/app/models/script.py rename to app/models/script.py diff --git a/SIDELManagerScripts/app/models/user.py b/app/models/user.py similarity index 100% rename from SIDELManagerScripts/app/models/user.py rename to app/models/user.py diff --git a/SIDELManagerScripts/app/services/backup_service.py b/app/services/backup_service.py similarity index 100% rename from SIDELManagerScripts/app/services/backup_service.py rename to app/services/backup_service.py diff --git a/SIDELManagerScripts/app/services/conda_service.py b/app/services/conda_service.py similarity index 100% rename from SIDELManagerScripts/app/services/conda_service.py rename to app/services/conda_service.py diff --git a/SIDELManagerScripts/app/services/data_manager.py b/app/services/data_manager.py similarity index 100% rename from SIDELManagerScripts/app/services/data_manager.py rename to app/services/data_manager.py diff --git a/SIDELManagerScripts/app/services/port_manager.py b/app/services/port_manager.py similarity index 100% rename from SIDELManagerScripts/app/services/port_manager.py rename to app/services/port_manager.py diff --git a/SIDELManagerScripts/app/services/script_discovery.py b/app/services/script_discovery.py similarity index 100% rename from SIDELManagerScripts/app/services/script_discovery.py rename to app/services/script_discovery.py diff --git a/SIDELManagerScripts/app/services/script_executor.py b/app/services/script_executor.py similarity index 100% rename from SIDELManagerScripts/app/services/script_executor.py rename to app/services/script_executor.py diff --git a/SIDELManagerScripts/app/services/translation_service.py b/app/services/translation_service.py similarity index 100% rename from SIDELManagerScripts/app/services/translation_service.py rename to app/services/translation_service.py diff --git a/SIDELManagerScripts/app/static/css/main.css b/app/static/css/main.css similarity index 100% rename from SIDELManagerScripts/app/static/css/main.css rename to app/static/css/main.css diff --git a/SIDELManagerScripts/app/static/css/responsive.css b/app/static/css/responsive.css similarity index 100% rename from SIDELManagerScripts/app/static/css/responsive.css rename to app/static/css/responsive.css diff --git a/SIDELManagerScripts/app/static/css/themes.css b/app/static/css/themes.css similarity index 100% rename from SIDELManagerScripts/app/static/css/themes.css rename to app/static/css/themes.css diff --git a/SIDELManagerScripts/app/static/images/SIDEL.png b/app/static/images/SIDEL.png similarity index 100% rename from SIDELManagerScripts/app/static/images/SIDEL.png rename to app/static/images/SIDEL.png diff --git a/SIDELManagerScripts/app/static/images/SIDEL.png:Zone.Identifier b/app/static/images/SIDEL.png:Zone.Identifier similarity index 100% rename from SIDELManagerScripts/app/static/images/SIDEL.png:Zone.Identifier rename to app/static/images/SIDEL.png:Zone.Identifier diff --git a/SIDELManagerScripts/app/static/images/SIDELw.png b/app/static/images/SIDELw.png similarity index 100% rename from SIDELManagerScripts/app/static/images/SIDELw.png rename to app/static/images/SIDELw.png diff --git a/SIDELManagerScripts/app/static/js/language-manager.js b/app/static/js/language-manager.js similarity index 100% rename from SIDELManagerScripts/app/static/js/language-manager.js rename to app/static/js/language-manager.js diff --git a/SIDELManagerScripts/app/static/js/main.js b/app/static/js/main.js similarity index 100% rename from SIDELManagerScripts/app/static/js/main.js rename to app/static/js/main.js diff --git a/SIDELManagerScripts/app/static/js/theme-manager.js b/app/static/js/theme-manager.js similarity index 100% rename from SIDELManagerScripts/app/static/js/theme-manager.js rename to app/static/js/theme-manager.js diff --git a/SIDELManagerScripts/app/static/js/websocket.js b/app/static/js/websocket.js similarity index 100% rename from SIDELManagerScripts/app/static/js/websocket.js rename to app/static/js/websocket.js diff --git a/SIDELManagerScripts/app/templates/403.html b/app/templates/403.html similarity index 100% rename from SIDELManagerScripts/app/templates/403.html rename to app/templates/403.html diff --git a/SIDELManagerScripts/app/templates/404.html b/app/templates/404.html similarity index 100% rename from SIDELManagerScripts/app/templates/404.html rename to app/templates/404.html diff --git a/SIDELManagerScripts/app/templates/500.html b/app/templates/500.html similarity index 100% rename from SIDELManagerScripts/app/templates/500.html rename to app/templates/500.html diff --git a/SIDELManagerScripts/app/templates/admin/backup.html b/app/templates/admin/backup.html similarity index 100% rename from SIDELManagerScripts/app/templates/admin/backup.html rename to app/templates/admin/backup.html diff --git a/SIDELManagerScripts/app/templates/admin/conda.html b/app/templates/admin/conda.html similarity index 100% rename from SIDELManagerScripts/app/templates/admin/conda.html rename to app/templates/admin/conda.html diff --git a/SIDELManagerScripts/app/templates/admin/user_form.html b/app/templates/admin/user_form.html similarity index 100% rename from SIDELManagerScripts/app/templates/admin/user_form.html rename to app/templates/admin/user_form.html diff --git a/SIDELManagerScripts/app/templates/admin/users.html b/app/templates/admin/users.html similarity index 100% rename from SIDELManagerScripts/app/templates/admin/users.html rename to app/templates/admin/users.html diff --git a/SIDELManagerScripts/app/templates/base.html b/app/templates/base.html similarity index 100% rename from SIDELManagerScripts/app/templates/base.html rename to app/templates/base.html diff --git a/SIDELManagerScripts/app/templates/dashboard.html b/app/templates/dashboard.html similarity index 100% rename from SIDELManagerScripts/app/templates/dashboard.html rename to app/templates/dashboard.html diff --git a/SIDELManagerScripts/app/templates/login.html b/app/templates/login.html similarity index 100% rename from SIDELManagerScripts/app/templates/login.html rename to app/templates/login.html diff --git a/SIDELManagerScripts/app/templates/script_group.html b/app/templates/script_group.html similarity index 100% rename from SIDELManagerScripts/app/templates/script_group.html rename to app/templates/script_group.html diff --git a/SIDELManagerScripts/app/translations/en.json b/app/translations/en.json similarity index 100% rename from SIDELManagerScripts/app/translations/en.json rename to app/translations/en.json diff --git a/SIDELManagerScripts/app/translations/es.json b/app/translations/es.json similarity index 100% rename from SIDELManagerScripts/app/translations/es.json rename to app/translations/es.json diff --git a/SIDELManagerScripts/app/translations/fr.json b/app/translations/fr.json similarity index 100% rename from SIDELManagerScripts/app/translations/fr.json rename to app/translations/fr.json diff --git a/SIDELManagerScripts/app/translations/it.json b/app/translations/it.json similarity index 100% rename from SIDELManagerScripts/app/translations/it.json rename to app/translations/it.json diff --git a/SIDELManagerScripts/backup/2025-09-12/data_backup_2025-09-12_014617.tar.gz b/backup/2025-09-12/data_backup_2025-09-12_014617.tar.gz similarity index 100% rename from SIDELManagerScripts/backup/2025-09-12/data_backup_2025-09-12_014617.tar.gz rename to backup/2025-09-12/data_backup_2025-09-12_014617.tar.gz diff --git a/SIDELManagerScripts/backup/2025-09-12/data_backup_2025-09-12_020037.tar.gz b/backup/2025-09-12/data_backup_2025-09-12_020037.tar.gz similarity index 100% rename from SIDELManagerScripts/backup/2025-09-12/data_backup_2025-09-12_020037.tar.gz rename to backup/2025-09-12/data_backup_2025-09-12_020037.tar.gz diff --git a/SIDELManagerScripts/backup/2025-09-12/data_backup_2025-09-12_020039.tar.gz b/backup/2025-09-12/data_backup_2025-09-12_020039.tar.gz similarity index 100% rename from SIDELManagerScripts/backup/2025-09-12/data_backup_2025-09-12_020039.tar.gz rename to backup/2025-09-12/data_backup_2025-09-12_020039.tar.gz diff --git a/SIDELManagerScripts/backup/2025-09-13/data_backup_2025-09-13_020013.tar.gz b/backup/2025-09-13/data_backup_2025-09-13_020013.tar.gz similarity index 100% rename from SIDELManagerScripts/backup/2025-09-13/data_backup_2025-09-13_020013.tar.gz rename to backup/2025-09-13/data_backup_2025-09-13_020013.tar.gz diff --git a/SIDELManagerScripts/backup/2025-09-13/data_backup_2025-09-13_020052.tar.gz b/backup/2025-09-13/data_backup_2025-09-13_020052.tar.gz similarity index 100% rename from SIDELManagerScripts/backup/2025-09-13/data_backup_2025-09-13_020052.tar.gz rename to backup/2025-09-13/data_backup_2025-09-13_020052.tar.gz diff --git a/SIDELManagerScripts/check_complete_log.py b/check_complete_log.py similarity index 100% rename from SIDELManagerScripts/check_complete_log.py rename to check_complete_log.py diff --git a/SIDELManagerScripts/check_db.py b/check_db.py similarity index 100% rename from SIDELManagerScripts/check_db.py rename to check_db.py diff --git a/SIDELManagerScripts/check_group_env.py b/check_group_env.py similarity index 100% rename from SIDELManagerScripts/check_group_env.py rename to check_group_env.py diff --git a/SIDELManagerScripts/check_log.py b/check_log.py similarity index 100% rename from SIDELManagerScripts/check_log.py rename to check_log.py diff --git a/SIDELManagerScripts/check_tables.py b/check_tables.py similarity index 100% rename from SIDELManagerScripts/check_tables.py rename to check_tables.py diff --git a/conda-environments.md b/conda-environments.md new file mode 100644 index 0000000..2e18f62 --- /dev/null +++ b/conda-environments.md @@ -0,0 +1,44 @@ +# Configuración de entornos Conda para SIDEL Manager Scripts +# Este archivo documenta los entornos disponibles y su propósito + +# ENTORNO PRINCIPAL: scriptsmanager +# - Propósito: Frontend Flask (ScriptsManager) +# - Puerto: 5002 +# - Python: 3.12 +# - Dependencias principales: +# * Flask >= 3.0.0 +# * Flask-SocketIO >= 5.3.0 +# * SQLAlchemy +# * Gunicorn +# * Psutil (para gestión de procesos conda) + +# ENTORNO TSNET: tsnet +# - Propósito: Simulaciones Water Hammer +# - Puertos dinámicos: 5200-5400 +# - Python: 3.12 +# - Dependencias principales: +# * TSNet >= 0.3.1 +# * WNTR >= 1.1.0 +# * NumPy >= 1.24.0 +# * Matplotlib >= 3.7.0 +# * Pandas >= 2.0.0 +# * SciPy >= 1.10.0 +# * ReportLab >= 4.0.0 + +# Comandos útiles para gestión de entornos: +# docker exec -it sidel_scriptsmanager conda env list +# docker exec -it sidel_scriptsmanager conda activate scriptsmanager +# docker exec -it sidel_scriptsmanager conda activate tsnet + +# Variables de entorno relevantes: +# CONDA_DEFAULT_ENV=scriptsmanager (entorno por defecto) +# TSNET_ENV=tsnet (entorno para scripts TSNet) + +# Ejemplo de uso desde el ScriptsManager: +# Para ejecutar un script TSNet, el sistema debería activar el entorno tsnet: +# conda activate tsnet && python script_hammer.py + +# Verificación de entornos: +# conda info --envs +# conda list -n scriptsmanager +# conda list -n tsnet \ No newline at end of file diff --git a/conda-environments.yml b/conda-environments.yml new file mode 100644 index 0000000..b2f00d0 --- /dev/null +++ b/conda-environments.yml @@ -0,0 +1,70 @@ +# Configuración de entornos Conda para SIDEL ScriptsManager +# Este archivo define los entornos necesarios según las especificaciones del proyecto + +# ENTORNO PRINCIPAL: scriptsmanager +# Propósito: Frontend Flask (SIDEL ScriptsManager) +# Puerto: 5002 (especificado en run_app.py) +# Características: +# - Gestión multiusuario con SQLite +# - WebSocket para logs en tiempo real +# - Multi-idioma (en, es, it, fr) +# - Temas light/dark +# - Gestión de proyectos y permisos + +scriptsmanager_env: + name: scriptsmanager + channels: + - conda-forge + - defaults + dependencies: + - python=3.12 + - pip + - sqlite + - pip: + - flask>=3.0.0 + - flask-sqlalchemy>=3.1.0 + - flask-login>=0.6.0 + - flask-wtf>=1.2.0 + - flask-socketio>=5.3.0 + - werkzeug>=3.0.0 + - gunicorn>=21.2.0 + - eventlet>=0.30.0 + - psutil>=5.9.0 + - schedule>=1.2.0 + - markdown>=3.5.0 + - pygments>=2.16.0 + - watchdog>=3.0.0 + - pyyaml>=6.0.1 + - python-dateutil>=2.8.2 + - requests>=2.31.0 + +--- + +# ENTORNO TSNET: tsnet +# Propósito: Simulaciones Water Hammer (scripts de hammer group) +# Puertos dinámicos: 5200-5400 +# Características: +# - Análisis de water hammer con TSNet +# - Visualización científica con matplotlib +# - Generación de reportes PDF +# - Integración con WNTR para redes de agua + +tsnet_env: + name: tsnet + channels: + - conda-forge + - defaults + dependencies: + - python=3.12 + - numpy>=1.24.0 + - matplotlib>=3.7.0 + - pandas>=2.0.0 + - scipy>=1.10.0 + - pip + - pip: + - flask>=2.0.0 + - flask-socketio>=5.0.0 + - reportlab>=4.0.0 + - requests>=2.25.0 + - wntr>=1.1.0 + - tsnet>=0.3.1 \ No newline at end of file diff --git a/SIDELManagerScripts/data/script_groups/group_2/user_1/Test Hydraulic Project/config.json b/data/script_groups/group_2/user_1/Test Hydraulic Project/config.json similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_2/user_1/Test Hydraulic Project/config.json rename to data/script_groups/group_2/user_1/Test Hydraulic Project/config.json diff --git a/SIDELManagerScripts/data/script_groups/group_2/user_1/Test Project/config.json b/data/script_groups/group_2/user_1/Test Project/config.json similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_2/user_1/Test Project/config.json rename to data/script_groups/group_2/user_1/Test Project/config.json diff --git a/SIDELManagerScripts/data/script_groups/group_3/user_1/project_default/config.json b/data/script_groups/group_3/user_1/project_default/config.json similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_3/user_1/project_default/config.json rename to data/script_groups/group_3/user_1/project_default/config.json diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/config.json b/data/script_groups/group_5/user_1/project_default/config.json similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/config.json rename to data/script_groups/group_5/user_1/project_default/config.json diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_143613.png b/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_143613.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_143613.png rename to data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_143613.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_152213.png b/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_152213.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_152213.png rename to data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_152213.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_153124.png b/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_153124.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_153124.png rename to data/script_groups/group_5/user_1/project_default/exports/flow_plot_20250912_153124.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250912_213034.pdf b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250912_213034.pdf similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250912_213034.pdf rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250912_213034.pdf diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250912_213103.pdf b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250912_213103.pdf similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250912_213103.pdf rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250912_213103.pdf diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250913_010718.pdf b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250913_010718.pdf similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250913_010718.pdf rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_20250913_010718.pdf diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_124706.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_124706.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_124706.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_124706.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_125103.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_125103.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_125103.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_125103.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_125141.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_125141.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_125141.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_125141.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_132938.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_132938.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_132938.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_132938.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_134957.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_134957.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_134957.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_134957.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_135403.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_135403.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_135403.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_135403.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_135518.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_135518.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_135518.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_135518.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_141450.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_141450.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_141450.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_141450.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_141533.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_141533.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_141533.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_141533.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_143613.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_143613.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_143613.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_143613.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_152213.zip b/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_152213.zip similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_152213.zip rename to data/script_groups/group_5/user_1/project_default/exports/hammer_analysis_obsidian_20250912_152213.zip diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_143613.png b/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_143613.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_143613.png rename to data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_143613.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_152213.png b/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_152213.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_152213.png rename to data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_152213.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_153124.png b/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_153124.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_153124.png rename to data/script_groups/group_5/user_1/project_default/exports/pressure_plot_20250912_153124.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_143613.png b/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_143613.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_143613.png rename to data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_143613.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_152213.png b/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_152213.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_152213.png rename to data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_152213.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_153124.png b/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_153124.png similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_153124.png rename to data/script_groups/group_5/user_1/project_default/exports/summary_plot_20250912_153124.png diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/hammer_config.json b/data/script_groups/group_5/user_1/project_default/hammer_config.json similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/hammer_config.json rename to data/script_groups/group_5/user_1/project_default/hammer_config.json diff --git a/SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/hammer_results.json b/data/script_groups/group_5/user_1/project_default/hammer_results.json similarity index 100% rename from SIDELManagerScripts/data/script_groups/group_5/user_1/project_default/hammer_results.json rename to data/script_groups/group_5/user_1/project_default/hammer_results.json diff --git a/SIDELManagerScripts/data/scriptsmanager.db b/data/scriptsmanager.db similarity index 100% rename from SIDELManagerScripts/data/scriptsmanager.db rename to data/scriptsmanager.db diff --git a/SIDELManagerScripts/debug_discovery.py b/debug_discovery.py similarity index 100% rename from SIDELManagerScripts/debug_discovery.py rename to debug_discovery.py diff --git a/SIDELManagerScripts/demo_scriptsmanager_integration.py b/demo_scriptsmanager_integration.py similarity index 100% rename from SIDELManagerScripts/demo_scriptsmanager_integration.py rename to demo_scriptsmanager_integration.py diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..73e597b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,190 @@ +version: '3.8' + +services: + # Servicio principal de SIDEL ScriptsManager + scriptsmanager: + build: . + container_name: sidel_scriptsmanager + ports: + - "5002:5002" # Puerto principal del frontend Flask (según run_app.py) + - "5200-5400:5200-5400" # Rango de puertos para scripts dinámicos (especificación SIDEL) + volumes: + # Volúmenes para persistencia de datos multiusuario según especificaciones + - ./data:/app/data + - ./backup:/app/backup + - ./logs:/app/logs + # Scripts de backend (SOLO app/backend/script_groups/) + - ./app/backend/script_groups:/app/app/backend/script_groups + # Base de datos SQLite + - ./data/scriptsmanager.db:/app/data/scriptsmanager.db + environment: + # Variables de entorno según especificaciones SIDEL ScriptsManager + - DEBUG=false + - SECRET_KEY=sidel-scriptsmanager-production-key-change-this + - DATABASE_URL=sqlite:///app/data/scriptsmanager.db + - BASE_DATA_PATH=/app/data + - BACKUP_ENABLED=true + - PORT_RANGE_START=5200 + - PORT_RANGE_END=5400 + - MAX_PROJECTS_PER_USER=50 + # Variables multiusuario y multi-proyecto + - DEFAULT_LANGUAGE=en + - SUPPORTED_LANGUAGES=en,es,it,fr + - DEFAULT_THEME=light + # Variables para conda - Entornos según especificaciones + - CONDA_DEFAULT_ENV=scriptsmanager + - TSNET_ENV=tsnet + - PYTHONPATH=/app + # Variables específicas de SIDEL + - SIDEL_LOGO_PATH=/app/app/static/images/SIDEL.png + - CORPORATE_BRANDING=true + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5002/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + networks: + - scriptsmanager_network + + # Servicio para desarrollo con hot-reload + scriptsmanager-dev: + build: . + container_name: sidel_scriptsmanager_dev + ports: + - "5003:5002" # Puerto de desarrollo para el frontend + - "5201-5401:5200-5400" # Rango de puertos para desarrollo + volumes: + # Montar código completo para desarrollo + - .:/app + - ./data:/app/data + - ./backup:/app/backup + - ./logs:/app/logs + environment: + - DEBUG=true + - SECRET_KEY=sidel-dev-secret-key + - DATABASE_URL=sqlite:///app/data/scriptsmanager_dev.db + - FLASK_ENV=development + - BASE_DATA_PATH=/app/data + - BACKUP_ENABLED=false + - PORT_RANGE_START=5200 + - PORT_RANGE_END=5400 + - MAX_PROJECTS_PER_USER=100 + - DEFAULT_LANGUAGE=en + - SUPPORTED_LANGUAGES=en,es,it,fr + - DEFAULT_THEME=light + - CONDA_DEFAULT_ENV=scriptsmanager + - TSNET_ENV=tsnet + - PYTHONPATH=/app + - SIDEL_LOGO_PATH=/app/app/static/images/SIDEL.png + - CORPORATE_BRANDING=true + command: > + bash -c "source activate scriptsmanager && + python scripts/init_db.py && + python scripts/run_app.py" + profiles: + - dev + networks: + - scriptsmanager_network + + # Servicio para backup automático según especificaciones SIDEL + backup: + build: . + container_name: sidel_backup_service + volumes: + - ./data:/app/data + - ./backup:/app/backup + - ./logs:/app/logs + environment: + - BACKUP_ENABLED=true + - BACKUP_RETENTION_DAYS=30 + - DATABASE_URL=sqlite:///app/data/scriptsmanager.db + - PYTHONPATH=/app + command: > + bash -c "source activate scriptsmanager && + while true; do + echo '=== Starting daily backup ===' + python -c 'from app.services.backup_service import BackupService; BackupService().create_backup()' + echo '=== Backup completed ===' + sleep 86400 # Backup diario (24 horas) + done" + profiles: + - backup + networks: + - scriptsmanager_network + + # Servicio de monitoreo de logs (opcional) + log-monitor: + build: . + container_name: sidel_log_monitor + volumes: + - ./logs:/app/logs + - ./data:/app/data + environment: + - DATABASE_URL=sqlite:///app/data/scriptsmanager.db + - PYTHONPATH=/app + command: > + bash -c "source activate scriptsmanager && + python -c ' + import time + from app.services.log_service import LogService + print(\"Starting log monitor service...\") + while True: + try: + # Cleanup de logs antiguos según políticas de retención + LogService().cleanup_old_logs() + time.sleep(3600) # Cleanup cada hora + except Exception as e: + print(f\"Log monitor error: {e}\") + time.sleep(60) + '" + profiles: + - monitoring + networks: + - scriptsmanager_network + + # Base de datos separada (opcional, si quieres usar PostgreSQL en lugar de SQLite) + postgres: + image: postgres:15 + container_name: sidel_postgres + environment: + - POSTGRES_DB=scriptsmanager + - POSTGRES_USER=scriptsmanager + - POSTGRES_PASSWORD=scriptsmanager_password + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "5432:5432" + profiles: + - postgres + networks: + - scriptsmanager_network + + # Servicio para backup automático + backup: + build: . + container_name: sidel_backup + volumes: + - ./data:/app/data + - ./backup:/app/backup + environment: + - BACKUP_ENABLED=true + - PYTHONPATH=/app + command: > + bash -c "source activate scriptsmanager && + while true; do + python -c 'from app.services.backup_service import BackupService; BackupService().create_backup()' + sleep 86400 # Backup diario + done" + profiles: + - backup + networks: + - scriptsmanager_network + +volumes: + postgres_data: + +networks: + scriptsmanager_network: + driver: bridge \ No newline at end of file diff --git a/docker-manage.sh b/docker-manage.sh new file mode 100755 index 0000000..70b11db --- /dev/null +++ b/docker-manage.sh @@ -0,0 +1,496 @@ +#!/bin/bash + +# Script de gestión Docker para SIDEL ScriptsManager +# Compatible con las especificaciones del proyecto +# Uso: ./docker-manage.sh [comando] + +set -e + +# Colores para output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +NC='\033[0m' # No Color + +# Variables del proyecto SIDEL +SIDEL_APP_PORT=5002 +SIDEL_DEV_PORT=5003 +SIDEL_SCRIPT_PORT_RANGE="5200-5400" +SIDEL_CONTAINER_NAME="sidel_scriptsmanager" +SIDEL_DEV_CONTAINER_NAME="sidel_scriptsmanager_dev" + +# Función para mostrar banner SIDEL +show_banner() { + echo -e "${BLUE}================================================================${NC}" + echo -e "${BLUE} SIDEL ScriptsManager - Docker Management ${NC}" + echo -e "${BLUE}================================================================${NC}" + echo -e "${PURPLE}Multi-User Script Manager with Conda Environments${NC}" + echo -e "${PURPLE}Frontend Port: ${SIDEL_APP_PORT} | Script Ports: ${SIDEL_SCRIPT_PORT_RANGE}${NC}" + echo -e "${BLUE}================================================================${NC}" + echo "" +} + +# Función para mostrar ayuda +show_help() { + show_banner + echo "Uso: $0 [comando]" + echo "" + echo "Comandos disponibles:" + echo -e " ${GREEN}build${NC} Construir la imagen Docker" + echo -e " ${GREEN}start${NC} Iniciar SIDEL ScriptsManager en producción" + echo -e " ${GREEN}start-dev${NC} Iniciar en modo desarrollo con hot-reload" + echo -e " ${GREEN}start-backup${NC} Iniciar servicio de backup automático" + echo -e " ${GREEN}start-monitoring${NC} Iniciar servicio de monitoreo de logs" + echo -e " ${GREEN}stop${NC} Detener todos los contenedores" + echo -e " ${GREEN}restart${NC} Reiniciar el contenedor principal" + echo -e " ${GREEN}logs${NC} Mostrar logs del contenedor principal" + echo -e " ${GREEN}logs-dev${NC} Mostrar logs del contenedor de desarrollo" + echo -e " ${GREEN}shell${NC} Abrir shell en el contenedor principal" + echo -e " ${GREEN}shell-dev${NC} Abrir shell en el contenedor de desarrollo" + echo -e " ${GREEN}backup${NC} Ejecutar backup manual del sistema" + echo -e " ${GREEN}clean${NC} Limpiar contenedores e imágenes no utilizadas" + echo -e " ${GREEN}reset${NC} Resetear completamente (¡CUIDADO: Borra datos!)" + echo -e " ${GREEN}status${NC} Mostrar estado de los contenedores" + echo -e " ${GREEN}envs${NC} Listar entornos conda disponibles" + echo -e " ${GREEN}health${NC} Verificar salud de la aplicación" + echo -e " ${GREEN}init-db${NC} Inicializar base de datos SIDEL" + echo -e " ${GREEN}verify${NC} Verificar configuración y entornos" + echo -e " ${GREEN}ports${NC} Mostrar puertos en uso" + echo -e " ${GREEN}users${NC} Gestionar usuarios (requiere shell activo)" + echo "" + echo "Servicios opcionales (perfiles):" + echo -e " ${YELLOW}--profile dev${NC} Modo desarrollo" + echo -e " ${YELLOW}--profile backup${NC} Backup automático" + echo -e " ${YELLOW}--profile monitoring${NC} Monitoreo de logs" + echo "" + echo "Ejemplos:" + echo " $0 build && $0 start" + echo " $0 start-dev" + echo " $0 logs -f" + echo " $0 verify" +} + +# Función para verificar si docker-compose está disponible +check_docker_compose() { + # Verificar permisos de Docker primero + if ! docker ps &> /dev/null; then + echo -e "${RED}Error: No tienes permisos para acceder a Docker${NC}" + echo -e "${YELLOW}Soluciones posibles:${NC}" + echo "1. Reinicia tu terminal/WSL después de agregar tu usuario al grupo docker" + echo "2. O ejecuta: sudo usermod -aG docker \$USER && newgrp docker" + echo "3. O usa sudo: sudo ./docker-manage.sh [comando]" + echo "4. O ejecuta: su - \$USER (para recargar grupos)" + exit 1 + fi + + if command -v docker-compose &> /dev/null; then + DOCKER_COMPOSE="docker-compose" + elif docker compose version &> /dev/null; then + DOCKER_COMPOSE="docker compose" + else + echo -e "${RED}Error: docker-compose no está disponible${NC}" + echo -e "${YELLOW}Instalando docker-compose...${NC}" + + # Intentar instalar docker-compose + if command -v apt &> /dev/null; then + sudo apt update && sudo apt install -y docker-compose + elif command -v yum &> /dev/null; then + sudo yum install -y docker-compose + else + echo "Por favor instala docker-compose manualmente" + exit 1 + fi + + # Verificar nuevamente + if command -v docker-compose &> /dev/null; then + DOCKER_COMPOSE="docker-compose" + else + exit 1 + fi + fi +} + +# Función para construir la imagen +build_image() { + show_banner + echo -e "${BLUE}Construyendo imagen Docker para SIDEL ScriptsManager...${NC}" + check_docker_compose + + # Verificar estructura de directorios antes de construir + if [ -d "backend/script_groups" ]; then + echo -e "${RED}❌ ERROR: Encontrado directorio incorrecto 'backend/script_groups/'${NC}" + echo -e "${RED} Según especificaciones SIDEL, los scripts deben estar en 'app/backend/script_groups/' únicamente${NC}" + exit 1 + fi + + if [ ! -d "app/backend/script_groups" ]; then + echo -e "${YELLOW}⚠️ Creando directorio app/backend/script_groups/...${NC}" + mkdir -p app/backend/script_groups/hammer + mkdir -p app/backend/script_groups/data_processing + mkdir -p app/backend/script_groups/system_utilities + fi + + $DOCKER_COMPOSE build scriptsmanager + echo -e "${GREEN}✅ Imagen SIDEL ScriptsManager construida exitosamente${NC}" +} + +# Función para iniciar en producción +start_production() { + show_banner + echo -e "${BLUE}Iniciando SIDEL ScriptsManager en modo producción...${NC}" + check_docker_compose + + # Crear directorios necesarios según especificaciones SIDEL + echo -e "${BLUE}Preparando estructura de directorios...${NC}" + mkdir -p data/script_groups data/system + mkdir -p logs/executions logs/system logs/audit + mkdir -p backup/daily + mkdir -p instance + + # Copiar archivo de entorno si no existe + if [ ! -f .env ]; then + echo -e "${YELLOW}Creando archivo .env desde .env.example${NC}" + cp .env.example .env + echo -e "${YELLOW}¡IMPORTANTE: Edita el archivo .env con tus configuraciones de producción!${NC}" + fi + + $DOCKER_COMPOSE up -d scriptsmanager + echo -e "${GREEN}✅ SIDEL ScriptsManager iniciado en http://localhost:${SIDEL_APP_PORT}${NC}" + echo -e "${BLUE}📊 Dashboard multiusuario disponible${NC}" + echo -e "${BLUE}🔧 Scripts TSNet en puertos ${SIDEL_SCRIPT_PORT_RANGE}${NC}" +} + +# Función para iniciar en desarrollo +start_development() { + show_banner + echo -e "${BLUE}Iniciando SIDEL ScriptsManager en modo desarrollo...${NC}" + check_docker_compose + + mkdir -p data/script_groups data/system + mkdir -p logs/executions logs/system logs/audit + mkdir -p backup/daily + + if [ ! -f .env ]; then + cp .env.example .env + fi + + $DOCKER_COMPOSE --profile dev up -d scriptsmanager-dev + echo -e "${GREEN}✅ SIDEL ScriptsManager (desarrollo) iniciado en http://localhost:${SIDEL_DEV_PORT}${NC}" + echo -e "${BLUE}🔄 Hot-reload activado para desarrollo${NC}" +} + +# Función para iniciar backup automático +start_backup_service() { + show_banner + echo -e "${BLUE}Iniciando servicio de backup automático...${NC}" + check_docker_compose + $DOCKER_COMPOSE --profile backup up -d backup + echo -e "${GREEN}✅ Servicio de backup automático iniciado${NC}" + echo -e "${BLUE}📦 Backups diarios programados${NC}" +} + +# Función para iniciar monitoreo +start_monitoring() { + show_banner + echo -e "${BLUE}Iniciando servicio de monitoreo de logs...${NC}" + check_docker_compose + $DOCKER_COMPOSE --profile monitoring up -d log-monitor + echo -e "${GREEN}✅ Servicio de monitoreo iniciado${NC}" + echo -e "${BLUE}📊 Monitoreo de logs multiusuario activado${NC}" +} + +# Función para detener contenedores +stop_containers() { + echo -e "${BLUE}Deteniendo contenedores...${NC}" + check_docker_compose + $DOCKER_COMPOSE down + echo -e "${GREEN}Contenedores detenidos${NC}" +} + +# Función para reiniciar +restart_container() { + echo -e "${BLUE}Reiniciando contenedor principal...${NC}" + check_docker_compose + $DOCKER_COMPOSE restart scriptsmanager + echo -e "${GREEN}Contenedor reiniciado${NC}" +} + +# Función para mostrar logs +show_logs() { + check_docker_compose + $DOCKER_COMPOSE logs "${@:2}" scriptsmanager +} + +# Función para mostrar logs de desarrollo +show_dev_logs() { + check_docker_compose + $DOCKER_COMPOSE logs "${@:2}" scriptsmanager-dev +} + +# Función para abrir shell +open_shell() { + check_docker_compose + echo -e "${BLUE}Abriendo shell en el contenedor...${NC}" + $DOCKER_COMPOSE exec scriptsmanager bash +} + +# Función para abrir shell de desarrollo +open_dev_shell() { + check_docker_compose + echo -e "${BLUE}Abriendo shell en el contenedor de desarrollo...${NC}" + $DOCKER_COMPOSE exec scriptsmanager-dev bash +} + +# Función para backup manual +manual_backup() { + echo -e "${BLUE}Ejecutando backup manual...${NC}" + check_docker_compose + $DOCKER_COMPOSE exec scriptsmanager bash -c "source activate scriptsmanager && python -c 'from app.services.backup_service import BackupService; BackupService().create_backup()'" + echo -e "${GREEN}Backup completado${NC}" +} + +# Función para limpiar Docker +clean_docker() { + echo -e "${YELLOW}Limpiando contenedores e imágenes no utilizadas...${NC}" + docker system prune -f + echo -e "${GREEN}Limpieza completada${NC}" +} + +# Función para reset completo +reset_all() { + echo -e "${RED}¡ADVERTENCIA! Esto eliminará todos los datos y contenedores.${NC}" + read -p "¿Estás seguro? (escribe 'yes' para continuar): " -r + if [[ $REPLY == "yes" ]]; then + check_docker_compose + $DOCKER_COMPOSE down -v + docker system prune -af + sudo rm -rf data/* backup/* logs/* + echo -e "${GREEN}Reset completado${NC}" + else + echo -e "${YELLOW}Operación cancelada${NC}" + fi +} + +# Función para mostrar estado +show_status() { + echo -e "${BLUE}Estado de los contenedores:${NC}" + check_docker_compose + $DOCKER_COMPOSE ps +} + +# Función para listar entornos conda +list_conda_envs() { + echo -e "${BLUE}Entornos conda disponibles:${NC}" + check_docker_compose + $DOCKER_COMPOSE exec scriptsmanager bash -c "conda env list" +} + +# Función para verificar salud +health_check() { + echo -e "${BLUE}Verificando salud de SIDEL ScriptsManager...${NC}" + if curl -f http://localhost:${SIDEL_APP_PORT}/health >/dev/null 2>&1; then + echo -e "${GREEN}✓ Aplicación saludable en puerto ${SIDEL_APP_PORT}${NC}" + else + echo -e "${RED}✗ Aplicación no responde en puerto ${SIDEL_APP_PORT}${NC}" + exit 1 + fi +} + +# Función para inicializar base de datos SIDEL +init_database() { + show_banner + echo -e "${BLUE}Inicializando base de datos SIDEL ScriptsManager...${NC}" + check_docker_compose + + if ! docker ps | grep -q $SIDEL_CONTAINER_NAME; then + echo -e "${YELLOW}Contenedor no está ejecutándose. Iniciando temporalmente...${NC}" + $DOCKER_COMPOSE up -d scriptsmanager + sleep 10 + fi + + $DOCKER_COMPOSE exec scriptsmanager bash -c "source activate scriptsmanager && python scripts/init_sidel_db.py" + echo -e "${GREEN}✅ Base de datos SIDEL inicializada${NC}" +} + +# Función para verificar configuración completa +verify_configuration() { + show_banner + echo -e "${BLUE}Verificando configuración SIDEL ScriptsManager...${NC}" + + echo -e "${BLUE}📁 Verificando estructura de directorios...${NC}" + + # Verificar directorios críticos + if [ ! -d "app/backend/script_groups" ]; then + echo -e "${RED}❌ app/backend/script_groups/ no encontrado${NC}" + return 1 + else + echo -e "${GREEN}✅ app/backend/script_groups/ correcto${NC}" + fi + + if [ -d "backend/script_groups" ]; then + echo -e "${RED}❌ backend/script_groups/ existe (NO debería existir)${NC}" + return 1 + else + echo -e "${GREEN}✅ backend/script_groups/ no existe (correcto)${NC}" + fi + + # Verificar archivos de configuración + if [ -f "requirements.txt" ]; then + echo -e "${GREEN}✅ requirements.txt encontrado${NC}" + else + echo -e "${RED}❌ requirements.txt no encontrado${NC}" + fi + + if [ -f "app/backend/script_groups/hammer/requirements.txt" ]; then + echo -e "${GREEN}✅ TSNet requirements.txt encontrado${NC}" + else + echo -e "${RED}❌ TSNet requirements.txt no encontrado${NC}" + fi + + # Verificar contenedor si está ejecutándose + if docker ps | grep -q $SIDEL_CONTAINER_NAME; then + echo -e "${BLUE}🐳 Verificando entornos conda en contenedor...${NC}" + + # Verificar entornos conda + echo -e "${BLUE}📋 Entornos conda disponibles:${NC}" + $DOCKER_COMPOSE exec scriptsmanager conda env list + + echo -e "${BLUE}🔍 Verificando paquetes en entorno scriptsmanager:${NC}" + $DOCKER_COMPOSE exec scriptsmanager bash -c "source activate scriptsmanager && python -c 'import flask, flask_socketio; print(f\"Flask: {flask.__version__}, SocketIO: {flask_socketio.__version__}\")'" + + echo -e "${BLUE}🔍 Verificando paquetes en entorno tsnet:${NC}" + $DOCKER_COMPOSE exec scriptsmanager bash -c "source activate tsnet && python -c 'import numpy, matplotlib; print(f\"NumPy: {numpy.__version__}, Matplotlib: {matplotlib.__version__}\")'" + + # Verificar puertos + echo -e "${BLUE}🔌 Verificando puertos:${NC}" + if curl -s http://localhost:${SIDEL_APP_PORT} >/dev/null; then + echo -e "${GREEN}✅ Puerto ${SIDEL_APP_PORT} (frontend) accesible${NC}" + else + echo -e "${YELLOW}⚠️ Puerto ${SIDEL_APP_PORT} (frontend) no accesible${NC}" + fi + else + echo -e "${YELLOW}⚠️ Contenedor no está ejecutándose${NC}" + echo -e "${BLUE}💡 Ejecuta: $0 start${NC}" + fi + + echo -e "${GREEN}✅ Verificación completada${NC}" +} + +# Función para mostrar puertos en uso +show_ports() { + show_banner + echo -e "${BLUE}Estado de puertos SIDEL ScriptsManager:${NC}" + echo "" + echo -e "${BLUE}Puerto Frontend:${NC} ${SIDEL_APP_PORT}" + echo -e "${BLUE}Puerto Desarrollo:${NC} ${SIDEL_DEV_PORT}" + echo -e "${BLUE}Rango Scripts:${NC} ${SIDEL_SCRIPT_PORT_RANGE}" + echo "" + + if command -v netstat >/dev/null 2>&1; then + echo -e "${BLUE}Puertos actualmente en uso:${NC}" + netstat -tlnp 2>/dev/null | grep -E ":(5002|5003|520[0-9]|53[0-9][0-9]|5400)" || echo "Ningún puerto SIDEL en uso" + elif command -v ss >/dev/null 2>&1; then + echo -e "${BLUE}Puertos actualmente en uso:${NC}" + ss -tlnp | grep -E ":(5002|5003|520[0-9]|53[0-9][0-9]|5400)" || echo "Ningún puerto SIDEL en uso" + else + echo -e "${YELLOW}⚠️ netstat/ss no disponible para verificar puertos${NC}" + fi +} + +# Función para gestión de usuarios +manage_users() { + show_banner + echo -e "${BLUE}Gestión de usuarios SIDEL ScriptsManager${NC}" + + if ! docker ps | grep -q $SIDEL_CONTAINER_NAME; then + echo -e "${RED}❌ El contenedor no está ejecutándose${NC}" + echo -e "${BLUE}💡 Ejecuta: $0 start${NC}" + return 1 + fi + + echo -e "${BLUE}Abriendo shell para gestión de usuarios...${NC}" + echo -e "${YELLOW}Comandos útiles:${NC}" + echo " - python scripts/create_admin.py --username --password " + echo " - python scripts/list_users.py" + echo " - python scripts/manage_users.py" + echo "" + + $DOCKER_COMPOSE exec scriptsmanager bash -c "source activate scriptsmanager && bash" +} + +# Script principal +case "${1:-help}" in + build) + build_image + ;; + start) + start_production + ;; + start-dev) + start_development + ;; + start-backup) + start_backup_service + ;; + start-monitoring) + start_monitoring + ;; + stop) + stop_containers + ;; + restart) + restart_container + ;; + logs) + show_logs "$@" + ;; + logs-dev) + show_dev_logs "$@" + ;; + shell) + open_shell + ;; + shell-dev) + open_dev_shell + ;; + backup) + manual_backup + ;; + clean) + clean_docker + ;; + reset) + reset_all + ;; + status) + show_status + ;; + envs) + list_conda_envs + ;; + health) + health_check + ;; + init-db) + init_database + ;; + verify) + verify_configuration + ;; + ports) + show_ports + ;; + users) + manage_users + ;; + help|--help|-h) + show_help + ;; + *) + echo -e "${RED}Comando desconocido: $1${NC}" + show_help + exit 1 + ;; +esac \ No newline at end of file diff --git a/docker-sudo.sh b/docker-sudo.sh new file mode 100755 index 0000000..8e8eb5b --- /dev/null +++ b/docker-sudo.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Script temporal para ejecutar docker-manage.sh con sudo hasta reiniciar sesión +# Uso: ./docker-sudo.sh [comando] + +echo "=== SIDEL ScriptsManager - Docker con SUDO ===" +echo "Nota: Ejecutando con sudo hasta que reinicies tu terminal/WSL" +echo "Después del reinicio podrás usar ./docker-manage.sh directamente" +echo "" + +if [ $# -eq 0 ]; then + echo "Uso: $0 [comando]" + echo "Ejemplos:" + echo " $0 build" + echo " $0 start" + echo " $0 status" + echo " $0 help" + exit 1 +fi + +# Ejecutar docker-manage.sh con sudo +sudo ./docker-manage.sh "$@" \ No newline at end of file diff --git a/SIDELManagerScripts/example_script.py b/example_script.py similarity index 100% rename from SIDELManagerScripts/example_script.py rename to example_script.py diff --git a/install-docker.sh b/install-docker.sh new file mode 100755 index 0000000..7a56165 --- /dev/null +++ b/install-docker.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +# Script de instalación automatizada para SIDEL ScriptsManager Docker +# Este script automatiza todo el proceso de configuración inicial + +set -e + +# Colores para output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Banner +echo -e "${BLUE}" +echo "╔══════════════════════════════════════════════════════════════╗" +echo "║ SIDEL ScriptsManager Docker Setup ║" +echo "║ Instalación Automatizada ║" +echo "╚══════════════════════════════════════════════════════════════╝" +echo -e "${NC}" + +# Verificar que estamos en el directorio correcto +if [ ! -f "Dockerfile" ] || [ ! -f "docker-compose.yml" ]; then + echo -e "${RED}Error: No se encontraron los archivos Docker necesarios${NC}" + echo "Asegúrate de estar en el directorio SIDELManagerScripts" + exit 1 +fi + +echo -e "${GREEN}✓ Archivos Docker encontrados${NC}" + +# Verificar que Docker está disponible +if ! command -v docker &> /dev/null; then + echo -e "${RED}Error: Docker no está instalado o no está en el PATH${NC}" + echo "Instala Docker antes de continuar" + exit 1 +fi + +echo -e "${GREEN}✓ Docker disponible${NC}" + +# Verificar que docker-compose está disponible +if command -v docker-compose &> /dev/null; then + DOCKER_COMPOSE="docker-compose" +elif docker compose version &> /dev/null; then + DOCKER_COMPOSE="docker compose" +else + echo -e "${RED}Error: docker-compose no está disponible${NC}" + exit 1 +fi + +echo -e "${GREEN}✓ Docker Compose disponible ($DOCKER_COMPOSE)${NC}" + +# Dar permisos de ejecución a scripts +echo -e "${BLUE}Configurando permisos...${NC}" +chmod +x docker-manage.sh +chmod +x verify-environments.sh +if [ -f "install-docker.sh" ]; then + chmod +x install-docker.sh +fi +echo -e "${GREEN}✓ Permisos configurados${NC}" + +# Crear archivo .env si no existe +if [ ! -f ".env" ]; then + echo -e "${BLUE}Creando archivo de configuración...${NC}" + cp .env.example .env + echo -e "${YELLOW}⚠️ Archivo .env creado desde .env.example${NC}" + echo -e "${YELLOW}⚠️ IMPORTANTE: Edita .env con tus configuraciones antes de usar en producción${NC}" +else + echo -e "${GREEN}✓ Archivo .env ya existe${NC}" +fi + +# Crear directorios necesarios +echo -e "${BLUE}Creando estructura de directorios...${NC}" +mkdir -p data backup logs +mkdir -p data/script_groups/hammer data/script_groups/group_2 data/script_groups/group_3 data/script_groups/group_5 +mkdir -p data/script_groups/logs +mkdir -p logs/executions logs/system logs/audit +echo -e "${GREEN}✓ Estructura de directorios creada${NC}" + +# Preguntar al usuario qué hacer +echo "" +echo -e "${BLUE}¿Qué deseas hacer?${NC}" +echo "1) Solo preparar (no construir imagen ni iniciar)" +echo "2) Construir imagen Docker" +echo "3) Construir imagen e iniciar en producción" +echo "4) Construir imagen e iniciar en desarrollo" +echo "5) Instalación completa con verificación" + +read -p "Selecciona una opción (1-5): " -r OPTION + +case $OPTION in + 1) + echo -e "${GREEN}✓ Preparación completada${NC}" + echo "" + echo "Próximos pasos:" + echo " ./docker-manage.sh build # Construir imagen" + echo " ./docker-manage.sh start # Iniciar producción" + ;; + 2) + echo -e "${BLUE}Construyendo imagen Docker...${NC}" + ./docker-manage.sh build + echo -e "${GREEN}✓ Imagen construida exitosamente${NC}" + echo "" + echo "Para iniciar: ./docker-manage.sh start" + ;; + 3) + echo -e "${BLUE}Construyendo imagen e iniciando en producción...${NC}" + ./docker-manage.sh build + ./docker-manage.sh start + echo "" + echo -e "${GREEN}✓ SIDEL ScriptsManager iniciado en http://localhost:5002${NC}" + ;; + 4) + echo -e "${BLUE}Construyendo imagen e iniciando en desarrollo...${NC}" + ./docker-manage.sh build + ./docker-manage.sh start-dev + echo "" + echo -e "${GREEN}✓ SIDEL ScriptsManager (dev) iniciado en http://localhost:5003${NC}" + ;; + 5) + echo -e "${BLUE}Realizando instalación completa...${NC}" + + # Construir imagen + echo -e "${BLUE}Paso 1/4: Construyendo imagen Docker...${NC}" + ./docker-manage.sh build + + # Iniciar aplicación + echo -e "${BLUE}Paso 2/4: Iniciando aplicación...${NC}" + ./docker-manage.sh start + + # Esperar un momento para que la aplicación se inicie + echo -e "${BLUE}Paso 3/4: Esperando que la aplicación se inicie...${NC}" + sleep 10 + + # Verificar instalación + echo -e "${BLUE}Paso 4/4: Verificando instalación...${NC}" + ./verify-environments.sh + + echo "" + echo -e "${GREEN}🎉 Instalación completa exitosa!${NC}" + echo -e "${GREEN}✓ SIDEL ScriptsManager disponible en http://localhost:5002${NC}" + ;; + *) + echo -e "${RED}Opción inválida${NC}" + exit 1 + ;; +esac + +echo "" +echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" +echo -e "${GREEN}Comandos útiles:${NC}" +echo -e " ${YELLOW}./docker-manage.sh status${NC} # Ver estado de contenedores" +echo -e " ${YELLOW}./docker-manage.sh logs${NC} # Ver logs de la aplicación" +echo -e " ${YELLOW}./docker-manage.sh shell${NC} # Acceder al contenedor" +echo -e " ${YELLOW}./docker-manage.sh stop${NC} # Detener la aplicación" +echo -e " ${YELLOW}./docker-manage.sh help${NC} # Ver todos los comandos disponibles" +echo "" +echo -e "${GREEN}Documentación:${NC}" +echo -e " ${YELLOW}README-Docker.md${NC} # Guía completa de Docker" +echo -e " ${YELLOW}MIGRATION-GUIDE.md${NC} # Guía de migración detallada" +echo -e " ${YELLOW}conda-environments.md${NC} # Información de entornos conda" +echo "" +echo -e "${BLUE}¡Instalación de SIDEL ScriptsManager Docker completada!${NC}" \ No newline at end of file diff --git a/SIDELManagerScripts/migrate_execution_logs.py b/migrate_execution_logs.py similarity index 100% rename from SIDELManagerScripts/migrate_execution_logs.py rename to migrate_execution_logs.py diff --git a/SIDELManagerScripts/requirements-dev.txt b/requirements-dev.txt similarity index 100% rename from SIDELManagerScripts/requirements-dev.txt rename to requirements-dev.txt diff --git a/SIDELManagerScripts/requirements.txt b/requirements.txt similarity index 100% rename from SIDELManagerScripts/requirements.txt rename to requirements.txt diff --git a/scriptmanager.code-workspace b/scriptmanager.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/scriptmanager.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/SIDELManagerScripts/scripts/create_admin.py b/scripts/create_admin.py similarity index 100% rename from SIDELManagerScripts/scripts/create_admin.py rename to scripts/create_admin.py diff --git a/SIDELManagerScripts/scripts/init_db.py b/scripts/init_db.py similarity index 100% rename from SIDELManagerScripts/scripts/init_db.py rename to scripts/init_db.py diff --git a/scripts/init_sidel_db.py b/scripts/init_sidel_db.py new file mode 100644 index 0000000..c2e44af --- /dev/null +++ b/scripts/init_sidel_db.py @@ -0,0 +1,383 @@ +#!/usr/bin/env python3 +""" +Script de inicialización de base de datos para SIDEL ScriptsManager +Implementa el esquema completo según las especificaciones del proyecto +""" + +import os +import sqlite3 +import sys +from pathlib import Path +from datetime import datetime +import hashlib +import json + +# Agregar el directorio raíz del proyecto al path +project_root = Path(__file__).parent.parent +sys.path.insert(0, str(project_root)) + +def create_database_schema(db_path): + """ + Crear el esquema completo de la base de datos SQLite + según las especificaciones SIDEL ScriptsManager + """ + + # Crear directorio si no existe + db_dir = os.path.dirname(db_path) + if db_dir: + os.makedirs(db_dir, exist_ok=True) + + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + print(f"Inicializando base de datos SQLite en: {db_path}") + + # === TABLA USERS === + print("Creando tabla users...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(100) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + user_level VARCHAR(20) NOT NULL CHECK (user_level IN ('admin', 'developer', 'operator', 'viewer')), + preferred_language VARCHAR(5) DEFAULT 'en' CHECK (preferred_language IN ('en', 'es', 'it', 'fr')), + preferred_theme VARCHAR(10) DEFAULT 'light' CHECK (preferred_theme IN ('light', 'dark')), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_login TIMESTAMP, + is_active BOOLEAN DEFAULT TRUE + ) + """) + + # === TABLA SCRIPT_GROUPS === + print("Creando tabla script_groups...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS script_groups ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR(100) NOT NULL, + directory_path VARCHAR(255) NOT NULL, + description TEXT, + required_level VARCHAR(20) NOT NULL CHECK (required_level IN ('admin', 'developer', 'operator', 'viewer')), + conda_environment VARCHAR(100) DEFAULT 'base', + is_active BOOLEAN DEFAULT TRUE, + discovered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + + # === TABLA SCRIPTS === + print("Creando tabla scripts...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS scripts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + group_id INTEGER REFERENCES script_groups(id) ON DELETE CASCADE, + filename VARCHAR(100) NOT NULL, + display_name VARCHAR(100), + description TEXT, + description_long_path VARCHAR(255), + tags TEXT, + required_level VARCHAR(20) NOT NULL CHECK (required_level IN ('admin', 'developer', 'operator', 'viewer')), + parameters JSON, + execution_timeout INTEGER DEFAULT 300, + flask_port INTEGER, + is_active BOOLEAN DEFAULT TRUE, + last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(group_id, filename) + ) + """) + + # === TABLA USER_SCRIPT_TAGS === + print("Creando tabla user_script_tags...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS user_script_tags ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, + script_id INTEGER REFERENCES scripts(id) ON DELETE CASCADE, + tags TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(user_id, script_id) + ) + """) + + # === TABLA CONDA_ENVIRONMENTS === + print("Creando tabla conda_environments...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS conda_environments ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR(100) UNIQUE NOT NULL, + path VARCHAR(255) NOT NULL, + python_version VARCHAR(20), + is_available BOOLEAN DEFAULT TRUE, + detected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_verified TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + + # === TABLA USER_PROJECTS === + print("Creando tabla user_projects...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS user_projects ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, + project_name VARCHAR(100) NOT NULL, + group_id INTEGER REFERENCES script_groups(id) ON DELETE CASCADE, + description TEXT, + is_default BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_accessed TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(user_id, project_name, group_id) + ) + """) + + # === TABLA PORT_ALLOCATIONS === + print("Creando tabla port_allocations...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS port_allocations ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + port_number INTEGER UNIQUE NOT NULL CHECK (port_number >= 5200 AND port_number <= 5400), + script_id INTEGER REFERENCES scripts(id) ON DELETE CASCADE, + user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, + project_id INTEGER REFERENCES user_projects(id) ON DELETE CASCADE, + process_id INTEGER, + status VARCHAR(20) NOT NULL CHECK (status IN ('allocated', 'active', 'released')), + allocated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + released_at TIMESTAMP + ) + """) + + # === TABLA SCRIPT_PROCESSES === + print("Creando tabla script_processes...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS script_processes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + script_id INTEGER REFERENCES scripts(id) ON DELETE CASCADE, + user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, + process_id INTEGER NOT NULL, + flask_port INTEGER CHECK (flask_port >= 5200 AND flask_port <= 5400), + tab_session_id VARCHAR(100), + status VARCHAR(20) NOT NULL CHECK (status IN ('starting', 'running', 'stopped', 'failed')), + started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_ping TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + ended_at TIMESTAMP + ) + """) + + # === TABLA EXECUTION_LOGS === + print("Creando tabla execution_logs...") + cursor.execute(""" + CREATE TABLE IF NOT EXISTS execution_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + script_id INTEGER REFERENCES scripts(id) ON DELETE CASCADE, + user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, + project_id INTEGER REFERENCES user_projects(id) ON DELETE CASCADE, + session_id VARCHAR(100), + execution_uuid VARCHAR(36) UNIQUE NOT NULL, + status VARCHAR(20) NOT NULL CHECK (status IN ('running', 'completed', 'failed', 'terminated')), + start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + end_time TIMESTAMP, + duration_seconds INTEGER, + output TEXT, + error_output TEXT, + debug_output TEXT, + exit_code INTEGER, + parameters JSON, + conda_environment VARCHAR(100), + flask_port INTEGER, + log_level VARCHAR(10) DEFAULT 'INFO' CHECK (log_level IN ('DEBUG', 'INFO', 'WARNING', 'ERROR')), + tags TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + + # === ÍNDICES PARA OPTIMIZACIÓN === + print("Creando índices...") + + # Índices para búsquedas frecuentes + cursor.execute("CREATE INDEX IF NOT EXISTS idx_users_username ON users(username)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_scripts_group_id ON scripts(group_id)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_user_projects_user_id ON user_projects(user_id)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_user_projects_group_id ON user_projects(group_id)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_execution_logs_user_id ON execution_logs(user_id)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_execution_logs_script_id ON execution_logs(script_id)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_execution_logs_project_id ON execution_logs(project_id)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_execution_logs_status ON execution_logs(status)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_execution_logs_start_time ON execution_logs(start_time)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_port_allocations_port ON port_allocations(port_number)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_port_allocations_status ON port_allocations(status)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_script_processes_user_id ON script_processes(user_id)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_script_processes_status ON script_processes(status)") + + conn.commit() + conn.close() + + print("✅ Esquema de base de datos creado exitosamente") + +def create_default_data(db_path): + """ + Crear datos iniciales según especificaciones SIDEL + """ + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + print("Insertando datos iniciales...") + + # === ENTORNOS CONDA POR DEFECTO === + print("Agregando entornos conda...") + conda_envs = [ + ('scriptsmanager', '/opt/conda/envs/scriptsmanager', '3.12', True), + ('tsnet', '/opt/conda/envs/tsnet', '3.12', True), + ('base', '/opt/conda', '3.12', True) + ] + + for env_name, env_path, python_ver, is_available in conda_envs: + cursor.execute(""" + INSERT OR IGNORE INTO conda_environments + (name, path, python_version, is_available) + VALUES (?, ?, ?, ?) + """, (env_name, env_path, python_ver, is_available)) + + # === USUARIO ADMINISTRADOR POR DEFECTO === + print("Creando usuario administrador por defecto...") + + # Hash de la contraseña "admin123" (cambiar en producción) + password = "admin123" + password_hash = hashlib.sha256(password.encode()).hexdigest() + + cursor.execute(""" + INSERT OR IGNORE INTO users + (username, email, password_hash, user_level, preferred_language, preferred_theme) + VALUES (?, ?, ?, ?, ?, ?) + """, ('admin', 'admin@sidel.com', password_hash, 'admin', 'en', 'light')) + + # === GRUPOS DE SCRIPTS POR DEFECTO === + print("Creando grupos de scripts...") + + script_groups = [ + ('Water Hammer Simulation', 'app/backend/script_groups/hammer', 'Scripts for water hammer analysis using TSNet', 'operator', 'tsnet'), + ('Data Processing', 'app/backend/script_groups/data_processing', 'Data analysis and processing scripts', 'developer', 'scriptsmanager'), + ('System Utilities', 'app/backend/script_groups/system_utilities', 'System administration and maintenance scripts', 'admin', 'scriptsmanager') + ] + + for name, path, desc, req_level, conda_env in script_groups: + cursor.execute(""" + INSERT OR IGNORE INTO script_groups + (name, directory_path, description, required_level, conda_environment) + VALUES (?, ?, ?, ?, ?) + """, (name, path, desc, req_level, conda_env)) + + conn.commit() + conn.close() + + print("✅ Datos iniciales insertados exitosamente") + +def create_directory_structure(base_path): + """ + Crear estructura de directorios según especificaciones SIDEL + """ + print("Creando estructura de directorios...") + + directories = [ + # Estructura principal de datos + "data/script_groups", + "data/system", + "logs/executions", + "logs/system", + "logs/audit", + "backup/daily", + "instance", + + # Estructura de scripts backend (SOLO app/backend/script_groups/) + "app/backend/script_groups/hammer", + "app/backend/script_groups/data_processing", + "app/backend/script_groups/system_utilities", + "app/backend/logs/executions", + + # Directorios para traducciones e imágenes + "app/translations", + "app/static/images", + "app/static/css", + "app/static/js", + "app/static/icons", + + # Templates + "app/templates/admin" + ] + + for directory in directories: + dir_path = os.path.join(base_path, directory) + os.makedirs(dir_path, exist_ok=True) + print(f" ✓ {directory}") + + # Verificar que NO existe backend/script_groups/ + wrong_path = os.path.join(base_path, "backend/script_groups") + if os.path.exists(wrong_path): + print(f"❌ ERROR: Encontrado directorio incorrecto: {wrong_path}") + print(" Según especificaciones SIDEL, los scripts deben estar SOLO en app/backend/script_groups/") + return False + + print("✅ Estructura de directorios creada correctamente") + return True + +def main(): + """Función principal de inicialización""" + + print("=" * 60) + print("SIDEL ScriptsManager - Inicialización de Base de Datos") + print("=" * 60) + + # Determinar rutas + if os.getenv('DOCKER_CONTAINER'): + # Ejecutándose en Docker + base_path = "/app" + db_path = "/app/data/scriptsmanager.db" + else: + # Ejecutándose localmente + base_path = str(project_root) + db_path = os.path.join(base_path, "data", "scriptsmanager.db") + + print(f"Directorio base: {base_path}") + print(f"Base de datos: {db_path}") + print() + + try: + # Crear estructura de directorios + if not create_directory_structure(base_path): + return 1 + + # Crear esquema de base de datos + create_database_schema(db_path) + + # Insertar datos iniciales + create_default_data(db_path) + + print() + print("=" * 60) + print("✅ INICIALIZACIÓN COMPLETADA EXITOSAMENTE") + print("=" * 60) + print() + print("Credenciales del administrador por defecto:") + print(" Usuario: admin") + print(" Contraseña: admin123") + print(" ⚠️ CAMBIAR ESTA CONTRASEÑA EN PRODUCCIÓN") + print() + print("Entornos conda configurados:") + print(" - scriptsmanager (Frontend Flask)") + print(" - tsnet (Scripts Water Hammer)") + print(" - base (Fallback)") + print() + print("Puerto de la aplicación: 5002") + print("Rango de puertos para scripts: 5200-5400") + print() + + return 0 + + except Exception as e: + print(f"❌ ERROR durante la inicialización: {e}") + import traceback + traceback.print_exc() + return 1 + +if __name__ == "__main__": + exit_code = main() + sys.exit(exit_code) \ No newline at end of file diff --git a/SIDELManagerScripts/scripts/run_app.py b/scripts/run_app.py similarity index 100% rename from SIDELManagerScripts/scripts/run_app.py rename to scripts/run_app.py diff --git a/SIDELManagerScripts/simple_debug.py b/simple_debug.py similarity index 100% rename from SIDELManagerScripts/simple_debug.py rename to simple_debug.py diff --git a/SIDELManagerScripts/test_complete_integration.py b/test_complete_integration.py similarity index 100% rename from SIDELManagerScripts/test_complete_integration.py rename to test_complete_integration.py diff --git a/SIDELManagerScripts/test_hammer_browser.py b/test_hammer_browser.py similarity index 100% rename from SIDELManagerScripts/test_hammer_browser.py rename to test_hammer_browser.py diff --git a/SIDELManagerScripts/test_hammer_calculations.py b/test_hammer_calculations.py similarity index 100% rename from SIDELManagerScripts/test_hammer_calculations.py rename to test_hammer_calculations.py diff --git a/SIDELManagerScripts/test_helper_functions.py b/test_helper_functions.py similarity index 100% rename from SIDELManagerScripts/test_helper_functions.py rename to test_helper_functions.py diff --git a/SIDELManagerScripts/test_language_switching.py b/test_language_switching.py similarity index 100% rename from SIDELManagerScripts/test_language_switching.py rename to test_language_switching.py diff --git a/SIDELManagerScripts/test_model.py b/test_model.py similarity index 100% rename from SIDELManagerScripts/test_model.py rename to test_model.py diff --git a/SIDELManagerScripts/test_permissions.py b/test_permissions.py similarity index 100% rename from SIDELManagerScripts/test_permissions.py rename to test_permissions.py diff --git a/verify-environments.sh b/verify-environments.sh new file mode 100755 index 0000000..05b6053 --- /dev/null +++ b/verify-environments.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +# Script de verificación de entornos Docker para SIDEL Manager Scripts +# Verifica que ambos entornos conda estén correctamente configurados + +echo "=== VERIFICACIÓN DE ENTORNOS CONDA ===" +echo + +# Verificar que el contenedor esté ejecutándose +if ! docker ps | grep -q sidel_scriptsmanager; then + echo "❌ Error: El contenedor sidel_scriptsmanager no está ejecutándose" + echo " Ejecuta: ./docker-manage.sh start" + exit 1 +fi + +echo "✅ Contenedor sidel_scriptsmanager está ejecutándose" +echo + +# Verificar entornos conda disponibles +echo "📋 Entornos conda disponibles:" +docker exec sidel_scriptsmanager conda env list +echo + +# Verificar entorno principal (scriptsmanager) +echo "🔍 Verificando entorno scriptsmanager..." +SCRIPTSMANAGER_PYTHON=$(docker exec sidel_scriptsmanager bash -c "source activate scriptsmanager && python --version") +echo " Python version: $SCRIPTSMANAGER_PYTHON" + +SCRIPTSMANAGER_FLASK=$(docker exec sidel_scriptsmanager bash -c "source activate scriptsmanager && python -c 'import flask; print(f\"Flask {flask.__version__}\")'" 2>/dev/null) +if [ $? -eq 0 ]; then + echo " ✅ $SCRIPTSMANAGER_FLASK" +else + echo " ❌ Error importando Flask" +fi + +SCRIPTSMANAGER_SOCKETIO=$(docker exec sidel_scriptsmanager bash -c "source activate scriptsmanager && python -c 'import flask_socketio; print(f\"Flask-SocketIO {flask_socketio.__version__}\")'" 2>/dev/null) +if [ $? -eq 0 ]; then + echo " ✅ $SCRIPTSMANAGER_SOCKETIO" +else + echo " ❌ Error importando Flask-SocketIO" +fi + +echo + +# Verificar entorno TSNet +echo "🔍 Verificando entorno tsnet..." +TSNET_PYTHON=$(docker exec sidel_scriptsmanager bash -c "source activate tsnet && python --version") +echo " Python version: $TSNET_PYTHON" + +TSNET_VERSION=$(docker exec sidel_scriptsmanager bash -c "source activate tsnet && python -c 'import tsnet; print(f\"TSNet {tsnet.__version__}\")'" 2>/dev/null) +if [ $? -eq 0 ]; then + echo " ✅ $TSNET_VERSION" +else + echo " ❌ Error importando TSNet" +fi + +NUMPY_VERSION=$(docker exec sidel_scriptsmanager bash -c "source activate tsnet && python -c 'import numpy; print(f\"NumPy {numpy.__version__}\")'" 2>/dev/null) +if [ $? -eq 0 ]; then + echo " ✅ $NUMPY_VERSION" +else + echo " ❌ Error importando NumPy" +fi + +MATPLOTLIB_VERSION=$(docker exec sidel_scriptsmanager bash -c "source activate tsnet && python -c 'import matplotlib; print(f\"Matplotlib {matplotlib.__version__}\")'" 2>/dev/null) +if [ $? -eq 0 ]; then + echo " ✅ $MATPLOTLIB_VERSION" +else + echo " ❌ Error importando Matplotlib" +fi + +WNTR_VERSION=$(docker exec sidel_scriptsmanager bash -c "source activate tsnet && python -c 'import wntr; print(f\"WNTR {wntr.__version__}\")'" 2>/dev/null) +if [ $? -eq 0 ]; then + echo " ✅ $WNTR_VERSION" +else + echo " ❌ Error importando WNTR" +fi + +echo + +# Verificar conectividad del frontend +echo "🌐 Verificando conectividad del frontend..." +if curl -s -o /dev/null -w "%{http_code}" http://localhost:5002 | grep -q "200\|404\|500"; then + echo " ✅ Frontend accesible en http://localhost:5002" +else + echo " ❌ Frontend no accesible en http://localhost:5002" +fi + +echo +echo "=== VERIFICACIÓN COMPLETADA ===" +echo +echo "📖 Para más información:" +echo " - Ver logs: ./docker-manage.sh logs" +echo " - Abrir shell: ./docker-manage.sh shell" +echo " - Listar entornos: ./docker-manage.sh envs" +echo " - Estado: ./docker-manage.sh status" \ No newline at end of file diff --git a/SIDELManagerScripts/verify_dashboard_changes.py b/verify_dashboard_changes.py similarity index 100% rename from SIDELManagerScripts/verify_dashboard_changes.py rename to verify_dashboard_changes.py diff --git a/SIDELManagerScripts/verify_design_changes.py b/verify_design_changes.py similarity index 100% rename from SIDELManagerScripts/verify_design_changes.py rename to verify_design_changes.py diff --git a/SIDELManagerScripts/verify_group5.py b/verify_group5.py similarity index 100% rename from SIDELManagerScripts/verify_group5.py rename to verify_group5.py diff --git a/SIDELManagerScripts/verify_navbar_themes.py b/verify_navbar_themes.py similarity index 100% rename from SIDELManagerScripts/verify_navbar_themes.py rename to verify_navbar_themes.py diff --git a/SIDELManagerScripts/verify_sidel_logo.py b/verify_sidel_logo.py similarity index 100% rename from SIDELManagerScripts/verify_sidel_logo.py rename to verify_sidel_logo.py