Files
prezenta_work/oldcode/MODULAR_ARCHITECTURE.md

509 lines
12 KiB
Markdown

# Prezenta Work - Modular Architecture Guide
## Overview
The application has been refactored from a monolithic `app.py` (1334 lines) into a modular structure with separation of concerns. Each module handles a specific responsibility.
---
## Module Structure
### Core Configuration
**File:** `config_settings.py`
- **Purpose:** Centralized configuration management
- **Responsibilities:**
- Server addresses and credentials
- File paths and directories
- Flask configuration
- Hardware settings
- Logging configuration
- Allowed commands list
- Environment variable loading from `.env`
**Key Features:**
- All settings in one place
- Environment variable support (can override defaults)
- Automatic directory creation
- `.env` file support for sensitive data
---
### Logging Module
**File:** `logger_module.py`
- **Purpose:** Unified logging system
- **Responsibilities:**
- Local file logging
- Remote server notifications
- Log rotation (10-day retention)
- Device/table name management
**Key Functions:**
```python
setup_logging() # Configure logger
log_with_server() # Log locally + send to server
send_log_to_server() # Send to monitoring server
read_masa_name() # Get table/room name
delete_old_logs() # Cleanup old logs
```
---
### Device Module
**File:** `device_module.py`
- **Purpose:** Device information management
- **Responsibilities:**
- Get hostname and IP address
- File-based fallback for device info
- Handle network resolution errors
**Key Functions:**
```python
get_device_info() # Returns (hostname, device_ip)
```
---
### System Initialization
**File:** `system_init_module.py`
- **Purpose:** First-run setup and hardware validation
- **Responsibilities:**
- System requirements checking
- Port capability setup (port 80)
- Hardware interface detection (UART/Serial)
- GPIO permission setup
- Network connectivity check
- Required file creation
**Key Functions:**
```python
perform_system_initialization() # Main initialization
check_system_requirements()
check_port_capabilities()
check_hardware_interfaces()
initialize_gpio_permissions()
check_network_connectivity()
create_required_files()
```
---
### Dependencies Management
**File:** `dependencies_module.py`
- **Purpose:** Package installation and verification
- **Responsibilities:**
- Wheel file installation
- Pip package installation
- Apt system package installation
- Dependency verification
**Key Functions:**
```python
check_and_install_dependencies() # Install missing packages
verify_dependencies() # Verify all packages available
install_package_from_wheel() # Install from wheel file
```
---
### Commands Execution
**File:** `commands_module.py`
- **Purpose:** Secure command execution with restrictions
- **Responsibilities:**
- Command allowlist enforcement
- Execution with timeout
- Logging command results
- Error handling and reporting
**Key Functions:**
```python
execute_system_command(command, hostname, device_ip)
```
**Allowed Commands:**
- `sudo apt update`, `sudo apt upgrade -y`
- `sudo apt autoremove -y`, `sudo apt autoclean`
- `sudo reboot`, `sudo shutdown -h now`
- `df -h`, `free -m`, `uptime`, `systemctl status`
- `sudo systemctl restart networking/ssh`
---
### Auto-Update Module
**File:** `autoupdate_module.py`
- **Purpose:** Remote application updates
- **Responsibilities:**
- Version checking
- Remote file downloading
- Backup creation
- Update verification
- Device restart scheduling
**Key Functions:**
```python
perform_auto_update() # Main update process
get_app_version() # Extract version from app
check_remote_version() # Check server version
```
**Process:**
1. Get local app version (from first line: `#App version X.X`)
2. Connect to update server via SSH
3. Compare versions
4. If update available:
- Create backup
- Download new files
- Schedule device restart
---
### Connectivity Module
**File:** `connectivity_module.py`
- **Purpose:** Network monitoring and backup data handling
- **Responsibilities:**
- Periodic connectivity checks
- Fallback data posting
- Harting server integration
**Key Functions:**
```python
check_internet_connection() # Periodic connectivity monitoring
post_backup_data() # Send queued data to Harting server
```
**Features:**
- Checks internet every 45 minutes
- Posts queued URLs from `tag.txt`
- Retry logic for failed posts
- Automatic cleanup of successful posts
---
### API Routes Module
**File:** `api_routes_module.py`
- **Purpose:** Flask API endpoints
- **Responsibilities:**
- Route registration
- Request handling
- Response formatting
**Key Endpoints:**
```
POST /execute_command - Execute allowed system commands
GET /status - Get device status information
POST /auto_update - Trigger application update
```
**Key Functions:**
```python
create_api_routes(app, hostname, device_ip, local_app_path, local_repo_path)
```
---
### RFID Module
**File:** `rfid_module.py`
- **Purpose:** RFID reader initialization
- **Responsibilities:**
- Reader initialization with multiple device attempts
- Error handling and troubleshooting
**Key Functions:**
```python
initialize_rfid_reader() # Initialize RFID reader
```
**Supported Devices:**
- `/dev/ttyS0` - Raspberry Pi default UART
- `/dev/ttyAMA0` - Alternative Pi UART
- `/dev/ttyUSB0` - USB serial adapter
- `/dev/ttyACM0` - USB CDC ACM device
---
### Main Application
**File:** `app_modular.py`
- **Purpose:** Application orchestration and startup
- **Responsibilities:**
- Initialize all modules in sequence
- Start Flask server
- Start connectivity monitoring
- Start RFID reader
- Handle errors and shutdown
**Key Functions:**
```python
main() # Application entry point
initialize_application() # Setup phase
start_flask_server() # Start HTTP API
start_connectivity_monitor() # Background monitoring
start_rfid_reader() # RFID initialization
```
---
## Usage
### Running the Application
```bash
# Run with default configuration
python3 app_modular.py
# Run with environment variables
MONITORING_SERVER_HOST=192.168.1.100 FLASK_PORT=8080 python3 app_modular.py
```
### Environment Variables
Create a `.env` file in the application directory:
```env
# Server Configuration
MONITORING_SERVER_HOST=rpi-ansible
MONITORING_SERVER_PORT=80
AUTO_UPDATE_SERVER_HOST=rpi-ansible
AUTO_UPDATE_SERVER_USER=pi
AUTO_UPDATE_SERVER_PASSWORD=your_password
CONNECTIVITY_CHECK_HOST=10.76.140.17
# Flask Configuration
FLASK_PORT=80
```
### Configuration Files
#### Device Configuration
- **`./data/idmasa.txt`** - Table/room name (used in all logs)
- **`./data/device_info.txt`** - Cached hostname & IP (fallback)
- **`./data/tag.txt`** - Harting server URLs for backup posting
- **`./data/log.txt`** - Application logs (auto-rotated at 10 days)
---
## Dependency Tree
```
app_modular.py (Main)
├── config_settings.py (Configuration)
├── dependencies_module.py (Package Management)
├── system_init_module.py (Initialization)
│ └── config_settings.py
├── device_module.py (Device Info)
│ └── config_settings.py
├── logger_module.py (Logging)
│ ├── config_settings.py
│ └── External: requests
├── connectivity_module.py (Network)
│ ├── config_settings.py
│ ├── logger_module.py
│ └── External: requests
├── commands_module.py (Command Execution)
│ ├── config_settings.py
│ └── logger_module.py
├── autoupdate_module.py (Updates)
│ ├── config_settings.py
│ └── logger_module.py
├── api_routes_module.py (API)
│ ├── commands_module.py
│ ├── autoupdate_module.py
│ ├── logger_module.py
│ └── External: Flask
└── rfid_module.py (RFID)
├── config_settings.py
└── External: rdm6300
```
---
## Migration from Old App
The old monolithic `app.py` has been preserved. To use the new modular version:
```bash
# The old app
python3 app.py
# The new modular app
python3 app_modular.py
```
Both versions can coexist during testing and transition period.
---
## Benefits of Modular Architecture
### ✅ Maintainability
- Each module has a single responsibility
- Easy to locate and fix bugs
- Clear code organization
### ✅ Testability
- Modules can be unit tested independently
- Easier to mock dependencies
- Cleaner test structure
### ✅ Reusability
- Modules can be imported and used elsewhere
- Configuration module can be shared with other apps
- Logger and connectivity modules are standalone
### ✅ Scalability
- Easy to add new features in separate modules
- New endpoints can be added without modifying core code
- Configuration management is centralized
### ✅ Readability
- Smaller files are easier to understand
- Clear module naming reflects responsibility
- Better code organization
### ✅ Flexibility
- Easy to swap implementations
- Configuration can be externalized
- Environment-specific settings via `.env`
---
## Adding New Features
### Example: Add a New API Endpoint
1. Create a new module: `my_feature_module.py`
2. Implement your logic
3. Update `api_routes_module.py` to register the route
4. Test independently
### Example: Change Server Address
Edit `config_settings.py` or set environment variable:
```bash
MONITORING_SERVER_HOST=new-server.com python3 app_modular.py
```
### Example: Modify Allowed Commands
Edit `config_settings.py`:
```python
ALLOWED_COMMANDS = [
# ... existing commands ...
"my_custom_command arg1 arg2"
]
```
---
## Error Handling
Each module follows consistent error handling:
1. **Try-except blocks** for external operations
2. **Logging** of all errors via logger_module
3. **Graceful degradation** when components fail
4. **Informative messages** for debugging
---
## Performance Considerations
- **Modular imports** only load necessary dependencies
- **Lazy loading** of Flask only when available
- **Daemon threads** for background tasks
- **Subprocess timeouts** prevent hanging operations
---
## Troubleshooting
### Port 80 Permission Denied
```bash
sudo setcap cap_net_bind_service=ep $(which python3)
```
### RFID Reader Not Found
```bash
# Add user to dialout group
sudo usermod -a -G dialout $USER
sudo reboot
```
### Cannot Connect to Server
- Check `MONITORING_SERVER_HOST` in config_settings.py
- Verify network connectivity with `ping 8.8.8.8`
- Check firewall rules
### Logs Not Sending
- Verify server endpoint: `http://MONITORING_SERVER_HOST:80/logs`
- Check network connectivity monitor is running
- Review log files for error messages
---
## File Summary
| File | Lines | Purpose |
|------|-------|---------|
| `app_modular.py` | ~200 | Application entry point & orchestration |
| `config_settings.py` | ~200 | Configuration management |
| `logger_module.py` | ~150 | Logging & notifications |
| `device_module.py` | ~100 | Device information |
| `system_init_module.py` | ~300 | System initialization |
| `dependencies_module.py` | ~150 | Package management |
| `commands_module.py` | ~80 | Command execution |
| `autoupdate_module.py` | ~200 | Auto-update functionality |
| `connectivity_module.py` | ~120 | Network monitoring |
| `api_routes_module.py` | ~150 | Flask routes |
| `rfid_module.py` | ~80 | RFID initialization |
| **Total** | **~1530** | **Organized & maintainable** |
---
## Next Steps
1. **Test the new modular app**: `python3 app_modular.py`
2. **Verify all features work**: Test `/status`, `/execute_command`, `/auto_update` endpoints
3. **Update documentation** for your team
4. **Gradually migrate** from old app to new app
5. **Consider systemd service** for automatic startup (see below)
---
## Optional: Systemd Service
Create `/etc/systemd/system/prezenta-work.service`:
```ini
[Unit]
Description=Prezenta Work Attendance System
After=network.target
[Service]
Type=simple
User=pi
WorkingDirectory=/srv/prezenta_work
ExecStart=/usr/bin/python3 /srv/prezenta_work/app_modular.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
```
Then:
```bash
sudo systemctl daemon-reload
sudo systemctl enable prezenta-work
sudo systemctl start prezenta-work
sudo systemctl status prezenta-work
```
---
## Questions or Issues?
Refer to individual module documentation or check logs at:
- **Application logs:** `./data/log.txt`
- **System logs:** `journalctl -u prezenta-work` (if using systemd)