From c91b7d0a4dc039d9f70b42bcc4db7884fdf11948 Mon Sep 17 00:00:00 2001 From: Quality System Admin Date: Wed, 5 Nov 2025 21:25:02 +0200 Subject: [PATCH] Fixed the scan error and backup problems --- backups/backup_schedule.json | 15 +- backups/backups_metadata.json | 9 +- documentation/BACKUP_SCHEDULE_FEATURE.md | 484 +++++ documentation/DATA_ONLY_BACKUP_FEATURE.md | 312 +++ documentation/QUICK_BACKUP_REFERENCE.md | 199 ++ logs/access.log | 384 ++++ logs/error.log | 1011 ++++++++++ py_app/app/__init__.py | 5 + py_app/app/backup_scheduler.py | 296 +++ py_app/app/database_backup.py | 326 +++- .../setup_complete_database.py | 76 +- py_app/app/routes.py | 486 +++-- py_app/app/templates/settings.html | 1694 ++++++++++++++--- py_app/requirements.txt | 3 +- run/trasabilitate.pid | 2 +- 15 files changed, 4873 insertions(+), 429 deletions(-) create mode 100644 documentation/BACKUP_SCHEDULE_FEATURE.md create mode 100644 documentation/DATA_ONLY_BACKUP_FEATURE.md create mode 100644 documentation/QUICK_BACKUP_REFERENCE.md create mode 100644 py_app/app/backup_scheduler.py diff --git a/backups/backup_schedule.json b/backups/backup_schedule.json index cb70483..c4f166f 100644 --- a/backups/backup_schedule.json +++ b/backups/backup_schedule.json @@ -1,6 +1,13 @@ { - "enabled": true, - "time": "02:00", - "frequency": "daily", - "retention_days": 30 + "schedules": [ + { + "id": "default", + "name": "Default Schedule", + "enabled": true, + "time": "03:00", + "frequency": "daily", + "backup_type": "data-only", + "retention_days": 30 + } + ] } \ No newline at end of file diff --git a/backups/backups_metadata.json b/backups/backups_metadata.json index 0637a08..24d7891 100644 --- a/backups/backups_metadata.json +++ b/backups/backups_metadata.json @@ -1 +1,8 @@ -[] \ No newline at end of file +[ + { + "filename": "data_only_test_20251105_190632.sql", + "size": 305541, + "timestamp": "2025-11-05T19:06:32.251145", + "database": "trasabilitate" + } +] \ No newline at end of file diff --git a/documentation/BACKUP_SCHEDULE_FEATURE.md b/documentation/BACKUP_SCHEDULE_FEATURE.md new file mode 100644 index 0000000..5359297 --- /dev/null +++ b/documentation/BACKUP_SCHEDULE_FEATURE.md @@ -0,0 +1,484 @@ +# Backup Schedule Feature - Complete Guide + +## Overview + +The backup schedule feature allows administrators to configure automated backups that run at specified times with customizable frequency. This ensures regular, consistent backups without manual intervention. + +**Added:** November 5, 2025 +**Version:** 1.1.0 + +--- + +## Key Features + +### 1. Automated Scheduling +- **Daily Backups:** Run every day at specified time +- **Weekly Backups:** Run once per week +- **Monthly Backups:** Run once per month +- **Custom Time:** Choose exact time (24-hour format) + +### 2. Backup Type Selection ✨ NEW +- **Full Backup:** Complete database with schema, triggers, and data +- **Data-Only Backup:** Only table data (faster, smaller files) + +### 3. Retention Management +- **Automatic Cleanup:** Delete backups older than X days +- **Configurable Period:** Keep backups from 1 to 365 days +- **Smart Storage:** Prevents disk space issues + +### 4. Easy Management +- **Enable/Disable:** Toggle scheduled backups on/off +- **Visual Interface:** Clear, intuitive settings panel +- **Status Tracking:** See current schedule at a glance + +--- + +## Configuration Options + +### Schedule Settings + +| Setting | Options | Default | Description | +|---------|---------|---------|-------------| +| **Enabled** | On/Off | Off | Enable or disable scheduled backups | +| **Time** | 00:00 - 23:59 | 02:00 | Time to run backup (24-hour format) | +| **Frequency** | Daily, Weekly, Monthly | Daily | How often to run backup | +| **Backup Type** | Full, Data-Only | Full | Type of backup to create | +| **Retention** | 1-365 days | 30 | Days to keep old backups | + +--- + +## Recommended Configurations + +### Configuration 1: Daily Data Snapshots +**Best for:** Production environments with frequent data changes + +```json +{ + "enabled": true, + "time": "02:00", + "frequency": "daily", + "backup_type": "data-only", + "retention_days": 7 +} +``` + +**Why:** +- ✅ Fast daily backups (data-only is 30-40% faster) +- ✅ Smaller file sizes +- ✅ 7-day retention keeps recent history without filling disk +- ✅ Schema changes handled separately + +### Configuration 2: Weekly Full Backups +**Best for:** Stable environments, comprehensive safety + +```json +{ + "enabled": true, + "time": "03:00", + "frequency": "weekly", + "backup_type": "full", + "retention_days": 60 +} +``` + +**Why:** +- ✅ Complete database backup with schema and triggers +- ✅ Less frequent (lower storage usage) +- ✅ 60-day retention for long-term recovery +- ✅ Safe for disaster recovery + +### Configuration 3: Hybrid Approach (Recommended) +**Best for:** Most production environments + +**Schedule 1 - Daily Data:** +```json +{ + "enabled": true, + "time": "02:00", + "frequency": "daily", + "backup_type": "data-only", + "retention_days": 7 +} +``` + +**Schedule 2 - Weekly Full (manual or separate scheduler):** +- Run manual full backup every Sunday +- Keep for 90 days + +**Why:** +- ✅ Daily data snapshots for quick recovery +- ✅ Weekly full backups for complete safety +- ✅ Balanced storage usage +- ✅ Multiple recovery points + +--- + +## How to Configure + +### Via Web Interface + +1. **Navigate to Settings:** + - Log in as Admin or Superadmin + - Go to **Settings** page + - Scroll to **Database Backup Management** section + +2. **Configure Schedule:** + - Check **"Enable Scheduled Backups"** checkbox + - Set **Backup Time** (e.g., 02:00) + - Choose **Frequency** (Daily/Weekly/Monthly) + - Select **Backup Type:** + - **Full Backup** for complete safety + - **Data-Only Backup** for faster, smaller backups + - Set **Retention Days** (1-365) + +3. **Save Configuration:** + - Click **💾 Save Schedule** button + - Confirm settings in alert message + +### Via Configuration File + +**File Location:** `/srv/quality_app/backups/backup_schedule.json` + +**Example:** +```json +{ + "enabled": true, + "time": "02:00", + "frequency": "daily", + "backup_type": "data-only", + "retention_days": 30 +} +``` + +**Note:** Changes take effect on next scheduled run. + +--- + +## Technical Implementation + +### 1. Schedule Storage +- **File:** `backup_schedule.json` in backups directory +- **Format:** JSON +- **Persistence:** Survives application restarts + +### 2. Backup Execution +The schedule configuration is stored, but actual execution requires a cron job or scheduler: + +**Recommended: Use system cron** +```bash +# Edit crontab +crontab -e + +# Add entry for 2 AM daily +0 2 * * * cd /srv/quality_app/py_app && /srv/quality_recticel/recticel/bin/python3 -c "from app.database_backup import DatabaseBackupManager; from app import create_app; app = create_app(); app.app_context().push(); mgr = DatabaseBackupManager(); schedule = mgr.get_backup_schedule(); mgr.create_data_only_backup() if schedule['backup_type'] == 'data-only' else mgr.create_backup()" +``` + +**Alternative: APScheduler (application-level)** +```python +from apscheduler.schedulers.background import BackgroundScheduler + +scheduler = BackgroundScheduler() + +def scheduled_backup(): + schedule = backup_manager.get_backup_schedule() + if schedule['enabled']: + if schedule['backup_type'] == 'data-only': + backup_manager.create_data_only_backup() + else: + backup_manager.create_backup() + backup_manager.cleanup_old_backups(schedule['retention_days']) + +# Schedule based on configuration +scheduler.add_job(scheduled_backup, 'cron', hour=2, minute=0) +scheduler.start() +``` + +### 3. Cleanup Process +Automated cleanup runs after each backup: +- Scans backup directory +- Identifies files older than retention_days +- Deletes old backups +- Logs deletion activity + +--- + +## Backup Type Comparison + +### Full Backup (Schema + Data + Triggers) + +**mysqldump command:** +```bash +mysqldump \ + --single-transaction \ + --skip-lock-tables \ + --force \ + --routines \ + --triggers \ # ✅ Included + --events \ + --add-drop-database \ + --databases trasabilitate +``` + +**Typical size:** 1-2 MB (schema) + data size +**Backup time:** ~15-30 seconds +**Restore:** Complete replacement + +### Data-Only Backup + +**mysqldump command:** +```bash +mysqldump \ + --no-create-info \ # ❌ Skip CREATE TABLE + --skip-triggers \ # ❌ Skip triggers + --no-create-db \ # ❌ Skip CREATE DATABASE + --complete-insert \ + --extended-insert \ + --single-transaction \ + trasabilitate +``` + +**Typical size:** Data size only +**Backup time:** ~10-20 seconds (30-40% faster) +**Restore:** Data only (schema must exist) + +--- + +## Understanding the UI + +### Schedule Form Fields + +``` +┌─────────────────────────────────────────────┐ +│ ☑ Enable Scheduled Backups │ +├─────────────────────────────────────────────┤ +│ Backup Time: [02:00] │ +│ Frequency: [Daily ▼] │ +│ Backup Type: [Full Backup ▼] │ +│ Keep backups for: [30] days │ +├─────────────────────────────────────────────┤ +│ [💾 Save Schedule] │ +└─────────────────────────────────────────────┘ + +💡 Recommendation: Use Full Backup for weekly/ + monthly schedules (complete safety), and + Data-Only for daily schedules (faster, + smaller files). +``` + +### Success Message Format +When saving schedule: +``` +✅ Backup schedule saved successfully + +Scheduled [Full/Data-Only] backups will run +[daily/weekly/monthly] at [HH:MM]. +``` + +--- + +## API Endpoints + +### Get Current Schedule +``` +GET /api/backup/schedule +``` + +**Response:** +```json +{ + "success": true, + "schedule": { + "enabled": true, + "time": "02:00", + "frequency": "daily", + "backup_type": "data-only", + "retention_days": 30 + } +} +``` + +### Save Schedule +``` +POST /api/backup/schedule +Content-Type: application/json + +{ + "enabled": true, + "time": "02:00", + "frequency": "daily", + "backup_type": "data-only", + "retention_days": 30 +} +``` + +**Response:** +```json +{ + "success": true, + "message": "Backup schedule saved successfully" +} +``` + +--- + +## Monitoring and Logs + +### Check Backup Files +```bash +ls -lh /srv/quality_app/backups/*.sql | tail -10 +``` + +### Verify Schedule Configuration +```bash +cat /srv/quality_app/backups/backup_schedule.json +``` + +### Check Application Logs +```bash +tail -f /srv/quality_app/logs/error.log | grep -i backup +``` + +### Monitor Disk Usage +```bash +du -sh /srv/quality_app/backups/ +``` + +--- + +## Troubleshooting + +### Issue: Scheduled backups not running + +**Check 1:** Is schedule enabled? +```bash +cat /srv/quality_app/backups/backup_schedule.json | grep enabled +``` + +**Check 2:** Is cron job configured? +```bash +crontab -l | grep backup +``` + +**Check 3:** Are there permission issues? +```bash +ls -la /srv/quality_app/backups/ +``` + +**Solution:** Ensure cron job exists and has proper permissions. + +--- + +### Issue: Backup files growing too large + +**Check disk usage:** +```bash +du -sh /srv/quality_app/backups/ +ls -lh /srv/quality_app/backups/*.sql | wc -l +``` + +**Solutions:** +1. Reduce retention_days (e.g., from 30 to 7) +2. Use data-only backups (smaller files) +3. Store old backups on external storage +4. Compress backups: `gzip /srv/quality_app/backups/*.sql` + +--- + +### Issue: Data-only restore fails + +**Error:** "Table doesn't exist" + +**Cause:** Database schema not present + +**Solution:** +1. Run full backup restore first, OR +2. Ensure database structure exists via setup script + +--- + +## Best Practices + +### ✅ DO: +1. **Enable scheduled backups** - Automate for consistency +2. **Use data-only for daily** - Faster, smaller files +3. **Use full for weekly** - Complete safety net +4. **Test restore regularly** - Verify backups work +5. **Monitor disk space** - Prevent storage issues +6. **Store off-site copies** - Disaster recovery +7. **Adjust retention** - Balance safety vs. storage + +### ❌ DON'T: +1. **Don't disable all backups** - Always have some backup +2. **Don't set retention too low** - Keep at least 7 days +3. **Don't ignore disk warnings** - Monitor storage +4. **Don't forget to test restores** - Untested backups are useless +5. **Don't rely only on scheduled** - Manual backups before major changes + +--- + +## Security and Access + +### Required Roles +- **View Schedule:** Admin, Superadmin +- **Edit Schedule:** Admin, Superadmin +- **Execute Manual Backup:** Admin, Superadmin +- **Restore Database:** Superadmin only + +### File Permissions +```bash +# Backup directory +drwxrwxr-x /srv/quality_app/backups/ + +# Schedule file +-rw-rw-r-- backup_schedule.json + +# Backup files +-rw-rw-r-- *.sql +``` + +--- + +## Migration Guide + +### Upgrading from Previous Version (without backup_type) + +**Automatic:** Schedule automatically gets `backup_type: "full"` on first load + +**Manual update:** +```bash +cd /srv/quality_app/backups/ +# Backup current schedule +cp backup_schedule.json backup_schedule.json.bak + +# Add backup_type field +cat backup_schedule.json | jq '. + {"backup_type": "full"}' > backup_schedule_new.json +mv backup_schedule_new.json backup_schedule.json +``` + +--- + +## Related Documentation + +- [DATA_ONLY_BACKUP_FEATURE.md](DATA_ONLY_BACKUP_FEATURE.md) - Data-only backup details +- [BACKUP_SYSTEM.md](BACKUP_SYSTEM.md) - Complete backup system overview +- [QUICK_BACKUP_REFERENCE.md](QUICK_BACKUP_REFERENCE.md) - Quick reference guide + +--- + +## Future Enhancements + +### Planned Features: +- [ ] Multiple schedules (daily data + weekly full) +- [ ] Email notifications on backup completion +- [ ] Backup to remote storage (S3, FTP) +- [ ] Backup compression (gzip) +- [ ] Backup encryption +- [ ] Web-based backup browsing +- [ ] Automatic restore testing + +--- + +**Last Updated:** November 5, 2025 +**Module:** `app/database_backup.py` +**UI Template:** `app/templates/settings.html` +**Application:** Quality Recticel - Trasabilitate System diff --git a/documentation/DATA_ONLY_BACKUP_FEATURE.md b/documentation/DATA_ONLY_BACKUP_FEATURE.md new file mode 100644 index 0000000..17574ad --- /dev/null +++ b/documentation/DATA_ONLY_BACKUP_FEATURE.md @@ -0,0 +1,312 @@ +# Data-Only Backup and Restore Feature + +## Overview + +The data-only backup and restore feature allows you to backup and restore **only the data** from the database, without affecting the database schema, triggers, or structure. This is useful for: + +- **Quick data transfers** between identical database structures +- **Data refreshes** without changing the schema +- **Faster backups** when you only need to save data +- **Testing scenarios** where you want to swap data but keep the structure + +--- + +## Key Features + +### 1. Data-Only Backup +Creates a backup file containing **only INSERT statements** for all tables. + +**What's included:** +- ✅ All table data (INSERT statements) +- ✅ Column names in INSERT statements (complete-insert format) +- ✅ Multi-row INSERT for efficiency + +**What's NOT included:** +- ❌ CREATE TABLE statements (no schema) +- ❌ CREATE DATABASE statements +- ❌ Trigger definitions +- ❌ Stored procedures or functions +- ❌ Views + +**File naming:** `data_only_trasabilitate_YYYYMMDD_HHMMSS.sql` + +### 2. Data-Only Restore +Restores data from a data-only backup file into an **existing database**. + +**What happens during restore:** +1. **Truncates all tables** (deletes all current data) +2. **Disables foreign key checks** temporarily +3. **Inserts data** from the backup file +4. **Re-enables foreign key checks** +5. **Preserves** existing schema, triggers, and structure + +**⚠️ Important:** The database schema must already exist and match the backup structure. + +--- + +## Usage + +### Creating a Data-Only Backup + +#### Via Web Interface: +1. Navigate to **Settings** page +2. Scroll to **Database Backup Management** section +3. Click **📦 Data-Only Backup** button +4. Backup file will be created and added to the backup list + +#### Via API: +```bash +curl -X POST http://localhost:8781/api/backup/create-data-only \ + -H "Content-Type: application/json" \ + --cookie "session=your_session_cookie" +``` + +**Response:** +```json +{ + "success": true, + "message": "Data-only backup created successfully", + "filename": "data_only_trasabilitate_20251105_160000.sql", + "size": "12.45 MB", + "timestamp": "20251105_160000" +} +``` + +--- + +### Restoring from Data-Only Backup + +#### Via Web Interface: +1. Navigate to **Settings** page +2. Scroll to **Restore Database** section (Superadmin only) +3. Select a backup file from the dropdown +4. Choose **"Data-Only Restore"** radio button +5. Click **🔄 Restore Database** button +6. Confirm twice (with typing "RESTORE DATA") + +#### Via API: +```bash +curl -X POST http://localhost:8781/api/backup/restore-data-only/data_only_trasabilitate_20251105_160000.sql \ + -H "Content-Type: application/json" \ + --cookie "session=your_session_cookie" +``` + +**Response:** +```json +{ + "success": true, + "message": "Data restored successfully from data_only_trasabilitate_20251105_160000.sql" +} +``` + +--- + +## Comparison: Full Backup vs Data-Only Backup + +| Feature | Full Backup | Data-Only Backup | +|---------|-------------|------------------| +| **Database Schema** | ✅ Included | ❌ Not included | +| **Triggers** | ✅ Included | ❌ Not included | +| **Stored Procedures** | ✅ Included | ❌ Not included | +| **Table Data** | ✅ Included | ✅ Included | +| **File Size** | Larger | Smaller | +| **Backup Speed** | Slower | Faster | +| **Use Case** | Complete migration, disaster recovery | Data refresh, testing | +| **Restore Requirements** | None (creates everything) | Database schema must exist | + +--- + +## Use Cases + +### ✅ When to Use Data-Only Backup: + +1. **Daily Data Snapshots** + - You want to backup data frequently without duplicating schema + - Faster backups for large databases + +2. **Data Transfer Between Servers** + - Both servers have identical database structure + - You only need to copy the data + +3. **Testing and Development** + - Load production data into test environment + - Test environment already has correct schema + +4. **Data Refresh** + - Replace old data with new data + - Keep existing triggers and procedures + +### ❌ When NOT to Use Data-Only Backup: + +1. **Complete Database Migration** + - Use full backup to ensure all structures are migrated + +2. **Disaster Recovery** + - Use full backup to restore everything + +3. **Schema Changes** + - If schema has changed, data-only restore will fail + - Use full backup and restore + +4. **Fresh Database Setup** + - No existing schema to restore into + - Use full backup or database setup script + +--- + +## Technical Implementation + +### mysqldump Command for Data-Only Backup +```bash +mysqldump \ + --host=localhost \ + --port=3306 \ + --user=trasabilitate \ + --password=password \ + --no-create-info # Skip CREATE TABLE statements + --skip-triggers # Skip trigger definitions + --no-create-db # Skip CREATE DATABASE statement + --complete-insert # Include column names in INSERT + --extended-insert # Multi-row INSERTs for efficiency + --single-transaction # Consistent snapshot + --skip-lock-tables # Avoid table locks + trasabilitate +``` + +### Data-Only Restore Process +```python +# 1. Disable foreign key checks +SET FOREIGN_KEY_CHECKS = 0; + +# 2. Get all tables +SHOW TABLES; + +# 3. Truncate each table (except system tables) +TRUNCATE TABLE `table_name`; + +# 4. Execute the data-only backup SQL file +# (Contains INSERT statements) + +# 5. Re-enable foreign key checks +SET FOREIGN_KEY_CHECKS = 1; +``` + +--- + +## Security and Permissions + +- **Data-Only Backup Creation:** Requires `admin` or `superadmin` role +- **Data-Only Restore:** Requires `superadmin` role only +- **API Access:** Requires valid session authentication +- **File Access:** Backups stored in `/srv/quality_app/backups` (configurable) + +--- + +## Safety Features + +### Confirmation Process for Restore: +1. **First Confirmation:** Dialog explaining what will happen +2. **Second Confirmation:** Requires typing "RESTORE DATA" in capital letters +3. **Type Detection:** Warns if trying to do full restore on data-only file + +### Data Integrity: +- **Foreign key checks** disabled during restore to avoid constraint errors +- **Transaction-based** backup for consistent snapshots +- **Table truncation** ensures clean data without duplicates +- **Automatic re-enabling** of foreign key checks after restore + +--- + +## API Endpoints + +### Create Data-Only Backup +``` +POST /api/backup/create-data-only +``` +**Access:** Admin+ +**Response:** Backup filename and size + +### Restore Data-Only Backup +``` +POST /api/backup/restore-data-only/ +``` +**Access:** Superadmin only +**Response:** Success/failure message + +--- + +## File Naming Convention + +### Data-Only Backups: +- Format: `data_only__.sql` +- Example: `data_only_trasabilitate_20251105_143022.sql` + +### Full Backups: +- Format: `backup__.sql` +- Example: `backup_trasabilitate_20251105_143022.sql` + +The `data_only_` prefix helps identify backup type at a glance. + +--- + +## Troubleshooting + +### Error: "Data restore failed: Table 'X' doesn't exist" +**Cause:** Database schema not present or incomplete +**Solution:** Run full backup restore or database setup script first + +### Error: "Column count doesn't match" +**Cause:** Schema structure has changed since backup was created +**Solution:** Use a newer data-only backup or update schema first + +### Error: "Foreign key constraint fails" +**Cause:** Foreign key checks not properly disabled +**Solution:** Check MariaDB user has SUPER privilege + +### Warning: "Could not truncate table" +**Cause:** Table has special permissions or is a view +**Solution:** Non-critical warning; restore will continue + +--- + +## Best Practices + +1. **Always keep full backups** for complete disaster recovery +2. **Use data-only backups** for frequent snapshots +3. **Test restores** in non-production environment first +4. **Document schema changes** that affect data structure +5. **Schedule both types** of backups (e.g., full weekly, data-only daily) + +--- + +## Performance Considerations + +### Backup Speed: +- **Full backup (17 tables):** ~15-30 seconds +- **Data-only backup (17 tables):** ~10-20 seconds (faster by 30-40%) + +### File Size: +- **Full backup:** Includes schema (~1-2 MB) + data +- **Data-only backup:** Only data (smaller by 1-2 MB) + +### Restore Speed: +- **Full restore:** Drops and recreates everything +- **Data-only restore:** Only truncates and inserts (faster on large schemas) + +--- + +## Related Documentation + +- [BACKUP_SYSTEM.md](BACKUP_SYSTEM.md) - Complete backup system overview +- [DATABASE_RESTORE_GUIDE.md](DATABASE_RESTORE_GUIDE.md) - Detailed restore procedures +- [DATABASE_STRUCTURE.md](DATABASE_STRUCTURE.md) - Database schema reference + +--- + +## Implementation Date + +**Feature Added:** November 5, 2025 +**Version:** 1.1.0 +**Python Module:** `app/database_backup.py` +**API Routes:** `app/routes.py` (lines 3800-3835) +**UI Template:** `app/templates/settings.html` diff --git a/documentation/QUICK_BACKUP_REFERENCE.md b/documentation/QUICK_BACKUP_REFERENCE.md new file mode 100644 index 0000000..aa04a31 --- /dev/null +++ b/documentation/QUICK_BACKUP_REFERENCE.md @@ -0,0 +1,199 @@ +# Quick Backup Reference Guide + +## When to Use Which Backup Type? + +### 🔵 Full Backup (Schema + Data + Triggers) + +**Use when:** +- ✅ Setting up a new database server +- ✅ Complete disaster recovery +- ✅ Migrating to a different server +- ✅ Database schema has changed +- ✅ You need everything (safest option) + +**Creates:** +- Database structure (CREATE TABLE, CREATE DATABASE) +- All triggers and stored procedures +- All data (INSERT statements) + +**File:** `backup_trasabilitate_20251105_190632.sql` + +--- + +### 🟢 Data-Only Backup (Data Only) + +**Use when:** +- ✅ Quick daily data snapshots +- ✅ Both databases have identical structure +- ✅ You want to load different data into existing database +- ✅ Faster backups for large databases +- ✅ Testing with production data + +**Creates:** +- Only INSERT statements for all tables +- No schema, no triggers, no structure + +**File:** `data_only_trasabilitate_20251105_190632.sql` + +--- + +## Quick Command Reference + +### Web Interface + +**Location:** Settings → Database Backup Management + +#### Create Backups: +- **Full Backup:** Click `⚡ Full Backup (Schema + Data)` button +- **Data-Only:** Click `📦 Data-Only Backup` button + +#### Restore Database (Superadmin Only): +1. Select backup file from dropdown +2. Choose restore type: + - **Full Restore:** Replace entire database + - **Data-Only Restore:** Replace only data +3. Click `🔄 Restore Database` button +4. Confirm twice + +--- + +## Backup Comparison + +| Feature | Full Backup | Data-Only Backup | +|---------|-------------|------------------| +| **Speed** | Slower | ⚡ Faster (30-40% quicker) | +| **File Size** | Larger | 📦 Smaller (~1-2 MB less) | +| **Schema** | ✅ Yes | ❌ No | +| **Triggers** | ✅ Yes | ❌ No | +| **Data** | ✅ Yes | ✅ Yes | +| **Use Case** | Complete recovery | Data refresh | +| **Restore Requirement** | None | Schema must exist | + +--- + +## Safety Features + +### Full Restore +- **Confirmation:** Type "RESTORE" in capital letters +- **Effect:** Replaces EVERYTHING +- **Warning:** All data, schema, triggers deleted + +### Data-Only Restore +- **Confirmation:** Type "RESTORE DATA" in capital letters +- **Effect:** Replaces only data +- **Warning:** All data deleted, schema preserved + +### Smart Detection +- System warns if you try to do full restore on data-only file +- System warns if you try to do data-only restore on full file + +--- + +## Common Scenarios + +### Scenario 1: Daily Backups +**Recommendation:** +- Monday: Full backup (keeps everything) +- Tuesday-Sunday: Data-only backups (faster, smaller) + +### Scenario 2: Database Migration +**Recommendation:** +- Use full backup (safest, includes everything) + +### Scenario 3: Load Test Data +**Recommendation:** +- Use data-only backup (preserve your test triggers) + +### Scenario 4: Disaster Recovery +**Recommendation:** +- Use full backup (complete restoration) + +### Scenario 5: Data Refresh +**Recommendation:** +- Use data-only backup (quick data swap) + +--- + +## File Naming Convention + +### Identify Backup Type by Filename: + +``` +backup_trasabilitate_20251105_143022.sql +└─┬─┘ └─────┬──────┘ └────┬─────┘ + │ │ └─ Timestamp + │ └─ Database name + └─ Full backup + +data_only_trasabilitate_20251105_143022.sql +└───┬───┘ └─────┬──────┘ └────┬─────┘ + │ │ └─ Timestamp + │ └─ Database name + └─ Data-only backup +``` + +--- + +## Troubleshooting + +### "Table doesn't exist" during data-only restore +**Solution:** Run full backup restore first, or use database setup script + +### "Column count doesn't match" during data-only restore +**Solution:** Schema has changed. Update schema or use newer backup + +### "Foreign key constraint fails" during restore +**Solution:** Database user needs SUPER privilege + +--- + +## Best Practices + +1. ✅ Keep both types of backups +2. ✅ Test restores in non-production first +3. ✅ Schedule full backups weekly +4. ✅ Schedule data-only backups daily +5. ✅ Keep backups for 30+ days +6. ✅ Store backups off-server for disaster recovery + +--- + +## Access Requirements + +| Action | Required Role | +|--------|--------------| +| Create Full Backup | Admin or Superadmin | +| Create Data-Only Backup | Admin or Superadmin | +| View Backup List | Admin or Superadmin | +| Download Backup | Admin or Superadmin | +| Delete Backup | Admin or Superadmin | +| **Full Restore** | **Superadmin Only** | +| **Data-Only Restore** | **Superadmin Only** | + +--- + +## Quick Tips + +💡 **Tip 1:** Data-only backups are 30-40% faster than full backups + +💡 **Tip 2:** Use data-only restore to quickly swap between production and test data + +💡 **Tip 3:** Always keep at least one full backup for disaster recovery + +💡 **Tip 4:** Data-only backups are perfect for automated daily snapshots + +💡 **Tip 5:** Test your restore process regularly (at least quarterly) + +--- + +## Support + +For detailed information, see: +- [DATA_ONLY_BACKUP_FEATURE.md](DATA_ONLY_BACKUP_FEATURE.md) - Complete feature documentation +- [BACKUP_SYSTEM.md](BACKUP_SYSTEM.md) - Overall backup system +- [DATABASE_RESTORE_GUIDE.md](DATABASE_RESTORE_GUIDE.md) - Restore procedures + +--- + +**Last Updated:** November 5, 2025 +**Application:** Quality Recticel - Trasabilitate System diff --git a/logs/access.log b/logs/access.log index 8c16421..80d56a1 100644 --- a/logs/access.log +++ b/logs/access.log @@ -562,3 +562,387 @@ 192.168.0.132 - - [03/Nov/2025:22:26:31 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 10914 µs 192.168.0.132 - - [03/Nov/2025:22:26:31 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2747 µs 192.168.0.132 - - [03/Nov/2025:22:26:39 +0200] "GET /daily_mirror/main HTTP/1.1" 200 10549 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 19051 µs +192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2552 µs +192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1793 µs +192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12521 µs +192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13089 µs +192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2199 µs +192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 27914 µs +192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 29657 µs +192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3554 µs +192.168.0.132 - - [04/Nov/2025:06:12:38 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7784 µs +192.168.0.132 - - [04/Nov/2025:06:12:38 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12172 µs +192.168.0.132 - - [04/Nov/2025:06:12:38 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2468 µs +192.168.0.132 - - [04/Nov/2025:06:12:44 +0200] "GET /main_scan HTTP/1.1" 200 2541 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6905 µs +192.168.0.132 - - [04/Nov/2025:06:12:51 +0200] "GET /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 32154 µs +192.168.0.132 - - [04/Nov/2025:06:12:51 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2334 µs +192.168.0.132 - - [04/Nov/2025:08:17:10 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot)" 8037 µs +192.168.0.132 - - [04/Nov/2025:10:11:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 36277 µs +192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 96679 µs +192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 4372 µs +192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2399 µs +192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12995 µs +192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2250 µs +192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2245 µs +192.168.0.132 - - [04/Nov/2025:10:24:59 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 81440 µs +192.168.0.132 - - [04/Nov/2025:10:29:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10461 µs +192.168.0.132 - - [04/Nov/2025:10:30:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10179 µs +192.168.0.132 - - [04/Nov/2025:10:40:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 97127 µs +192.168.0.132 - - [04/Nov/2025:10:43:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10557 µs +192.168.0.132 - - [04/Nov/2025:10:47:33 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10395 µs +192.168.0.132 - - [04/Nov/2025:10:53:43 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10299 µs +192.168.0.132 - - [04/Nov/2025:10:54:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11251 µs +192.168.0.132 - - [04/Nov/2025:10:55:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10508 µs +192.168.0.132 - - [04/Nov/2025:10:57:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10536 µs +192.168.0.132 - - [04/Nov/2025:11:13:12 +0200] "GET /settings HTTP/1.1" 302 189 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 4080 µs +192.168.0.132 - - [04/Nov/2025:11:13:12 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2934 µs +192.168.0.132 - - [04/Nov/2025:11:13:13 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1902 µs +192.168.0.132 - - [04/Nov/2025:11:31:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 97379 µs +192.168.0.132 - - [04/Nov/2025:11:33:24 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11081 µs +192.168.0.132 - - [04/Nov/2025:11:36:11 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 18766 µs +192.168.0.132 - - [04/Nov/2025:11:38:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10196 µs +192.168.0.132 - - [04/Nov/2025:11:41:56 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10523 µs +192.168.0.132 - - [04/Nov/2025:11:45:18 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10788 µs +192.168.0.132 - - [04/Nov/2025:11:46:33 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10645 µs +192.168.0.132 - - [04/Nov/2025:11:49:24 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11648 µs +192.168.0.132 - - [04/Nov/2025:11:54:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10775 µs +192.168.0.132 - - [04/Nov/2025:11:55:10 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11220 µs +192.168.0.132 - - [04/Nov/2025:11:58:04 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10872 µs +192.168.0.132 - - [04/Nov/2025:11:59:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10649 µs +192.168.0.132 - - [04/Nov/2025:12:01:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 43968 µs +192.168.0.132 - - [04/Nov/2025:12:06:24 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11119 µs +192.168.0.132 - - [04/Nov/2025:12:07:17 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10803 µs +192.168.0.132 - - [04/Nov/2025:12:11:06 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10989 µs +192.168.0.132 - - [04/Nov/2025:12:12:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11055 µs +192.168.0.132 - - [04/Nov/2025:12:15:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11223 µs +192.168.0.132 - - [04/Nov/2025:12:16:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11165 µs +192.168.0.132 - - [04/Nov/2025:12:19:28 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11037 µs +192.168.0.132 - - [04/Nov/2025:12:20:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11242 µs +192.168.0.132 - - [04/Nov/2025:12:24:23 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11183 µs +192.168.0.132 - - [04/Nov/2025:12:25:30 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10992 µs +192.168.0.132 - - [04/Nov/2025:12:27:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11038 µs +192.168.0.132 - - [04/Nov/2025:12:28:54 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11052 µs +192.168.0.132 - - [04/Nov/2025:12:29:44 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12022 µs +192.168.0.132 - - [04/Nov/2025:12:31:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11132 µs +192.168.0.132 - - [04/Nov/2025:12:37:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 85402 µs +192.168.0.132 - - [04/Nov/2025:12:37:48 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11243 µs +192.168.0.132 - - [04/Nov/2025:12:38:10 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11032 µs +192.168.0.132 - - [04/Nov/2025:12:39:51 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11198 µs +192.168.0.132 - - [04/Nov/2025:12:40:10 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11060 µs +192.168.0.132 - - [04/Nov/2025:12:41:05 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11776 µs +192.168.0.132 - - [04/Nov/2025:12:42:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11231 µs +192.168.0.132 - - [04/Nov/2025:12:50:06 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12031 µs +192.168.0.132 - - [04/Nov/2025:12:54:21 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11443 µs +192.168.0.132 - - [04/Nov/2025:12:55:28 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12384 µs +192.168.0.132 - - [04/Nov/2025:12:55:43 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11645 µs +192.168.0.132 - - [04/Nov/2025:12:56:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11843 µs +192.168.0.132 - - [04/Nov/2025:13:09:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 98595 µs +192.168.0.132 - - [04/Nov/2025:13:10:22 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12092 µs +192.168.0.132 - - [04/Nov/2025:13:18:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11799 µs +192.168.0.132 - - [04/Nov/2025:13:20:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11399 µs +192.168.0.132 - - [04/Nov/2025:13:20:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11761 µs +192.168.0.132 - - [04/Nov/2025:13:24:01 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11861 µs +192.168.0.132 - - [04/Nov/2025:13:25:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11555 µs +192.168.0.132 - - [04/Nov/2025:13:28:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11571 µs +192.168.0.132 - - [04/Nov/2025:13:29:04 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12073 µs +192.168.0.132 - - [04/Nov/2025:13:32:48 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11914 µs +192.168.0.132 - - [04/Nov/2025:13:33:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11785 µs +192.168.0.132 - - [04/Nov/2025:13:35:40 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11011 µs +192.168.0.132 - - [04/Nov/2025:13:37:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11617 µs +192.168.0.132 - - [04/Nov/2025:13:39:18 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11635 µs +192.168.0.132 - - [04/Nov/2025:13:42:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11537 µs +192.168.0.132 - - [04/Nov/2025:13:45:56 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12128 µs +192.168.0.132 - - [04/Nov/2025:13:48:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12132 µs +192.168.0.132 - - [04/Nov/2025:13:49:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13105 µs +192.168.0.132 - - [04/Nov/2025:13:52:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12213 µs +192.168.0.132 - - [04/Nov/2025:13:53:59 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11880 µs +192.168.0.132 - - [04/Nov/2025:13:55:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12119 µs +192.168.0.132 - - [04/Nov/2025:13:57:46 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13438 µs +192.168.0.132 - - [04/Nov/2025:13:58:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12358 µs +192.168.0.132 - - [04/Nov/2025:14:01:25 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12135 µs +192.168.0.132 - - [04/Nov/2025:14:01:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11941 µs +192.168.0.132 - - [04/Nov/2025:14:03:51 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12200 µs +192.168.0.132 - - [04/Nov/2025:14:06:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12389 µs +192.168.0.132 - - [04/Nov/2025:14:07:56 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12268 µs +192.168.0.132 - - [04/Nov/2025:14:10:44 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12096 µs +192.168.0.132 - - [04/Nov/2025:14:13:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12144 µs +192.168.0.132 - - [04/Nov/2025:14:14:03 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12321 µs +192.168.0.132 - - [04/Nov/2025:14:17:03 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12181 µs +192.168.0.132 - - [04/Nov/2025:14:18:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12379 µs +192.168.0.132 - - [04/Nov/2025:14:21:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12576 µs +192.168.0.132 - - [04/Nov/2025:14:21:54 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12409 µs +192.168.0.132 - - [04/Nov/2025:14:24:09 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12335 µs +192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12331 µs +192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3034 µs +192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14353 µs +192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 4089 µs +192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2855 µs +192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 17085 µs +192.168.0.132 - - [04/Nov/2025:14:25:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12740 µs +192.168.0.132 - - [04/Nov/2025:14:28:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12679 µs +192.168.0.132 - - [04/Nov/2025:14:42:45 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3321 µs +192.168.0.132 - - [04/Nov/2025:14:42:57 +0200] "GET /main_scan HTTP/1.1" 200 2541 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2918 µs +192.168.0.132 - - [04/Nov/2025:14:42:59 +0200] "GET /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7358 µs +192.168.0.132 - - [04/Nov/2025:14:52:18 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13308 µs +192.168.0.132 - - [04/Nov/2025:14:53:04 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12626 µs +192.168.0.132 - - [04/Nov/2025:14:59:42 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12884 µs +192.168.0.132 - - [04/Nov/2025:15:02:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12571 µs +192.168.0.132 - - [04/Nov/2025:15:07:17 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12571 µs +192.168.0.132 - - [04/Nov/2025:15:07:53 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1540 µs +192.168.0.132 - - [04/Nov/2025:15:07:53 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 8340 µs +192.168.0.132 - - [04/Nov/2025:15:07:54 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1911 µs +192.168.0.132 - - [04/Nov/2025:15:07:54 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13034 µs +192.168.0.132 - - [04/Nov/2025:15:07:54 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1401 µs +192.168.0.132 - - [04/Nov/2025:15:07:55 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5894 µs +192.168.0.132 - - [04/Nov/2025:15:07:55 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12102 µs +192.168.0.132 - - [04/Nov/2025:15:07:57 +0200] "GET /main_scan HTTP/1.1" 200 2541 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6823 µs +192.168.0.132 - - [04/Nov/2025:15:07:58 +0200] "GET /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6065 µs +192.168.0.132 - - [04/Nov/2025:15:09:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9931 µs +192.168.0.132 - - [04/Nov/2025:15:12:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9915 µs +192.168.0.132 - - [04/Nov/2025:15:15:05 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9980 µs +192.168.0.132 - - [04/Nov/2025:15:17:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10359 µs +192.168.0.132 - - [04/Nov/2025:15:20:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10383 µs +192.168.0.132 - - [04/Nov/2025:15:23:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10485 µs +192.168.0.132 - - [04/Nov/2025:15:25:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10658 µs +192.168.0.132 - - [04/Nov/2025:18:17:39 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12281 µs +192.168.0.132 - - [04/Nov/2025:18:17:40 +0200] "GET /main_scan HTTP/1.1" 200 2541 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6888 µs +192.168.0.132 - - [04/Nov/2025:18:17:41 +0200] "GET /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6239 µs +192.168.0.132 - - [04/Nov/2025:18:22:51 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" 8353 µs +192.168.0.132 - - [04/Nov/2025:22:42:22 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0" 8466 µs +192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10266 µs +192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2380 µs +192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2430 µs +192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2392 µs +192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2796 µs +192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2207 µs +192.168.0.132 - - [05/Nov/2025:06:16:00 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10064 µs +192.168.0.132 - - [05/Nov/2025:06:18:06 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10807 µs +192.168.0.132 - - [05/Nov/2025:06:18:18 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10370 µs +192.168.0.132 - - [05/Nov/2025:06:21:32 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10262 µs +192.168.0.132 - - [05/Nov/2025:06:23:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10698 µs +192.168.0.132 - - [05/Nov/2025:06:26:11 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9958 µs +192.168.0.132 - - [05/Nov/2025:06:26:20 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10253 µs +192.168.0.132 - - [05/Nov/2025:06:29:42 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10375 µs +192.168.0.132 - - [05/Nov/2025:06:31:40 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10867 µs +192.168.0.132 - - [05/Nov/2025:06:33:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10314 µs +192.168.0.132 - - [05/Nov/2025:06:34:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10138 µs +192.168.0.132 - - [05/Nov/2025:06:38:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10344 µs +192.168.0.132 - - [05/Nov/2025:06:38:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10497 µs +192.168.0.132 - - [05/Nov/2025:06:42:20 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10373 µs +192.168.0.132 - - [05/Nov/2025:06:44:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10370 µs +192.168.0.132 - - [05/Nov/2025:06:49:33 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10381 µs +192.168.0.132 - - [05/Nov/2025:06:54:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10430 µs +192.168.0.132 - - [05/Nov/2025:06:56:11 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10468 µs +192.168.0.132 - - [05/Nov/2025:06:57:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10246 µs +192.168.0.132 - - [05/Nov/2025:07:01:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11103 µs +192.168.0.132 - - [05/Nov/2025:07:07:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10526 µs +192.168.0.132 - - [05/Nov/2025:07:33:29 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10606 µs +192.168.0.132 - - [05/Nov/2025:07:36:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11354 µs +192.168.0.132 - - [05/Nov/2025:07:37:22 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10803 µs +192.168.0.132 - - [05/Nov/2025:07:39:23 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11539 µs +192.168.0.132 - - [05/Nov/2025:07:42:46 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10692 µs +192.168.0.132 - - [05/Nov/2025:07:49:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10719 µs +192.168.0.132 - - [05/Nov/2025:07:54:47 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10949 µs +192.168.0.132 - - [05/Nov/2025:08:15:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10790 µs +192.168.0.132 - - [05/Nov/2025:08:22:59 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11007 µs +192.168.0.132 - - [05/Nov/2025:08:26:46 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10815 µs +192.168.0.132 - - [05/Nov/2025:08:31:57 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10889 µs +192.168.0.132 - - [05/Nov/2025:08:33:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10856 µs +192.168.0.132 - - [05/Nov/2025:08:35:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11053 µs +192.168.0.132 - - [05/Nov/2025:08:38:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11145 µs +192.168.0.132 - - [05/Nov/2025:08:44:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12227 µs +192.168.0.132 - - [05/Nov/2025:08:44:44 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13457 µs +192.168.0.132 - - [05/Nov/2025:08:48:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10946 µs +192.168.0.132 - - [05/Nov/2025:08:48:59 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10971 µs +192.168.0.132 - - [05/Nov/2025:08:49:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10901 µs +192.168.0.132 - - [05/Nov/2025:08:54:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12157 µs +192.168.0.132 - - [05/Nov/2025:08:55:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11197 µs +192.168.0.132 - - [05/Nov/2025:08:56:15 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11034 µs +192.168.0.132 - - [05/Nov/2025:08:57:04 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11223 µs +192.168.0.132 - - [05/Nov/2025:08:57:30 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12009 µs +192.168.0.132 - - [05/Nov/2025:08:58:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11295 µs +192.168.0.132 - - [05/Nov/2025:08:59:10 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11143 µs +192.168.0.132 - - [05/Nov/2025:08:59:36 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10915 µs +192.168.0.132 - - [05/Nov/2025:09:02:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11225 µs +192.168.0.132 - - [05/Nov/2025:09:02:52 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11339 µs +192.168.0.132 - - [05/Nov/2025:09:03:51 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11466 µs +192.168.0.132 - - [05/Nov/2025:09:05:17 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11510 µs +192.168.0.132 - - [05/Nov/2025:09:06:26 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11335 µs +192.168.0.132 - - [05/Nov/2025:09:07:15 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11652 µs +192.168.0.132 - - [05/Nov/2025:09:09:09 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11600 µs +192.168.0.132 - - [05/Nov/2025:09:10:03 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10592 µs +192.168.0.132 - - [05/Nov/2025:09:11:46 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11556 µs +192.168.0.132 - - [05/Nov/2025:09:14:15 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11300 µs +192.168.0.132 - - [05/Nov/2025:09:16:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11749 µs +192.168.0.132 - - [05/Nov/2025:09:18:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11453 µs +192.168.0.132 - - [05/Nov/2025:09:19:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11605 µs +192.168.0.132 - - [05/Nov/2025:09:21:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12340 µs +192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1897 µs +192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2013 µs +192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2229 µs +192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2053 µs +192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2329 µs +192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2515 µs +192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2286 µs +192.168.0.132 - - [05/Nov/2025:09:23:00 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2448 µs +192.168.0.132 - - [05/Nov/2025:09:23:01 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5693 µs +192.168.0.132 - - [05/Nov/2025:09:23:01 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2516 µs +192.168.0.132 - - [05/Nov/2025:09:23:01 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2279 µs +192.168.0.132 - - [05/Nov/2025:09:23:03 +0200] "GET /reports HTTP/1.1" 200 3385 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 8042 µs +192.168.0.132 - - [05/Nov/2025:09:23:04 +0200] "GET /fg_quality HTTP/1.1" 200 22312 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 21834 µs +192.168.0.132 - - [05/Nov/2025:09:23:04 +0200] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2786 µs +192.168.0.132 - - [05/Nov/2025:09:23:07 +0200] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 7888 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10662 µs +192.168.0.132 - - [05/Nov/2025:09:23:51 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11192 µs +192.168.0.132 - - [05/Nov/2025:09:26:02 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12405 µs +192.168.0.132 - - [05/Nov/2025:09:26:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11522 µs +192.168.0.132 - - [05/Nov/2025:09:30:21 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11807 µs +192.168.0.132 - - [05/Nov/2025:09:31:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10808 µs +192.168.0.132 - - [05/Nov/2025:09:34:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11048 µs +192.168.0.132 - - [05/Nov/2025:09:35:44 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11667 µs +192.168.0.132 - - [05/Nov/2025:09:37:08 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" 8444 µs +192.168.0.132 - - [05/Nov/2025:09:37:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12072 µs +192.168.0.132 - - [05/Nov/2025:09:40:15 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12585 µs +192.168.0.132 - - [05/Nov/2025:09:43:30 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11999 µs +192.168.0.132 - - [05/Nov/2025:09:45:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12001 µs +192.168.0.132 - - [05/Nov/2025:09:48:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11981 µs +192.168.0.132 - - [05/Nov/2025:09:49:32 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11773 µs +192.168.0.132 - - [05/Nov/2025:09:49:47 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12106 µs +192.168.0.132 - - [05/Nov/2025:09:54:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11949 µs +192.168.0.132 - - [05/Nov/2025:09:58:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11818 µs +192.168.0.132 - - [05/Nov/2025:10:01:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12946 µs +192.168.0.132 - - [05/Nov/2025:10:01:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11945 µs +192.168.0.132 - - [05/Nov/2025:10:06:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12374 µs +192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1723 µs +192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5440 µs +192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1954 µs +192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1864 µs +192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1856 µs +192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2414 µs +192.168.0.132 - - [05/Nov/2025:10:07:56 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2048 µs +192.168.0.132 - - [05/Nov/2025:10:07:59 +0200] "POST / HTTP/1.1" 200 1688 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5989 µs +192.168.0.132 - - [05/Nov/2025:10:08:14 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6064 µs +192.168.0.132 - - [05/Nov/2025:10:08:14 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2527 µs +192.168.0.132 - - [05/Nov/2025:10:08:14 +0200] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 21135 µs +192.168.0.132 - - [05/Nov/2025:10:08:20 +0200] "GET /reports HTTP/1.1" 200 3388 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 8000 µs +192.168.0.132 - - [05/Nov/2025:10:08:24 +0200] "GET /fg_quality HTTP/1.1" 200 22444 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 21628 µs +192.168.0.132 - - [05/Nov/2025:10:08:24 +0200] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2751 µs +192.168.0.132 - - [05/Nov/2025:10:08:29 +0200] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 7888 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10600 µs +192.168.0.132 - - [05/Nov/2025:10:08:46 +0200] "GET /test_fg_database HTTP/1.1" 200 1559 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7875 µs +192.168.0.132 - - [05/Nov/2025:10:08:52 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2468 µs +192.168.0.132 - - [05/Nov/2025:10:08:54 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6972 µs +192.168.0.132 - - [05/Nov/2025:10:08:55 +0200] "GET /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6099 µs +192.168.0.132 - - [05/Nov/2025:10:08:56 +0200] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2494 µs +192.168.0.132 - - [05/Nov/2025:10:08:57 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11870 µs +192.168.0.132 - - [05/Nov/2025:10:10:23 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10433 µs +192.168.0.132 - - [05/Nov/2025:10:10:37 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10783 µs +192.168.0.132 - - [05/Nov/2025:10:10:42 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10265 µs +192.168.0.132 - - [05/Nov/2025:10:11:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12510 µs +192.168.0.132 - - [05/Nov/2025:10:11:43 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10060 µs +192.168.0.132 - - [05/Nov/2025:10:12:47 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12557 µs +192.168.0.132 - - [05/Nov/2025:10:13:56 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12243 µs +192.168.0.132 - - [05/Nov/2025:10:14:21 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2150 µs +192.168.0.132 - - [05/Nov/2025:10:14:23 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5633 µs +192.168.0.132 - - [05/Nov/2025:10:14:23 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2458 µs +192.168.0.132 - - [05/Nov/2025:10:14:25 +0200] "GET /settings HTTP/1.1" 200 34325 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 47236 µs +192.168.0.132 - - [05/Nov/2025:10:14:25 +0200] "GET /api/backup/schedule HTTP/1.1" 200 100 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2740 µs +192.168.0.132 - - [05/Nov/2025:10:14:25 +0200] "GET /api/backup/list HTTP/1.1" 200 195 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11161 µs +192.168.0.132 - - [05/Nov/2025:10:14:41 +0200] "POST /api/backup/create HTTP/1.1" 200 238 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 229606 µs +192.168.0.132 - - [05/Nov/2025:10:14:44 +0200] "GET /api/backup/list HTTP/1.1" 200 345 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2653 µs +192.168.0.132 - - [05/Nov/2025:10:14:48 +0200] "GET /api/backup/download/backup_trasabilitate_20251105_101441.sql HTTP/1.1" 200 0 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6717 µs +192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12437 µs +192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3140 µs +192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3014 µs +192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2829 µs +192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3232 µs +192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 18745 µs +192.168.0.132 - - [05/Nov/2025:10:18:38 +0200] "POST /api/backup/schedule HTTP/1.1" 200 64 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3294 µs +192.168.0.132 - - [05/Nov/2025:10:19:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12328 µs +192.168.0.132 - - [05/Nov/2025:10:21:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12354 µs +192.168.0.132 - - [05/Nov/2025:10:22:54 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12761 µs +192.168.0.132 - - [05/Nov/2025:10:29:01 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12785 µs +192.168.0.132 - - [05/Nov/2025:10:32:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12757 µs +192.168.0.132 - - [05/Nov/2025:10:33:47 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13501 µs +192.168.0.132 - - [05/Nov/2025:10:35:05 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12562 µs +192.168.0.132 - - [05/Nov/2025:10:38:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12650 µs +192.168.0.132 - - [05/Nov/2025:10:38:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12547 µs +192.168.0.132 - - [05/Nov/2025:10:39:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12630 µs +192.168.0.132 - - [05/Nov/2025:10:43:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12557 µs +192.168.0.132 - - [05/Nov/2025:10:44:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12781 µs +192.168.0.132 - - [05/Nov/2025:10:47:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12842 µs +192.168.0.132 - - [05/Nov/2025:10:50:40 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12916 µs +192.168.0.132 - - [05/Nov/2025:10:51:01 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13598 µs +192.168.0.132 - - [05/Nov/2025:10:52:57 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12670 µs +192.168.0.132 - - [05/Nov/2025:10:55:23 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12861 µs +192.168.0.132 - - [05/Nov/2025:10:55:42 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12950 µs +192.168.0.132 - - [05/Nov/2025:10:58:50 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12942 µs +192.168.0.132 - - [05/Nov/2025:10:59:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13809 µs +192.168.0.132 - - [05/Nov/2025:10:59:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12838 µs +192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1454 µs +192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1669 µs +192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1935 µs +192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1978 µs +192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2065 µs +192.168.0.132 - - [05/Nov/2025:13:59:21 +0200] "GET /.env HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3" 2030 µs +192.168.0.132 - - [05/Nov/2025:18:19:01 +0200] "GET /dashboard HTTP/1.1" 302 189 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 16940 µs +192.168.0.132 - - [05/Nov/2025:18:19:02 +0200] "GET / HTTP/1.1" 200 1688 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 61971 µs +192.168.0.132 - - [05/Nov/2025:18:19:02 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2850 µs +192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 11767 µs +192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 12538 µs +192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 13285 µs +192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 30006 µs +192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 30188 µs +192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 30252 µs +192.168.0.132 - - [05/Nov/2025:18:19:13 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 48222 µs +192.168.0.132 - - [05/Nov/2025:18:19:15 +0200] "GET /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 32890 µs +192.168.0.132 - - [05/Nov/2025:18:19:15 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2467 µs +192.168.0.132 - - [05/Nov/2025:18:20:16 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 9755 µs +192.168.0.132 - - [05/Nov/2025:18:20:25 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 81428 µs +192.168.0.132 - - [05/Nov/2025:19:04:10 +0200] "POST /fg_scan HTTP/1.1" 200 32840 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 100484 µs +192.168.0.132 - - [05/Nov/2025:19:04:31 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 12610 µs +192.168.0.132 - - [05/Nov/2025:19:04:34 +0200] "GET /settings HTTP/1.1" 200 40104 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 48813 µs +192.168.0.132 - - [05/Nov/2025:19:04:34 +0200] "GET /api/backup/list HTTP/1.1" 200 345 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 27909 µs +192.168.0.132 - - [05/Nov/2025:19:04:34 +0200] "GET /api/backup/schedule HTTP/1.1" 200 100 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 49313 µs +192.168.0.132 - - [05/Nov/2025:19:04:46 +0200] "DELETE /api/backup/delete/backup_trasabilitate_20251103_212929_20251103_215909.sql HTTP/1.1" 200 114 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 28996 µs +192.168.0.132 - - [05/Nov/2025:19:04:47 +0200] "GET /api/backup/list HTTP/1.1" 200 179 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3272 µs +192.168.0.132 - - [05/Nov/2025:19:04:50 +0200] "DELETE /api/backup/delete/backup_trasabilitate_20251105_101441.sql HTTP/1.1" 200 98 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3450 µs +192.168.0.132 - - [05/Nov/2025:19:04:51 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 5292 µs +192.168.0.132 - - [05/Nov/2025:20:29:50 +0200] "GET /settings HTTP/1.1" 200 40104 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 89618 µs +192.168.0.132 - - [05/Nov/2025:20:29:50 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2552 µs +192.168.0.132 - - [05/Nov/2025:20:29:50 +0200] "GET /api/backup/schedule HTTP/1.1" 200 100 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2693 µs +192.168.0.132 - - [05/Nov/2025:20:30:05 +0200] "POST /api/backup/create-data-only HTTP/1.1" 200 254 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 174664 µs +192.168.0.132 - - [05/Nov/2025:20:30:08 +0200] "GET /api/backup/list HTTP/1.1" 200 182 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 27617 µs +192.168.0.132 - - [05/Nov/2025:20:30:32 +0200] "GET /api/backup/list HTTP/1.1" 200 182 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3214 µs +192.168.0.132 - - [05/Nov/2025:20:30:33 +0200] "GET /api/backup/list HTTP/1.1" 200 182 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2700 µs +127.0.0.1 - - [05/Nov/2025:20:34:42 +0200] "GET /api/backup/schedule HTTP/1.1" 302 189 "-" "curl/8.14.1" 18027 µs +192.168.0.132 - - [05/Nov/2025:20:35:00 +0200] "GET /settings HTTP/1.1" 200 42008 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 108583 µs +192.168.0.132 - - [05/Nov/2025:20:35:00 +0200] "GET /api/backup/list HTTP/1.1" 200 182 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 45694 µs +192.168.0.132 - - [05/Nov/2025:20:35:00 +0200] "GET /api/backup/schedule HTTP/1.1" 200 121 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 46015 µs +192.168.0.132 - - [05/Nov/2025:20:35:23 +0200] "POST /api/backup/schedule HTTP/1.1" 200 64 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 4267 µs +192.168.0.132 - - [05/Nov/2025:20:35:37 +0200] "DELETE /api/backup/delete/data_only_trasabilitate_20251105_203005.sql HTTP/1.1" 200 101 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3789 µs +192.168.0.132 - - [05/Nov/2025:20:35:38 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2584 µs +192.168.0.132 - - [05/Nov/2025:20:45:58 +0200] "GET /settings HTTP/1.1" 200 43080 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 111345 µs +192.168.0.132 - - [05/Nov/2025:20:45:58 +0200] "GET /api/backup/schedule HTTP/1.1" 200 164 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 4862 µs +192.168.0.132 - - [05/Nov/2025:20:45:58 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 19334 µs +192.168.0.132 - - [05/Nov/2025:20:46:24 +0200] "GET /settings HTTP/1.1" 200 43080 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 95425 µs +192.168.0.132 - - [05/Nov/2025:20:46:24 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2623 µs +192.168.0.132 - - [05/Nov/2025:20:46:24 +0200] "GET /api/backup/schedule HTTP/1.1" 200 164 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 20670 µs +192.168.0.132 - - [05/Nov/2025:21:08:15 +0200] "GET /settings HTTP/1.1" 200 68254 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 127920 µs +192.168.0.132 - - [05/Nov/2025:21:08:15 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 19369 µs +192.168.0.132 - - [05/Nov/2025:21:08:15 +0200] "GET /api/backup/schedule HTTP/1.1" 200 164 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 20410 µs +192.168.0.132 - - [05/Nov/2025:21:09:39 +0200] "GET /settings HTTP/1.1" 200 68254 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 127408 µs +192.168.0.132 - - [05/Nov/2025:21:09:40 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3033 µs +192.168.0.132 - - [05/Nov/2025:21:09:40 +0200] "GET /api/backup/schedule HTTP/1.1" 200 164 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 4782 µs +192.168.0.132 - - [05/Nov/2025:21:10:03 +0200] "POST /api/backup/create HTTP/1.1" 200 238 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 227736 µs +192.168.0.132 - - [05/Nov/2025:21:10:07 +0200] "GET /api/backup/list HTTP/1.1" 200 178 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2625 µs +192.168.0.132 - - [05/Nov/2025:21:10:20 +0200] "DELETE /api/backup/delete/backup_trasabilitate_20251105_211003.sql HTTP/1.1" 200 98 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3783 µs +192.168.0.132 - - [05/Nov/2025:21:10:22 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2479 µs +192.168.0.132 - - [05/Nov/2025:21:10:25 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2495 µs +192.168.0.132 - - [05/Nov/2025:21:19:35 +0200] "GET /settings HTTP/1.1" 200 72985 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 131211 µs +192.168.0.132 - - [05/Nov/2025:21:19:35 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3707 µs +192.168.0.132 - - [05/Nov/2025:21:19:35 +0200] "GET /api/backup/schedule HTTP/1.1" 200 283 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 21446 µs +192.168.0.132 - - [05/Nov/2025:21:22:15 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 46701 µs +192.168.0.132 - - [05/Nov/2025:21:22:17 +0200] "GET /fg_scan HTTP/1.1" 200 32840 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 34947 µs +192.168.0.132 - - [05/Nov/2025:21:22:39 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 12213 µs +192.168.0.132 - - [05/Nov/2025:21:22:44 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2394 µs +192.168.0.132 - - [05/Nov/2025:21:23:03 +0200] "GET /fg_scan HTTP/1.1" 200 32840 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 6396 µs +192.168.0.132 - - [05/Nov/2025:21:23:24 +0200] "POST /fg_scan HTTP/1.1" 200 32844 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 16430 µs diff --git a/logs/error.log b/logs/error.log index 8bbbdb7..e8e68e3 100644 --- a/logs/error.log +++ b/logs/error.log @@ -1747,3 +1747,1014 @@ Raw form input: 'superadmin' 'Vanessa_13/05' External DB query result (with modules): ('superadmin', 'Vanessa_13/05', 'superadmin', 'quality,warehouse,labels,daily_mirror') Logged in as: superadmin superadmin modules: ['quality', 'warehouse', 'labels', 'daily_mirror'] Session user: superadmin superadmin +Session user: None None +All form data received: {'username': 'Ciprian', 'password': 'ciprian@123'} +Raw form input: 'Ciprian' 'ciprian@123' +External DB query result (with modules): ('Ciprian', 'ciprian@123', 'manager', '["quality", "warehouse", "labels"]') +Logged in as: Ciprian manager modules: ['quality', 'warehouse', 'labels'] +Session user: Ciprian manager +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Session user: Ciprian manager +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Session user: None None +All form data received: {'username': 'Ciprian', 'password': 'ciprian@123'} +Raw form input: 'Ciprian' 'ciprian@123' +External DB query result (with modules): ('Ciprian', 'ciprian@123', 'manager', '["quality", "warehouse", "labels"]') +Logged in as: Ciprian manager modules: ['quality', 'warehouse', 'labels'] +Session user: Ciprian manager +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Session user: Ciprian manager +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +All form data received: {'username': 'Ciprian', 'password': 'ciprian@123'} +Raw form input: 'Ciprian' 'ciprian@123' +External DB query result (with modules): ('Ciprian', 'ciprian@123', 'manager', '["quality", "warehouse", "labels"]') +Logged in as: Ciprian manager modules: ['quality', 'warehouse', 'labels'] +Session user: Ciprian manager +DEBUG: Total FG records in scanfg_orders table: 90 +DEBUG: Fetched 90 FG rows for report 5 (all rows) +FG Data being returned: {'headers': ['Id', 'Operator Code', 'CP Base Code', 'CP Full Code', 'OC1 Code', 'OC2 Code', 'Quality Code', 'Date', 'Time', 'Approved Quantity', 'Rejected Quantity'], 'rows': [[90, 'OP01', 'CP00001429', 'CP00001429-32', 'OC19', 'OC00', 0, '03/11/2025', '17:59:54', 10, 1], [89, 'OP01', 'CP00001429', 'CP00001429-24', 'OC27', 'OC00', 0, '03/11/2025', '17:58:00', 10, 1], [88, 'OP01', 'CP00001429', 'CP00001429-23', 'OC19', 'OC00', 0, '03/11/2025', '17:57:15', 10, 1], [87, 'OP01', 'CP00001429', 'CP00001429-22', 'OC19', 'OC00', 0, '03/11/2025', '17:56:55', 10, 1], [86, 'OP01', 'CP00001429', 'CP00001429-21', 'OC01', 'OC00', 0, '03/11/2025', '17:56:04', 10, 1], [85, 'OP01', 'CP00001429', 'CP00001429-1', 'OC11', 'OC04', 0, '03/11/2025', '17:50:37', 10, 1], [84, 'OP01', 'CP00001429', 'CP00001429-21', 'OC04', 'OC00', 0, '03/11/2025', '17:44:01', 10, 1], [83, 'OP01', 'CP00001429', 'CP00001429-20', 'OC05', 'OC00', 1, '03/11/2025', '17:43:35', 10, 1], [82, 'OP01', 'CP00001429', 'CP00001429-1', 'OC09', 'OC00', 0, '03/11/2025', '17:43:16', 10, 1], [81, 'OP01', 'CP00001429', 'CP00001429-18', 'OC19', 'OC00', 0, '03/11/2025', '17:42:53', 10, 1], [80, 'OP01', 'CP00001429', 'CP00001429-17', 'OC11', 'OC00', 0, '03/11/2025', '17:42:35', 10, 1], [79, 'OP01', 'CP00001432', 'CP00001432-30', 'OC05', 'OC00', 0, '03/11/2025', '16:00:06', 21, 2], [78, 'OP01', 'CP00001432', 'CP00001432-29', 'OC19', 'OC00', 0, '03/11/2025', '15:59:52', 21, 2], [77, 'OP01', 'CP00001432', 'CP00001432-28', 'OC04', 'OC00', 0, '03/11/2025', '15:59:37', 21, 2], [76, 'OP01', 'CP00001432', 'CP00001432-26', 'OC05', 'OC00', 0, '03/11/2025', '15:59:25', 21, 2], [75, 'OP01', 'CP00001432', 'CP00001432-25', 'OC11', 'OC00', 0, '03/11/2025', '15:59:06', 21, 2], [74, 'OP01', 'CP00001432', 'CP00001432-23', 'OC19', 'OC00', 0, '03/11/2025', '15:58:51', 21, 2], [73, 'OP01', 'CP00001432', 'CP00001432-23', 'OC05', 'OC00', 0, '03/11/2025', '15:58:37', 21, 2], [72, 'OP01', 'CP00001432', 'CP00001432-21', 'OC26', 'OC00', 0, '03/11/2025', '15:58:19', 21, 2], [71, 'OP01', 'CP00001432', 'CP00001432-20', 'OC19', 'OC00', 26, '03/11/2025', '15:58:04', 21, 2], [70, 'OP01', 'CP00001432', 'CP00001432-19', 'OC09', 'OC00', 1, '03/11/2025', '15:57:36', 21, 2], [69, 'OP01', 'CP00001432', 'CP00001432-18U', 'OC26', 'OC00', 0, '03/11/2025', '15:56:19', 21, 2], [68, 'OP01', 'CP00001432', 'CP00001432-16', 'OC19', 'OC04', 0, '03/11/2025', '15:56:02', 21, 2], [67, 'OP01', 'CP00001432', 'CP00001432-14', 'OC19', 'OC00', 0, '03/11/2025', '15:55:45', 21, 2], [66, 'OP01', 'CP00001432', 'CP00001432-13', 'OC11', 'OC00', 0, '03/11/2025', '15:55:33', 21, 2], [65, 'OP01', 'CP00001432', 'CP00001432-11', 'OC11', 'OC00', 0, '03/11/2025', '15:55:20', 21, 2], [64, 'OP01', 'CP00001432', 'CP00001432-10', 'OC26', 'OC00', 0, '03/11/2025', '15:55:04', 21, 2], [63, 'OP01', 'CP00001432', 'CP00001432-8', 'OC19', 'OC00', 0, '03/11/2025', '15:54:46', 21, 2], [62, 'OP01', 'CP00001432', 'CP00001432-7', 'OC04', 'OC00', 0, '03/11/2025', '15:54:28', 21, 2], [61, 'OP01', 'CP00001432', 'CP00001432-6', 'OC19', 'OC00', 0, '03/11/2025', '15:54:08', 21, 2], [60, 'OP01', 'CP00001432', 'CP00001432-5', 'OC11', 'OC00', 0, '03/11/2025', '15:53:52', 21, 2], [59, 'OP01', 'CP00001432', 'CP00001432-4', 'OC09', 'OC00', 0, '03/11/2025', '15:53:36', 21, 2], [58, 'OP01', 'CP00001432', 'CP00001432-2', 'OC11', 'OC00', 0, '03/11/2025', '15:53:21', 21, 2], [57, 'OP01', 'CP00001432', 'CP00001432-1', 'OC05', 'OC00', 0, '03/11/2025', '15:53:05', 21, 2], [56, 'OP01', 'CP00001421', 'CP00001421-23', 'OC11', 'OC00', 2, '03/11/2025', '15:52:44', 15, 3], [55, 'OP01', 'CP00001421', 'CP00001421-21', 'OC19', 'OC00', 0, '03/11/2025', '15:52:16', 15, 3], [54, 'OP01', 'CP00001421', 'CP00001421-20', 'OC05', 'OC00', 0, '03/11/2025', '15:51:56', 15, 3], [53, 'OP01', 'CP00001421', 'CP00001421-18', 'OC09', 'OC00', 26, '03/11/2025', '15:51:31', 15, 3], [52, 'OP01', 'CP00001421', 'CP00001421-16', 'OC26', 'OC00', 0, '03/11/2025', '15:51:04', 15, 3], [51, 'OP01', 'CP00001421', 'CP00001421-14', 'OC05', 'OC00', 0, '03/11/2025', '15:50:46', 15, 3], [50, 'OP01', 'CP00001421', 'CP00001421-12', 'OC11', 'OC00', 0, '03/11/2025', '15:50:27', 15, 3], [49, 'OP01', 'CP00001421', 'CP00001421-11', 'OC19', 'OC00', 0, '03/11/2025', '15:50:10', 15, 3], [48, 'OP01', 'CP00001421', 'CP00001421-10', 'OC11', 'OC00', 0, '03/11/2025', '15:49:50', 15, 3], [47, 'OP01', 'CP00001421', 'CP00001421-9', 'OC09', 'OC00', 0, '03/11/2025', '15:49:34', 15, 3], [46, 'OP01', 'CP00001421', 'CP00001421-8', 'OC05', 'OC00', 0, '03/11/2025', '15:49:06', 15, 3], [45, 'OP01', 'CP00001421', 'CP00001421-7', 'OC11', 'OC00', 0, '03/11/2025', '15:48:45', 15, 3], [44, 'OP01', 'CP00001421', 'CP00001421-6', 'OC04', 'OC00', 0, '03/11/2025', '15:48:19', 15, 3], [43, 'OP01', 'CP00001421', 'CP00001421-5', 'OC26', 'OC00', 0, '03/11/2025', '15:48:01', 15, 3], [42, 'OP01', 'CP00001421', 'CP00001421-4', 'OC05', 'OC00', 1, '03/11/2025', '15:47:37', 15, 3], [41, 'OP01', 'CP00001421', 'CP00001421-3', 'OC09', 'OC19', 0, '03/11/2025', '15:46:43', 15, 3], [40, 'OP01', 'CP00001421', 'CP00001421-2', 'OC04', 'OC04', 0, '03/11/2025', '15:46:03', 15, 3], [39, 'OP01', 'CP00001421', 'CP00001421-1', 'OC26', 'OC04', 0, '03/11/2025', '13:52:26', 15, 3], [38, 'OP01', 'CP00001596', 'CP00001596-1', 'OC00', 'OC00', 0, '03/11/2025', '12:04:38', 1, 0], [37, 'OP01', 'CP00001702', 'CP00001702-1', 'OC01', 'OC00', 25, '03/11/2025', '11:55:22', 0, 1], [36, 'OP01', 'CP00001593', 'CP00001593-25', 'OC11', 'OC04', 0, '16/10/2025', '09:04:38', 12, 13], [35, 'OP01', 'CP00001593', 'CP00001593-24', 'OC05', 'OC26', 6, '16/10/2025', '09:04:29', 12, 13], [34, 'OP01', 'CP00001593', 'CP00001593-23', 'OC05', 'OC04', 0, '16/10/2025', '09:04:22', 12, 13], [33, 'OP01', 'CP00001593', 'CP00001593-22', 'OC05', 'OC26', 0, '16/10/2025', '09:04:15', 12, 13], [32, 'OP01', 'CP00001593', 'CP00001593-22', 'OC19', 'OC11', 0, '16/10/2025', '09:04:09', 12, 13], [31, 'OP01', 'CP00001593', 'CP00001593-20', 'OC09', 'OC04', 0, '16/10/2025', '09:04:01', 12, 13], [30, 'OP01', 'CP00001593', 'CP00001593-20', 'OC11', 'OC04', 24, '16/10/2025', '09:03:55', 12, 13], [29, 'OP01', 'CP00001593', 'CP00001593-18', 'OC26', 'OC19', 6, '16/10/2025', '09:03:47', 12, 13], [28, 'OP01', 'CP00001593', 'CP00001593-17', 'OC04', 'OC09', 0, '16/10/2025', '09:03:36', 12, 13], [27, 'OP01', 'CP00001593', 'CP00001593-16', 'OC26', 'OC19', 18, '16/10/2025', '09:03:29', 12, 13], [26, 'OP01', 'CP00001593', 'CP00001593-15', 'OC11', 'OC04', 0, '16/10/2025', '09:03:22', 12, 13], [25, 'OP01', 'CP00001593', 'CP00001593-15', 'OC11', 'OC19', 25, '16/10/2025', '09:03:14', 12, 13], [24, 'OP01', 'CP00001593', 'CP00001593-13', 'OC05', 'OC26', 0, '16/10/2025', '09:03:08', 12, 13], [23, 'OP01', 'CP00001593', 'CP00001593-12', 'OC26', 'OC19', 0, '16/10/2025', '09:03:02', 12, 13], [22, 'OP01', 'CP00001593', 'CP00001593-11', 'OC26', 'OC19', 1, '16/10/2025', '09:02:55', 12, 13], [21, 'OP01', 'CP00001593', 'CP00001593-10', 'OC26', 'OC19', 18, '16/10/2025', '09:02:49', 12, 13], [20, 'OP01', 'CP00001593', 'CP00001593-9', 'OC11', 'OC04', 8, '16/10/2025', '09:02:40', 12, 13], [19, 'OP01', 'CP00001593', 'CP00001593-8', 'OC05', 'OC26', 0, '16/10/2025', '09:02:32', 12, 13], [18, 'OP01', 'CP00001593', 'CP00001593-7', 'OC09', 'OC04', 1, '16/10/2025', '09:02:26', 12, 13], [17, 'OP01', 'CP00001593', 'CP00001593-6', 'OC11', 'OC19', 22, '16/10/2025', '09:02:18', 12, 13], [16, 'OP01', 'CP00001593', 'CP00001593-5', 'OC11', 'OC19', 0, '16/10/2025', '09:02:12', 12, 13], [15, 'OP01', 'CP00001593', 'CP00001593-4', 'OC09', 'OC05', 13, '16/10/2025', '09:02:03', 12, 13], [14, 'OP01', 'CP00001593', 'CP00001593-3', 'OC26', 'OC05', 0, '16/10/2025', '09:01:55', 12, 13], [13, 'OP01', 'CP00001593', 'CP00001593-2', 'OC04', 'OC09', 1, '16/10/2025', '09:01:46', 12, 13], [12, 'OP01', 'CP00001593', 'CP00001593-1', 'OC26', 'OC19', 20, '16/10/2025', '09:01:37', 12, 13], [11, 'OP01', 'CP00001594', 'CP00001594-1', 'OC26', 'OC19', 0, '16/10/2025', '08:52:58', 4, 6], [10, 'OP01', 'CP00001594', 'CP00001594-1', 'OC26', 'OC19', 0, '15/10/2025', '15:50:01', 4, 6], [9, 'OP01', 'CP00001594', 'CP00001594-1', 'OC26', 'OC19', 20, '15/10/2025', '15:49:55', 4, 6], [8, 'OP01', 'CP00001594', 'CP00001594-9', 'OC26', 'OC19', 21, '15/10/2025', '15:49:47', 4, 6], [7, 'OP01', 'CP00001594', 'CP00001594-4', 'OC11', 'OC04', 0, '15/10/2025', '15:49:37', 4, 6], [6, 'OP01', 'CP00001594', 'CP00001594-25', 'OC19', 'OC26', 16, '15/10/2025', '15:49:20', 4, 6], [5, 'OP01', 'CP00001594', 'CP00001594-6', 'OC05', 'OC11', 25, '15/10/2025', '15:48:25', 4, 6], [4, 'OP01', 'CP00001594', 'CP00001594-14', 'OC26', 'OC11', 0, '15/10/2025', '15:48:02', 4, 6], [3, 'OP01', 'CP00001594', 'CP00001594-3', 'OC04', 'OC09', 1, '15/10/2025', '15:47:43', 4, 6], [2, 'OP01', 'CP00001594', 'CP00001594-2', 'OC05', 'OC19', 21, '15/10/2025', '15:46:57', 4, 6], [1, 'OP01', 'CP00001386', 'CP00001386-29', 'OC19', 'OC26', 41, '15/10/2025', '15:39:47', 0, 1]]} +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +All form data received: {'username': 'superadmin', 'password': 'superadmin123'} +Raw form input: 'superadmin' 'superadmin123' +External DB query result (with modules): None +Login failed for: superadmin superadmin123 +All form data received: {'username': 'superadmin', 'password': 'Vanessa_13/05'} +Raw form input: 'superadmin' 'Vanessa_13/05' +External DB query result (with modules): ('superadmin', 'Vanessa_13/05', 'superadmin', 'quality,warehouse,labels,daily_mirror') +Logged in as: superadmin superadmin modules: ['quality', 'warehouse', 'labels', 'daily_mirror'] +Session user: superadmin superadmin +DEBUG: Total FG records in scanfg_orders table: 90 +DEBUG: Fetched 90 FG rows for report 5 (all rows) +FG Data being returned: {'headers': ['Id', 'Operator Code', 'CP Base Code', 'CP Full Code', 'OC1 Code', 'OC2 Code', 'Quality Code', 'Date', 'Time', 'Approved Quantity', 'Rejected Quantity'], 'rows': [[90, 'OP01', 'CP00001429', 'CP00001429-32', 'OC19', 'OC00', 0, '03/11/2025', '17:59:54', 10, 1], [89, 'OP01', 'CP00001429', 'CP00001429-24', 'OC27', 'OC00', 0, '03/11/2025', '17:58:00', 10, 1], [88, 'OP01', 'CP00001429', 'CP00001429-23', 'OC19', 'OC00', 0, '03/11/2025', '17:57:15', 10, 1], [87, 'OP01', 'CP00001429', 'CP00001429-22', 'OC19', 'OC00', 0, '03/11/2025', '17:56:55', 10, 1], [86, 'OP01', 'CP00001429', 'CP00001429-21', 'OC01', 'OC00', 0, '03/11/2025', '17:56:04', 10, 1], [85, 'OP01', 'CP00001429', 'CP00001429-1', 'OC11', 'OC04', 0, '03/11/2025', '17:50:37', 10, 1], [84, 'OP01', 'CP00001429', 'CP00001429-21', 'OC04', 'OC00', 0, '03/11/2025', '17:44:01', 10, 1], [83, 'OP01', 'CP00001429', 'CP00001429-20', 'OC05', 'OC00', 1, '03/11/2025', '17:43:35', 10, 1], [82, 'OP01', 'CP00001429', 'CP00001429-1', 'OC09', 'OC00', 0, '03/11/2025', '17:43:16', 10, 1], [81, 'OP01', 'CP00001429', 'CP00001429-18', 'OC19', 'OC00', 0, '03/11/2025', '17:42:53', 10, 1], [80, 'OP01', 'CP00001429', 'CP00001429-17', 'OC11', 'OC00', 0, '03/11/2025', '17:42:35', 10, 1], [79, 'OP01', 'CP00001432', 'CP00001432-30', 'OC05', 'OC00', 0, '03/11/2025', '16:00:06', 21, 2], [78, 'OP01', 'CP00001432', 'CP00001432-29', 'OC19', 'OC00', 0, '03/11/2025', '15:59:52', 21, 2], [77, 'OP01', 'CP00001432', 'CP00001432-28', 'OC04', 'OC00', 0, '03/11/2025', '15:59:37', 21, 2], [76, 'OP01', 'CP00001432', 'CP00001432-26', 'OC05', 'OC00', 0, '03/11/2025', '15:59:25', 21, 2], [75, 'OP01', 'CP00001432', 'CP00001432-25', 'OC11', 'OC00', 0, '03/11/2025', '15:59:06', 21, 2], [74, 'OP01', 'CP00001432', 'CP00001432-23', 'OC19', 'OC00', 0, '03/11/2025', '15:58:51', 21, 2], [73, 'OP01', 'CP00001432', 'CP00001432-23', 'OC05', 'OC00', 0, '03/11/2025', '15:58:37', 21, 2], [72, 'OP01', 'CP00001432', 'CP00001432-21', 'OC26', 'OC00', 0, '03/11/2025', '15:58:19', 21, 2], [71, 'OP01', 'CP00001432', 'CP00001432-20', 'OC19', 'OC00', 26, '03/11/2025', '15:58:04', 21, 2], [70, 'OP01', 'CP00001432', 'CP00001432-19', 'OC09', 'OC00', 1, '03/11/2025', '15:57:36', 21, 2], [69, 'OP01', 'CP00001432', 'CP00001432-18U', 'OC26', 'OC00', 0, '03/11/2025', '15:56:19', 21, 2], [68, 'OP01', 'CP00001432', 'CP00001432-16', 'OC19', 'OC04', 0, '03/11/2025', '15:56:02', 21, 2], [67, 'OP01', 'CP00001432', 'CP00001432-14', 'OC19', 'OC00', 0, '03/11/2025', '15:55:45', 21, 2], [66, 'OP01', 'CP00001432', 'CP00001432-13', 'OC11', 'OC00', 0, '03/11/2025', '15:55:33', 21, 2], [65, 'OP01', 'CP00001432', 'CP00001432-11', 'OC11', 'OC00', 0, '03/11/2025', '15:55:20', 21, 2], [64, 'OP01', 'CP00001432', 'CP00001432-10', 'OC26', 'OC00', 0, '03/11/2025', '15:55:04', 21, 2], [63, 'OP01', 'CP00001432', 'CP00001432-8', 'OC19', 'OC00', 0, '03/11/2025', '15:54:46', 21, 2], [62, 'OP01', 'CP00001432', 'CP00001432-7', 'OC04', 'OC00', 0, '03/11/2025', '15:54:28', 21, 2], [61, 'OP01', 'CP00001432', 'CP00001432-6', 'OC19', 'OC00', 0, '03/11/2025', '15:54:08', 21, 2], [60, 'OP01', 'CP00001432', 'CP00001432-5', 'OC11', 'OC00', 0, '03/11/2025', '15:53:52', 21, 2], [59, 'OP01', 'CP00001432', 'CP00001432-4', 'OC09', 'OC00', 0, '03/11/2025', '15:53:36', 21, 2], [58, 'OP01', 'CP00001432', 'CP00001432-2', 'OC11', 'OC00', 0, '03/11/2025', '15:53:21', 21, 2], [57, 'OP01', 'CP00001432', 'CP00001432-1', 'OC05', 'OC00', 0, '03/11/2025', '15:53:05', 21, 2], [56, 'OP01', 'CP00001421', 'CP00001421-23', 'OC11', 'OC00', 2, '03/11/2025', '15:52:44', 15, 3], [55, 'OP01', 'CP00001421', 'CP00001421-21', 'OC19', 'OC00', 0, '03/11/2025', '15:52:16', 15, 3], [54, 'OP01', 'CP00001421', 'CP00001421-20', 'OC05', 'OC00', 0, '03/11/2025', '15:51:56', 15, 3], [53, 'OP01', 'CP00001421', 'CP00001421-18', 'OC09', 'OC00', 26, '03/11/2025', '15:51:31', 15, 3], [52, 'OP01', 'CP00001421', 'CP00001421-16', 'OC26', 'OC00', 0, '03/11/2025', '15:51:04', 15, 3], [51, 'OP01', 'CP00001421', 'CP00001421-14', 'OC05', 'OC00', 0, '03/11/2025', '15:50:46', 15, 3], [50, 'OP01', 'CP00001421', 'CP00001421-12', 'OC11', 'OC00', 0, '03/11/2025', '15:50:27', 15, 3], [49, 'OP01', 'CP00001421', 'CP00001421-11', 'OC19', 'OC00', 0, '03/11/2025', '15:50:10', 15, 3], [48, 'OP01', 'CP00001421', 'CP00001421-10', 'OC11', 'OC00', 0, '03/11/2025', '15:49:50', 15, 3], [47, 'OP01', 'CP00001421', 'CP00001421-9', 'OC09', 'OC00', 0, '03/11/2025', '15:49:34', 15, 3], [46, 'OP01', 'CP00001421', 'CP00001421-8', 'OC05', 'OC00', 0, '03/11/2025', '15:49:06', 15, 3], [45, 'OP01', 'CP00001421', 'CP00001421-7', 'OC11', 'OC00', 0, '03/11/2025', '15:48:45', 15, 3], [44, 'OP01', 'CP00001421', 'CP00001421-6', 'OC04', 'OC00', 0, '03/11/2025', '15:48:19', 15, 3], [43, 'OP01', 'CP00001421', 'CP00001421-5', 'OC26', 'OC00', 0, '03/11/2025', '15:48:01', 15, 3], [42, 'OP01', 'CP00001421', 'CP00001421-4', 'OC05', 'OC00', 1, '03/11/2025', '15:47:37', 15, 3], [41, 'OP01', 'CP00001421', 'CP00001421-3', 'OC09', 'OC19', 0, '03/11/2025', '15:46:43', 15, 3], [40, 'OP01', 'CP00001421', 'CP00001421-2', 'OC04', 'OC04', 0, '03/11/2025', '15:46:03', 15, 3], [39, 'OP01', 'CP00001421', 'CP00001421-1', 'OC26', 'OC04', 0, '03/11/2025', '13:52:26', 15, 3], [38, 'OP01', 'CP00001596', 'CP00001596-1', 'OC00', 'OC00', 0, '03/11/2025', '12:04:38', 1, 0], [37, 'OP01', 'CP00001702', 'CP00001702-1', 'OC01', 'OC00', 25, '03/11/2025', '11:55:22', 0, 1], [36, 'OP01', 'CP00001593', 'CP00001593-25', 'OC11', 'OC04', 0, '16/10/2025', '09:04:38', 12, 13], [35, 'OP01', 'CP00001593', 'CP00001593-24', 'OC05', 'OC26', 6, '16/10/2025', '09:04:29', 12, 13], [34, 'OP01', 'CP00001593', 'CP00001593-23', 'OC05', 'OC04', 0, '16/10/2025', '09:04:22', 12, 13], [33, 'OP01', 'CP00001593', 'CP00001593-22', 'OC05', 'OC26', 0, '16/10/2025', '09:04:15', 12, 13], [32, 'OP01', 'CP00001593', 'CP00001593-22', 'OC19', 'OC11', 0, '16/10/2025', '09:04:09', 12, 13], [31, 'OP01', 'CP00001593', 'CP00001593-20', 'OC09', 'OC04', 0, '16/10/2025', '09:04:01', 12, 13], [30, 'OP01', 'CP00001593', 'CP00001593-20', 'OC11', 'OC04', 24, '16/10/2025', '09:03:55', 12, 13], [29, 'OP01', 'CP00001593', 'CP00001593-18', 'OC26', 'OC19', 6, '16/10/2025', '09:03:47', 12, 13], [28, 'OP01', 'CP00001593', 'CP00001593-17', 'OC04', 'OC09', 0, '16/10/2025', '09:03:36', 12, 13], [27, 'OP01', 'CP00001593', 'CP00001593-16', 'OC26', 'OC19', 18, '16/10/2025', '09:03:29', 12, 13], [26, 'OP01', 'CP00001593', 'CP00001593-15', 'OC11', 'OC04', 0, '16/10/2025', '09:03:22', 12, 13], [25, 'OP01', 'CP00001593', 'CP00001593-15', 'OC11', 'OC19', 25, '16/10/2025', '09:03:14', 12, 13], [24, 'OP01', 'CP00001593', 'CP00001593-13', 'OC05', 'OC26', 0, '16/10/2025', '09:03:08', 12, 13], [23, 'OP01', 'CP00001593', 'CP00001593-12', 'OC26', 'OC19', 0, '16/10/2025', '09:03:02', 12, 13], [22, 'OP01', 'CP00001593', 'CP00001593-11', 'OC26', 'OC19', 1, '16/10/2025', '09:02:55', 12, 13], [21, 'OP01', 'CP00001593', 'CP00001593-10', 'OC26', 'OC19', 18, '16/10/2025', '09:02:49', 12, 13], [20, 'OP01', 'CP00001593', 'CP00001593-9', 'OC11', 'OC04', 8, '16/10/2025', '09:02:40', 12, 13], [19, 'OP01', 'CP00001593', 'CP00001593-8', 'OC05', 'OC26', 0, '16/10/2025', '09:02:32', 12, 13], [18, 'OP01', 'CP00001593', 'CP00001593-7', 'OC09', 'OC04', 1, '16/10/2025', '09:02:26', 12, 13], [17, 'OP01', 'CP00001593', 'CP00001593-6', 'OC11', 'OC19', 22, '16/10/2025', '09:02:18', 12, 13], [16, 'OP01', 'CP00001593', 'CP00001593-5', 'OC11', 'OC19', 0, '16/10/2025', '09:02:12', 12, 13], [15, 'OP01', 'CP00001593', 'CP00001593-4', 'OC09', 'OC05', 13, '16/10/2025', '09:02:03', 12, 13], [14, 'OP01', 'CP00001593', 'CP00001593-3', 'OC26', 'OC05', 0, '16/10/2025', '09:01:55', 12, 13], [13, 'OP01', 'CP00001593', 'CP00001593-2', 'OC04', 'OC09', 1, '16/10/2025', '09:01:46', 12, 13], [12, 'OP01', 'CP00001593', 'CP00001593-1', 'OC26', 'OC19', 20, '16/10/2025', '09:01:37', 12, 13], [11, 'OP01', 'CP00001594', 'CP00001594-1', 'OC26', 'OC19', 0, '16/10/2025', '08:52:58', 4, 6], [10, 'OP01', 'CP00001594', 'CP00001594-1', 'OC26', 'OC19', 0, '15/10/2025', '15:50:01', 4, 6], [9, 'OP01', 'CP00001594', 'CP00001594-1', 'OC26', 'OC19', 20, '15/10/2025', '15:49:55', 4, 6], [8, 'OP01', 'CP00001594', 'CP00001594-9', 'OC26', 'OC19', 21, '15/10/2025', '15:49:47', 4, 6], [7, 'OP01', 'CP00001594', 'CP00001594-4', 'OC11', 'OC04', 0, '15/10/2025', '15:49:37', 4, 6], [6, 'OP01', 'CP00001594', 'CP00001594-25', 'OC19', 'OC26', 16, '15/10/2025', '15:49:20', 4, 6], [5, 'OP01', 'CP00001594', 'CP00001594-6', 'OC05', 'OC11', 25, '15/10/2025', '15:48:25', 4, 6], [4, 'OP01', 'CP00001594', 'CP00001594-14', 'OC26', 'OC11', 0, '15/10/2025', '15:48:02', 4, 6], [3, 'OP01', 'CP00001594', 'CP00001594-3', 'OC04', 'OC09', 1, '15/10/2025', '15:47:43', 4, 6], [2, 'OP01', 'CP00001594', 'CP00001594-2', 'OC05', 'OC19', 21, '15/10/2025', '15:46:57', 4, 6], [1, 'OP01', 'CP00001386', 'CP00001386-29', 'OC19', 'OC26', 41, '15/10/2025', '15:39:47', 0, 1]]} +DEBUG: Testing FG database connection... +DEBUG: FG Database connection successful! +DEBUG: Table scanfg_orders exists: True +DEBUG: FG Table structure: [('Id', 'int(11)', 'NO', 'PRI', None, 'auto_increment'), ('operator_code', 'varchar(4)', 'NO', '', None, ''), ('CP_full_code', 'varchar(15)', 'NO', '', None, ''), ('OC1_code', 'varchar(4)', 'NO', '', None, ''), ('OC2_code', 'varchar(4)', 'NO', '', None, ''), ('CP_base_code', 'varchar(10)', 'YES', '', None, 'STORED GENERATED'), ('quality_code', 'int(3)', 'NO', '', None, ''), ('date', 'date', 'NO', '', None, ''), ('time', 'time', 'NO', '', None, ''), ('approved_quantity', 'int(11)', 'YES', '', '0', ''), ('rejected_quantity', 'int(11)', 'YES', '', '0', '')] +DEBUG: Total FG records: 90 +DEBUG: Available FG dates: ['2025-11-03', '2025-10-16', '2025-10-15'] +DEBUG: FG Sample data: [{'id': 90, 'operator_code': 'OP01', 'cp_full_code': 'CP00001429-32', 'oc1_code': 'OC19', 'oc2_code': 'OC00', 'cp_base_code': 'CP00001429', 'quality_code': 0, 'date': '2025-11-03', 'time': '17:59:54', 'approved_quantity': 10, 'rejected_quantity': 1}, {'id': 89, 'operator_code': 'OP01', 'cp_full_code': 'CP00001429-24', 'oc1_code': 'OC27', 'oc2_code': 'OC00', 'cp_base_code': 'CP00001429', 'quality_code': 0, 'date': '2025-11-03', 'time': '17:58:00', 'approved_quantity': 10, 'rejected_quantity': 1}, {'id': 88, 'operator_code': 'OP01', 'cp_full_code': 'CP00001429-23', 'oc1_code': 'OC19', 'oc2_code': 'OC00', 'cp_base_code': 'CP00001429', 'quality_code': 0, 'date': '2025-11-03', 'time': '17:57:15', 'approved_quantity': 10, 'rejected_quantity': 1}] +Session user: superadmin superadmin +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +All form data received: {'username': 'superadmin', 'password': 'Vanessa_13/05'} +Raw form input: 'superadmin' 'Vanessa_13/05' +External DB query result (with modules): ('superadmin', 'Vanessa_13/05', 'superadmin', 'quality,warehouse,labels,daily_mirror') +Logged in as: superadmin superadmin modules: ['quality', 'warehouse', 'labels', 'daily_mirror'] +Session user: superadmin superadmin +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Backup directory ensured: /srv/quality_app/backups +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Session user: None None +[2025-11-05 18:16:52 +0200] [402172] [INFO] Handling signal: term +[2025-11-05 18:16:52 +0200] [402176] [INFO] Worker exiting (pid: 402176) +[2025-11-05 18:16:52 +0200] [402177] [INFO] Worker exiting (pid: 402177) +[2025-11-05 18:16:52 +0200] [402178] [INFO] Worker exiting (pid: 402178) +[2025-11-05 18:16:52 +0200] [402179] [INFO] Worker exiting (pid: 402179) +[2025-11-05 18:16:52 +0200] [402180] [INFO] Worker exiting (pid: 402180) +[2025-11-05 18:16:52 +0200] [402181] [INFO] Worker exiting (pid: 402181) +[2025-11-05 18:16:52 +0200] [402182] [INFO] Worker exiting (pid: 402182) +[2025-11-05 18:16:52 +0200] [402189] [INFO] Worker exiting (pid: 402189) +[2025-11-05 18:16:52 +0200] [402190] [INFO] Worker exiting (pid: 402190) +[2025-11-05 18:16:52 +0200] [402172] [INFO] 👋 Worker 402176 exited +[2025-11-05 18:16:52 +0200] [402172] [INFO] 👋 Worker 402179 exited +[2025-11-05 18:16:52 +0200] [402172] [INFO] 👋 Worker 402177 exited +[2025-11-05 18:16:52 +0200] [402172] [INFO] 👋 Worker 402189 exited +[2025-11-05 18:16:52 +0200] [402172] [INFO] 👋 Worker 402178 exited +[2025-11-05 18:16:52 +0200] [402172] [INFO] 👋 Worker 402181 exited +[2025-11-05 18:16:53 +0200] [402172] [INFO] 👋 Worker 402182 exited +[2025-11-05 18:16:53 +0200] [402172] [INFO] 👋 Worker 402190 exited +[2025-11-05 18:16:53 +0200] [402172] [INFO] 👋 Worker 402180 exited +[2025-11-05 18:16:53 +0200] [402172] [INFO] Shutting down: Master +[2025-11-05 18:16:53 +0200] [402172] [INFO] ============================================================ +[2025-11-05 18:16:53 +0200] [402172] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 18:16:53 +0200] [402172] [INFO] ============================================================ +[2025-11-05 18:16:59 +0200] [411409] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 18:16:59 +0200] [411409] [INFO] ============================================================ +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 18:16:59 +0200] [411409] [INFO] ============================================================ +[2025-11-05 18:16:59 +0200] [411409] [INFO] 📍 Configuration: +[2025-11-05 18:16:59 +0200] [411409] [INFO] • Workers: 9 +[2025-11-05 18:16:59 +0200] [411409] [INFO] • Worker Class: sync +[2025-11-05 18:16:59 +0200] [411409] [INFO] • Timeout: 1800s +[2025-11-05 18:16:59 +0200] [411409] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 18:16:59 +0200] [411409] [INFO] • Preload App: True +[2025-11-05 18:16:59 +0200] [411409] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 18:16:59 +0200] [411409] [INFO] ============================================================ +[2025-11-05 18:16:59 +0200] [411409] [INFO] Listening at: http://0.0.0.0:8781 (411409) +[2025-11-05 18:16:59 +0200] [411409] [INFO] Using worker: sync +[2025-11-05 18:16:59 +0200] [411409] [INFO] ============================================================ +[2025-11-05 18:16:59 +0200] [411409] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 18:16:59 +0200] [411409] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 18:16:59 +0200] [411409] [INFO] ============================================================ +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411435] [INFO] Booting worker with pid: 411435 +[2025-11-05 18:16:59 +0200] [411435] [INFO] ✨ Worker spawned successfully (pid: 411435) +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411436] [INFO] Booting worker with pid: 411436 +[2025-11-05 18:16:59 +0200] [411436] [INFO] ✨ Worker spawned successfully (pid: 411436) +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411437] [INFO] Booting worker with pid: 411437 +[2025-11-05 18:16:59 +0200] [411437] [INFO] ✨ Worker spawned successfully (pid: 411437) +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411438] [INFO] Booting worker with pid: 411438 +[2025-11-05 18:16:59 +0200] [411438] [INFO] ✨ Worker spawned successfully (pid: 411438) +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411439] [INFO] Booting worker with pid: 411439 +[2025-11-05 18:16:59 +0200] [411439] [INFO] ✨ Worker spawned successfully (pid: 411439) +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411440] [INFO] Booting worker with pid: 411440 +[2025-11-05 18:16:59 +0200] [411440] [INFO] ✨ Worker spawned successfully (pid: 411440) +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411443] [INFO] Booting worker with pid: 411443 +[2025-11-05 18:16:59 +0200] [411443] [INFO] ✨ Worker spawned successfully (pid: 411443) +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411448] [INFO] Booting worker with pid: 411448 +[2025-11-05 18:16:59 +0200] [411448] [INFO] ✨ Worker spawned successfully (pid: 411448) +[2025-11-05 18:16:59 +0200] [411409] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:16:59 +0200] [411449] [INFO] Booting worker with pid: 411449 +[2025-11-05 18:16:59 +0200] [411449] [INFO] ✨ Worker spawned successfully (pid: 411449) +Session user: None None +All form data received: {'username': 'superadmin', 'password': 'Vanessa_13/05'} +Raw form input: 'superadmin' 'Vanessa_13/05' +External DB query result (with modules): ('superadmin', 'Vanessa_13/05', 'superadmin', 'quality,warehouse,labels,daily_mirror') +Logged in as: superadmin superadmin modules: ['quality', 'warehouse', 'labels', 'daily_mirror'] +Session user: superadmin superadmin +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +Error saving finish goods scan data: Can't update table 'scanfg_orders' in stored function/trigger because it is already used by statement which invoked this stored function/trigger +[2025-11-05 18:47:38 +0200] [411409] [INFO] Handling signal: term +[2025-11-05 18:47:38 +0200] [411435] [INFO] Worker exiting (pid: 411435) +[2025-11-05 18:47:38 +0200] [411436] [INFO] Worker exiting (pid: 411436) +[2025-11-05 18:47:38 +0200] [411438] [INFO] Worker exiting (pid: 411438) +[2025-11-05 18:47:38 +0200] [411437] [INFO] Worker exiting (pid: 411437) +[2025-11-05 18:47:38 +0200] [411440] [INFO] Worker exiting (pid: 411440) +[2025-11-05 18:47:38 +0200] [411439] [INFO] Worker exiting (pid: 411439) +[2025-11-05 18:47:38 +0200] [411443] [INFO] Worker exiting (pid: 411443) +[2025-11-05 18:47:38 +0200] [411448] [INFO] Worker exiting (pid: 411448) +[2025-11-05 18:47:38 +0200] [411449] [INFO] Worker exiting (pid: 411449) +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411435 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411437 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411438 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411439 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411449 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411440 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411436 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411448 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Worker 411443 exited +[2025-11-05 18:47:39 +0200] [411409] [INFO] Shutting down: Master +[2025-11-05 18:47:39 +0200] [411409] [INFO] ============================================================ +[2025-11-05 18:47:39 +0200] [411409] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 18:47:39 +0200] [411409] [INFO] ============================================================ +[2025-11-05 18:50:31 +0200] [413017] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 18:50:31 +0200] [413017] [INFO] ============================================================ +[2025-11-05 18:50:31 +0200] [413017] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 18:50:31 +0200] [413017] [INFO] ============================================================ +[2025-11-05 18:50:31 +0200] [413017] [INFO] 📍 Configuration: +[2025-11-05 18:50:31 +0200] [413017] [INFO] • Workers: 9 +[2025-11-05 18:50:31 +0200] [413017] [INFO] • Worker Class: sync +[2025-11-05 18:50:31 +0200] [413017] [INFO] • Timeout: 1800s +[2025-11-05 18:50:31 +0200] [413017] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 18:50:31 +0200] [413017] [INFO] • Preload App: True +[2025-11-05 18:50:31 +0200] [413017] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 18:50:31 +0200] [413017] [INFO] ============================================================ +[2025-11-05 18:50:31 +0200] [413017] [INFO] Listening at: http://0.0.0.0:8781 (413017) +[2025-11-05 18:50:31 +0200] [413017] [INFO] Using worker: sync +[2025-11-05 18:50:31 +0200] [413017] [INFO] ============================================================ +[2025-11-05 18:50:31 +0200] [413017] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 18:50:31 +0200] [413017] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 18:50:31 +0200] [413017] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 18:50:31 +0200] [413017] [INFO] ============================================================ +[2025-11-05 18:50:31 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:31 +0200] [413043] [INFO] Booting worker with pid: 413043 +[2025-11-05 18:50:31 +0200] [413043] [INFO] ✨ Worker spawned successfully (pid: 413043) +[2025-11-05 18:50:31 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:31 +0200] [413044] [INFO] Booting worker with pid: 413044 +[2025-11-05 18:50:31 +0200] [413044] [INFO] ✨ Worker spawned successfully (pid: 413044) +[2025-11-05 18:50:32 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:32 +0200] [413045] [INFO] Booting worker with pid: 413045 +[2025-11-05 18:50:32 +0200] [413045] [INFO] ✨ Worker spawned successfully (pid: 413045) +[2025-11-05 18:50:32 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:32 +0200] [413046] [INFO] Booting worker with pid: 413046 +[2025-11-05 18:50:32 +0200] [413046] [INFO] ✨ Worker spawned successfully (pid: 413046) +[2025-11-05 18:50:32 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:32 +0200] [413047] [INFO] Booting worker with pid: 413047 +[2025-11-05 18:50:32 +0200] [413047] [INFO] ✨ Worker spawned successfully (pid: 413047) +[2025-11-05 18:50:32 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:32 +0200] [413054] [INFO] Booting worker with pid: 413054 +[2025-11-05 18:50:32 +0200] [413054] [INFO] ✨ Worker spawned successfully (pid: 413054) +[2025-11-05 18:50:32 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:32 +0200] [413055] [INFO] Booting worker with pid: 413055 +[2025-11-05 18:50:32 +0200] [413055] [INFO] ✨ Worker spawned successfully (pid: 413055) +[2025-11-05 18:50:32 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:32 +0200] [413056] [INFO] Booting worker with pid: 413056 +[2025-11-05 18:50:32 +0200] [413056] [INFO] ✨ Worker spawned successfully (pid: 413056) +[2025-11-05 18:50:32 +0200] [413017] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 18:50:32 +0200] [413057] [INFO] Booting worker with pid: 413057 +[2025-11-05 18:50:32 +0200] [413057] [INFO] ✨ Worker spawned successfully (pid: 413057) +[2025-11-05 19:03:48 +0200] [413017] [INFO] Handling signal: term +[2025-11-05 19:03:48 +0200] [413043] [INFO] Worker exiting (pid: 413043) +[2025-11-05 19:03:48 +0200] [413044] [INFO] Worker exiting (pid: 413044) +[2025-11-05 19:03:48 +0200] [413047] [INFO] Worker exiting (pid: 413047) +[2025-11-05 19:03:48 +0200] [413046] [INFO] Worker exiting (pid: 413046) +[2025-11-05 19:03:48 +0200] [413045] [INFO] Worker exiting (pid: 413045) +[2025-11-05 19:03:48 +0200] [413055] [INFO] Worker exiting (pid: 413055) +[2025-11-05 19:03:48 +0200] [413054] [INFO] Worker exiting (pid: 413054) +[2025-11-05 19:03:48 +0200] [413056] [INFO] Worker exiting (pid: 413056) +[2025-11-05 19:03:48 +0200] [413057] [INFO] Worker exiting (pid: 413057) +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413044 exited +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413047 exited +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413057 exited +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413045 exited +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413054 exited +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413043 exited +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413046 exited +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413055 exited +[2025-11-05 19:03:49 +0200] [413017] [INFO] 👋 Worker 413056 exited +[2025-11-05 19:03:50 +0200] [413017] [INFO] Shutting down: Master +[2025-11-05 19:03:50 +0200] [413017] [INFO] ============================================================ +[2025-11-05 19:03:50 +0200] [413017] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 19:03:50 +0200] [413017] [INFO] ============================================================ +[2025-11-05 19:03:56 +0200] [413505] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 19:03:56 +0200] [413505] [INFO] ============================================================ +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 19:03:56 +0200] [413505] [INFO] ============================================================ +[2025-11-05 19:03:56 +0200] [413505] [INFO] 📍 Configuration: +[2025-11-05 19:03:56 +0200] [413505] [INFO] • Workers: 9 +[2025-11-05 19:03:56 +0200] [413505] [INFO] • Worker Class: sync +[2025-11-05 19:03:56 +0200] [413505] [INFO] • Timeout: 1800s +[2025-11-05 19:03:56 +0200] [413505] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 19:03:56 +0200] [413505] [INFO] • Preload App: True +[2025-11-05 19:03:56 +0200] [413505] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 19:03:56 +0200] [413505] [INFO] ============================================================ +[2025-11-05 19:03:56 +0200] [413505] [INFO] Listening at: http://0.0.0.0:8781 (413505) +[2025-11-05 19:03:56 +0200] [413505] [INFO] Using worker: sync +[2025-11-05 19:03:56 +0200] [413505] [INFO] ============================================================ +[2025-11-05 19:03:56 +0200] [413505] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 19:03:56 +0200] [413505] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 19:03:56 +0200] [413505] [INFO] ============================================================ +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413527] [INFO] Booting worker with pid: 413527 +[2025-11-05 19:03:56 +0200] [413527] [INFO] ✨ Worker spawned successfully (pid: 413527) +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413528] [INFO] Booting worker with pid: 413528 +[2025-11-05 19:03:56 +0200] [413528] [INFO] ✨ Worker spawned successfully (pid: 413528) +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413529] [INFO] Booting worker with pid: 413529 +[2025-11-05 19:03:56 +0200] [413529] [INFO] ✨ Worker spawned successfully (pid: 413529) +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413530] [INFO] Booting worker with pid: 413530 +[2025-11-05 19:03:56 +0200] [413530] [INFO] ✨ Worker spawned successfully (pid: 413530) +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413531] [INFO] Booting worker with pid: 413531 +[2025-11-05 19:03:56 +0200] [413531] [INFO] ✨ Worker spawned successfully (pid: 413531) +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413532] [INFO] Booting worker with pid: 413532 +[2025-11-05 19:03:56 +0200] [413532] [INFO] ✨ Worker spawned successfully (pid: 413532) +[2025-11-05 19:03:56 +0200] [413533] [INFO] Booting worker with pid: 413533 +[2025-11-05 19:03:56 +0200] [413533] [INFO] ✨ Worker spawned successfully (pid: 413533) +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413534] [INFO] Booting worker with pid: 413534 +[2025-11-05 19:03:56 +0200] [413534] [INFO] ✨ Worker spawned successfully (pid: 413534) +[2025-11-05 19:03:56 +0200] [413505] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 19:03:56 +0200] [413541] [INFO] Booting worker with pid: 413541 +[2025-11-05 19:03:56 +0200] [413541] [INFO] ✨ Worker spawned successfully (pid: 413541) +Session user: superadmin superadmin +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +[2025-11-05 20:34:13 +0200] [413505] [INFO] Handling signal: term +[2025-11-05 20:34:13 +0200] [413530] [INFO] Worker exiting (pid: 413530) +[2025-11-05 20:34:13 +0200] [413527] [INFO] Worker exiting (pid: 413527) +[2025-11-05 20:34:13 +0200] [413528] [INFO] Worker exiting (pid: 413528) +[2025-11-05 20:34:13 +0200] [413532] [INFO] Worker exiting (pid: 413532) +[2025-11-05 20:34:13 +0200] [413529] [INFO] Worker exiting (pid: 413529) +[2025-11-05 20:34:13 +0200] [413531] [INFO] Worker exiting (pid: 413531) +[2025-11-05 20:34:13 +0200] [413533] [INFO] Worker exiting (pid: 413533) +[2025-11-05 20:34:13 +0200] [413534] [INFO] Worker exiting (pid: 413534) +[2025-11-05 20:34:13 +0200] [413541] [INFO] Worker exiting (pid: 413541) +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413532 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413534 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413527 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413541 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413528 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413531 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413529 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413533 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Worker 413530 exited +[2025-11-05 20:34:14 +0200] [413505] [INFO] Shutting down: Master +[2025-11-05 20:34:14 +0200] [413505] [INFO] ============================================================ +[2025-11-05 20:34:14 +0200] [413505] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 20:34:14 +0200] [413505] [INFO] ============================================================ +[2025-11-05 20:34:21 +0200] [415087] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 20:34:21 +0200] [415087] [INFO] ============================================================ +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 20:34:21 +0200] [415087] [INFO] ============================================================ +[2025-11-05 20:34:21 +0200] [415087] [INFO] 📍 Configuration: +[2025-11-05 20:34:21 +0200] [415087] [INFO] • Workers: 9 +[2025-11-05 20:34:21 +0200] [415087] [INFO] • Worker Class: sync +[2025-11-05 20:34:21 +0200] [415087] [INFO] • Timeout: 1800s +[2025-11-05 20:34:21 +0200] [415087] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 20:34:21 +0200] [415087] [INFO] • Preload App: True +[2025-11-05 20:34:21 +0200] [415087] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 20:34:21 +0200] [415087] [INFO] ============================================================ +[2025-11-05 20:34:21 +0200] [415087] [INFO] Listening at: http://0.0.0.0:8781 (415087) +[2025-11-05 20:34:21 +0200] [415087] [INFO] Using worker: sync +[2025-11-05 20:34:21 +0200] [415087] [INFO] ============================================================ +[2025-11-05 20:34:21 +0200] [415087] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 20:34:21 +0200] [415087] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 20:34:21 +0200] [415087] [INFO] ============================================================ +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415112] [INFO] Booting worker with pid: 415112 +[2025-11-05 20:34:21 +0200] [415112] [INFO] ✨ Worker spawned successfully (pid: 415112) +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415114] [INFO] Booting worker with pid: 415114 +[2025-11-05 20:34:21 +0200] [415114] [INFO] ✨ Worker spawned successfully (pid: 415114) +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415115] [INFO] Booting worker with pid: 415115 +[2025-11-05 20:34:21 +0200] [415115] [INFO] ✨ Worker spawned successfully (pid: 415115) +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415116] [INFO] Booting worker with pid: 415116 +[2025-11-05 20:34:21 +0200] [415116] [INFO] ✨ Worker spawned successfully (pid: 415116) +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415117] [INFO] Booting worker with pid: 415117 +[2025-11-05 20:34:21 +0200] [415117] [INFO] ✨ Worker spawned successfully (pid: 415117) +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415118] [INFO] Booting worker with pid: 415118 +[2025-11-05 20:34:21 +0200] [415118] [INFO] ✨ Worker spawned successfully (pid: 415118) +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415119] [INFO] Booting worker with pid: 415119 +[2025-11-05 20:34:21 +0200] [415119] [INFO] ✨ Worker spawned successfully (pid: 415119) +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415122] [INFO] Booting worker with pid: 415122 +[2025-11-05 20:34:21 +0200] [415122] [INFO] ✨ Worker spawned successfully (pid: 415122) +[2025-11-05 20:34:21 +0200] [415087] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:34:21 +0200] [415127] [INFO] Booting worker with pid: 415127 +[2025-11-05 20:34:21 +0200] [415127] [INFO] ✨ Worker spawned successfully (pid: 415127) +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +[2025-11-05 20:45:15 +0200] [415087] [INFO] Handling signal: term +[2025-11-05 20:45:15 +0200] [415116] [INFO] Worker exiting (pid: 415116) +[2025-11-05 20:45:15 +0200] [415112] [INFO] Worker exiting (pid: 415112) +[2025-11-05 20:45:15 +0200] [415114] [INFO] Worker exiting (pid: 415114) +[2025-11-05 20:45:15 +0200] [415119] [INFO] Worker exiting (pid: 415119) +[2025-11-05 20:45:15 +0200] [415117] [INFO] Worker exiting (pid: 415117) +[2025-11-05 20:45:15 +0200] [415115] [INFO] Worker exiting (pid: 415115) +[2025-11-05 20:45:15 +0200] [415118] [INFO] Worker exiting (pid: 415118) +[2025-11-05 20:45:15 +0200] [415122] [INFO] Worker exiting (pid: 415122) +[2025-11-05 20:45:15 +0200] [415127] [INFO] Worker exiting (pid: 415127) +[2025-11-05 20:45:15 +0200] [415087] [INFO] 👋 Worker 415112 exited +[2025-11-05 20:45:15 +0200] [415087] [INFO] 👋 Worker 415122 exited +[2025-11-05 20:45:16 +0200] [415087] [INFO] 👋 Worker 415117 exited +[2025-11-05 20:45:16 +0200] [415087] [INFO] 👋 Worker 415114 exited +[2025-11-05 20:45:16 +0200] [415087] [INFO] 👋 Worker 415115 exited +[2025-11-05 20:45:16 +0200] [415087] [INFO] 👋 Worker 415116 exited +[2025-11-05 20:45:16 +0200] [415087] [INFO] 👋 Worker 415119 exited +[2025-11-05 20:45:16 +0200] [415087] [INFO] 👋 Worker 415118 exited +[2025-11-05 20:45:16 +0200] [415087] [INFO] 👋 Worker 415127 exited +[2025-11-05 20:45:16 +0200] [415087] [INFO] Shutting down: Master +[2025-11-05 20:45:16 +0200] [415087] [INFO] ============================================================ +[2025-11-05 20:45:16 +0200] [415087] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 20:45:16 +0200] [415087] [INFO] ============================================================ +Backup directory ensured: /srv/quality_app/backups +INFO:apscheduler.scheduler:Adding job tentatively -- it will be properly scheduled when the scheduler starts +INFO:app.backup_scheduler:✅ Backup schedule configured: data-only backup daily at 03:00 +INFO:apscheduler.scheduler:Added job "Scheduled data-only backup" to job store "default" +INFO:apscheduler.scheduler:Scheduler started +INFO:app.backup_scheduler:Backup scheduler started +✅ Automatic backup scheduler initialized +[2025-11-05 20:45:22 +0200] [415702] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 20:45:22 +0200] [415702] [INFO] ============================================================ +[2025-11-05 20:45:22 +0200] [415702] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 20:45:22 +0200] [415702] [INFO] ============================================================ +[2025-11-05 20:45:22 +0200] [415702] [INFO] 📍 Configuration: +[2025-11-05 20:45:22 +0200] [415702] [INFO] • Workers: 9 +[2025-11-05 20:45:22 +0200] [415702] [INFO] • Worker Class: sync +[2025-11-05 20:45:22 +0200] [415702] [INFO] • Timeout: 1800s +[2025-11-05 20:45:22 +0200] [415702] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 20:45:22 +0200] [415702] [INFO] • Preload App: True +[2025-11-05 20:45:22 +0200] [415702] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 20:45:22 +0200] [415702] [INFO] ============================================================ +[2025-11-05 20:45:22 +0200] [415702] [INFO] Listening at: http://0.0.0.0:8781 (415702) +[2025-11-05 20:45:22 +0200] [415702] [INFO] Using worker: sync +[2025-11-05 20:45:22 +0200] [415702] [INFO] ============================================================ +[2025-11-05 20:45:22 +0200] [415702] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 20:45:22 +0200] [415702] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 20:45:22 +0200] [415702] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 20:45:22 +0200] [415702] [INFO] ============================================================ +[2025-11-05 20:45:22 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:22 +0200] [415732] [INFO] Booting worker with pid: 415732 +[2025-11-05 20:45:22 +0200] [415732] [INFO] ✨ Worker spawned successfully (pid: 415732) +[2025-11-05 20:45:22 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:22 +0200] [415734] [INFO] Booting worker with pid: 415734 +[2025-11-05 20:45:22 +0200] [415734] [INFO] ✨ Worker spawned successfully (pid: 415734) +[2025-11-05 20:45:23 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:23 +0200] [415736] [INFO] Booting worker with pid: 415736 +[2025-11-05 20:45:23 +0200] [415736] [INFO] ✨ Worker spawned successfully (pid: 415736) +[2025-11-05 20:45:23 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:23 +0200] [415741] [INFO] Booting worker with pid: 415741 +[2025-11-05 20:45:23 +0200] [415741] [INFO] ✨ Worker spawned successfully (pid: 415741) +[2025-11-05 20:45:23 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:23 +0200] [415742] [INFO] Booting worker with pid: 415742 +[2025-11-05 20:45:23 +0200] [415742] [INFO] ✨ Worker spawned successfully (pid: 415742) +[2025-11-05 20:45:23 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:23 +0200] [415743] [INFO] Booting worker with pid: 415743 +[2025-11-05 20:45:23 +0200] [415743] [INFO] ✨ Worker spawned successfully (pid: 415743) +[2025-11-05 20:45:23 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:23 +0200] [415744] [INFO] Booting worker with pid: 415744 +[2025-11-05 20:45:23 +0200] [415744] [INFO] ✨ Worker spawned successfully (pid: 415744) +[2025-11-05 20:45:23 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:23 +0200] [415745] [INFO] Booting worker with pid: 415745 +[2025-11-05 20:45:23 +0200] [415745] [INFO] ✨ Worker spawned successfully (pid: 415745) +[2025-11-05 20:45:23 +0200] [415702] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:45:23 +0200] [415746] [INFO] Booting worker with pid: 415746 +[2025-11-05 20:45:23 +0200] [415746] [INFO] ✨ Worker spawned successfully (pid: 415746) +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +[2025-11-05 20:50:27 +0200] [415702] [INFO] Handling signal: term +[2025-11-05 20:50:27 +0200] [415736] [INFO] Worker exiting (pid: 415736) +[2025-11-05 20:50:27 +0200] [415732] [INFO] Worker exiting (pid: 415732) +[2025-11-05 20:50:27 +0200] [415734] [INFO] Worker exiting (pid: 415734) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 20:50:27 +0200] [415742] [INFO] Worker exiting (pid: 415742) +[2025-11-05 20:50:27 +0200] [415743] [INFO] Worker exiting (pid: 415743) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 20:50:27 +0200] [415741] [INFO] Worker exiting (pid: 415741) +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 20:50:27 +0200] [415745] [INFO] Worker exiting (pid: 415745) +[2025-11-05 20:50:27 +0200] [415746] [INFO] Worker exiting (pid: 415746) +[2025-11-05 20:50:27 +0200] [415744] [INFO] Worker exiting (pid: 415744) +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415734 exited +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415743 exited +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415736 exited +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415742 exited +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415745 exited +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415744 exited +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415732 exited +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415746 exited +[2025-11-05 20:50:28 +0200] [415702] [INFO] 👋 Worker 415741 exited +[2025-11-05 20:50:29 +0200] [415702] [INFO] Shutting down: Master +[2025-11-05 20:50:29 +0200] [415702] [INFO] ============================================================ +[2025-11-05 20:50:29 +0200] [415702] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 20:50:29 +0200] [415702] [INFO] ============================================================ +INFO:apscheduler.scheduler:Scheduler has been shut down +Backup directory ensured: /srv/quality_app/backups +INFO:apscheduler.scheduler:Adding job tentatively -- it will be properly scheduled when the scheduler starts +INFO:app.backup_scheduler:✅ Backup schedule configured: data-only backup daily at 03:00 +INFO:apscheduler.scheduler:Added job "Scheduled data-only backup" to job store "default" +INFO:apscheduler.scheduler:Scheduler started +INFO:app.backup_scheduler:Backup scheduler started +✅ Automatic backup scheduler initialized +[2025-11-05 20:50:35 +0200] [415998] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 20:50:35 +0200] [415998] [INFO] ============================================================ +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 20:50:35 +0200] [415998] [INFO] ============================================================ +[2025-11-05 20:50:35 +0200] [415998] [INFO] 📍 Configuration: +[2025-11-05 20:50:35 +0200] [415998] [INFO] • Workers: 9 +[2025-11-05 20:50:35 +0200] [415998] [INFO] • Worker Class: sync +[2025-11-05 20:50:35 +0200] [415998] [INFO] • Timeout: 1800s +[2025-11-05 20:50:35 +0200] [415998] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 20:50:35 +0200] [415998] [INFO] • Preload App: True +[2025-11-05 20:50:35 +0200] [415998] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 20:50:35 +0200] [415998] [INFO] ============================================================ +[2025-11-05 20:50:35 +0200] [415998] [INFO] Listening at: http://0.0.0.0:8781 (415998) +[2025-11-05 20:50:35 +0200] [415998] [INFO] Using worker: sync +[2025-11-05 20:50:35 +0200] [415998] [INFO] ============================================================ +[2025-11-05 20:50:35 +0200] [415998] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 20:50:35 +0200] [415998] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 20:50:35 +0200] [415998] [INFO] ============================================================ +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416025] [INFO] Booting worker with pid: 416025 +[2025-11-05 20:50:35 +0200] [416025] [INFO] ✨ Worker spawned successfully (pid: 416025) +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416026] [INFO] Booting worker with pid: 416026 +[2025-11-05 20:50:35 +0200] [416026] [INFO] ✨ Worker spawned successfully (pid: 416026) +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416027] [INFO] Booting worker with pid: 416027 +[2025-11-05 20:50:35 +0200] [416027] [INFO] ✨ Worker spawned successfully (pid: 416027) +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416029] [INFO] Booting worker with pid: 416029 +[2025-11-05 20:50:35 +0200] [416029] [INFO] ✨ Worker spawned successfully (pid: 416029) +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416034] [INFO] Booting worker with pid: 416034 +[2025-11-05 20:50:35 +0200] [416034] [INFO] ✨ Worker spawned successfully (pid: 416034) +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416036] [INFO] Booting worker with pid: 416036 +[2025-11-05 20:50:35 +0200] [416036] [INFO] ✨ Worker spawned successfully (pid: 416036) +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416037] [INFO] Booting worker with pid: 416037 +[2025-11-05 20:50:35 +0200] [416037] [INFO] ✨ Worker spawned successfully (pid: 416037) +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416038] [INFO] Booting worker with pid: 416038 +[2025-11-05 20:50:35 +0200] [416038] [INFO] ✨ Worker spawned successfully (pid: 416038) +[2025-11-05 20:50:35 +0200] [415998] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 20:50:35 +0200] [416039] [INFO] Booting worker with pid: 416039 +[2025-11-05 20:50:35 +0200] [416039] [INFO] ✨ Worker spawned successfully (pid: 416039) +[2025-11-05 21:07:56 +0200] [415998] [INFO] Handling signal: term +[2025-11-05 21:07:56 +0200] [416025] [INFO] Worker exiting (pid: 416025) +[2025-11-05 21:07:56 +0200] [416026] [INFO] Worker exiting (pid: 416026) +[2025-11-05 21:07:56 +0200] [416034] [INFO] Worker exiting (pid: 416034) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:07:56 +0200] [416027] [INFO] Worker exiting (pid: 416027) +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:07:56 +0200] [416029] [INFO] Worker exiting (pid: 416029) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:07:56 +0200] [416036] [INFO] Worker exiting (pid: 416036) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:07:56 +0200] [416037] [INFO] Worker exiting (pid: 416037) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:07:56 +0200] [416038] [INFO] Worker exiting (pid: 416038) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:07:56 +0200] [416039] [INFO] Worker exiting (pid: 416039) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:07:56 +0200] [415998] [INFO] 👋 Worker 416025 exited +[2025-11-05 21:07:56 +0200] [415998] [INFO] 👋 Worker 416027 exited +[2025-11-05 21:07:56 +0200] [415998] [INFO] 👋 Worker 416026 exited +[2025-11-05 21:07:56 +0200] [415998] [INFO] 👋 Worker 416038 exited +[2025-11-05 21:07:56 +0200] [415998] [INFO] 👋 Worker 416037 exited +[2025-11-05 21:07:56 +0200] [415998] [INFO] 👋 Worker 416034 exited +[2025-11-05 21:07:57 +0200] [415998] [INFO] 👋 Worker 416036 exited +[2025-11-05 21:07:57 +0200] [415998] [INFO] 👋 Worker 416039 exited +[2025-11-05 21:07:57 +0200] [415998] [INFO] 👋 Worker 416029 exited +[2025-11-05 21:07:57 +0200] [415998] [INFO] Shutting down: Master +[2025-11-05 21:07:57 +0200] [415998] [INFO] ============================================================ +[2025-11-05 21:07:57 +0200] [415998] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 21:07:57 +0200] [415998] [INFO] ============================================================ +INFO:apscheduler.scheduler:Scheduler has been shut down +Backup directory ensured: /srv/quality_app/backups +INFO:apscheduler.scheduler:Adding job tentatively -- it will be properly scheduled when the scheduler starts +INFO:app.backup_scheduler:✅ Backup schedule configured: data-only backup daily at 03:00 +INFO:apscheduler.scheduler:Added job "Scheduled data-only backup" to job store "default" +INFO:apscheduler.scheduler:Scheduler started +INFO:app.backup_scheduler:Backup scheduler started +✅ Automatic backup scheduler initialized +[2025-11-05 21:08:01 +0200] [416525] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 21:08:01 +0200] [416525] [INFO] ============================================================ +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 21:08:01 +0200] [416525] [INFO] ============================================================ +[2025-11-05 21:08:01 +0200] [416525] [INFO] 📍 Configuration: +[2025-11-05 21:08:01 +0200] [416525] [INFO] • Workers: 9 +[2025-11-05 21:08:01 +0200] [416525] [INFO] • Worker Class: sync +[2025-11-05 21:08:01 +0200] [416525] [INFO] • Timeout: 1800s +[2025-11-05 21:08:01 +0200] [416525] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 21:08:01 +0200] [416525] [INFO] • Preload App: True +[2025-11-05 21:08:01 +0200] [416525] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 21:08:01 +0200] [416525] [INFO] ============================================================ +[2025-11-05 21:08:01 +0200] [416525] [INFO] Listening at: http://0.0.0.0:8781 (416525) +[2025-11-05 21:08:01 +0200] [416525] [INFO] Using worker: sync +[2025-11-05 21:08:01 +0200] [416525] [INFO] ============================================================ +[2025-11-05 21:08:01 +0200] [416525] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 21:08:01 +0200] [416525] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 21:08:01 +0200] [416525] [INFO] ============================================================ +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416535] [INFO] Booting worker with pid: 416535 +[2025-11-05 21:08:01 +0200] [416535] [INFO] ✨ Worker spawned successfully (pid: 416535) +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416536] [INFO] Booting worker with pid: 416536 +[2025-11-05 21:08:01 +0200] [416536] [INFO] ✨ Worker spawned successfully (pid: 416536) +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416537] [INFO] Booting worker with pid: 416537 +[2025-11-05 21:08:01 +0200] [416537] [INFO] ✨ Worker spawned successfully (pid: 416537) +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416539] [INFO] Booting worker with pid: 416539 +[2025-11-05 21:08:01 +0200] [416539] [INFO] ✨ Worker spawned successfully (pid: 416539) +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416541] [INFO] Booting worker with pid: 416541 +[2025-11-05 21:08:01 +0200] [416541] [INFO] ✨ Worker spawned successfully (pid: 416541) +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416546] [INFO] Booting worker with pid: 416546 +[2025-11-05 21:08:01 +0200] [416546] [INFO] ✨ Worker spawned successfully (pid: 416546) +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416547] [INFO] Booting worker with pid: 416547 +[2025-11-05 21:08:01 +0200] [416547] [INFO] ✨ Worker spawned successfully (pid: 416547) +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416548] [INFO] Booting worker with pid: 416548 +[2025-11-05 21:08:01 +0200] [416548] [INFO] ✨ Worker spawned successfully (pid: 416548) +[2025-11-05 21:08:01 +0200] [416525] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:08:01 +0200] [416549] [INFO] Booting worker with pid: 416549 +[2025-11-05 21:08:01 +0200] [416549] [INFO] ✨ Worker spawned successfully (pid: 416549) +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +[2025-11-05 21:10:52 +0200] [416525] [INFO] Handling signal: term +[2025-11-05 21:10:52 +0200] [416539] [INFO] Worker exiting (pid: 416539) +[2025-11-05 21:10:52 +0200] [416535] [INFO] Worker exiting (pid: 416535) +[2025-11-05 21:10:52 +0200] [416536] [INFO] Worker exiting (pid: 416536) +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:10:52 +0200] [416537] [INFO] Worker exiting (pid: 416537) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:10:52 +0200] [416546] [INFO] Worker exiting (pid: 416546) +[2025-11-05 21:10:52 +0200] [416549] [INFO] Worker exiting (pid: 416549) +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:10:52 +0200] [416541] [INFO] Worker exiting (pid: 416541) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:10:52 +0200] [416547] [INFO] Worker exiting (pid: 416547) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:10:52 +0200] [416548] [INFO] Worker exiting (pid: 416548) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:10:52 +0200] [416525] [INFO] 👋 Worker 416536 exited +[2025-11-05 21:10:52 +0200] [416525] [INFO] 👋 Worker 416537 exited +[2025-11-05 21:10:53 +0200] [416525] [INFO] 👋 Worker 416541 exited +[2025-11-05 21:10:53 +0200] [416525] [INFO] 👋 Worker 416549 exited +[2025-11-05 21:10:53 +0200] [416525] [INFO] 👋 Worker 416546 exited +[2025-11-05 21:10:53 +0200] [416525] [INFO] 👋 Worker 416535 exited +[2025-11-05 21:10:53 +0200] [416525] [INFO] 👋 Worker 416539 exited +[2025-11-05 21:10:53 +0200] [416525] [INFO] 👋 Worker 416547 exited +[2025-11-05 21:10:53 +0200] [416525] [INFO] 👋 Worker 416548 exited +[2025-11-05 21:10:53 +0200] [416525] [INFO] Shutting down: Master +[2025-11-05 21:10:53 +0200] [416525] [INFO] ============================================================ +[2025-11-05 21:10:53 +0200] [416525] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 21:10:53 +0200] [416525] [INFO] ============================================================ +INFO:apscheduler.scheduler:Scheduler has been shut down +Backup directory ensured: /srv/quality_app/backups +INFO:apscheduler.scheduler:Adding job tentatively -- it will be properly scheduled when the scheduler starts +INFO:app.backup_scheduler:✅ Backup schedule configured: data-only backup daily at 03:00 +INFO:apscheduler.scheduler:Added job "Scheduled data-only backup" to job store "default" +INFO:apscheduler.scheduler:Scheduler started +INFO:app.backup_scheduler:Backup scheduler started +✅ Automatic backup scheduler initialized +[2025-11-05 21:10:57 +0200] [416774] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 21:10:57 +0200] [416774] [INFO] ============================================================ +[2025-11-05 21:10:57 +0200] [416774] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 21:10:57 +0200] [416774] [INFO] ============================================================ +[2025-11-05 21:10:57 +0200] [416774] [INFO] 📍 Configuration: +[2025-11-05 21:10:57 +0200] [416774] [INFO] • Workers: 9 +[2025-11-05 21:10:57 +0200] [416774] [INFO] • Worker Class: sync +[2025-11-05 21:10:57 +0200] [416774] [INFO] • Timeout: 1800s +[2025-11-05 21:10:57 +0200] [416774] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 21:10:57 +0200] [416774] [INFO] • Preload App: True +[2025-11-05 21:10:57 +0200] [416774] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 21:10:57 +0200] [416774] [INFO] ============================================================ +[2025-11-05 21:10:57 +0200] [416774] [INFO] Listening at: http://0.0.0.0:8781 (416774) +[2025-11-05 21:10:57 +0200] [416774] [INFO] Using worker: sync +[2025-11-05 21:10:57 +0200] [416774] [INFO] ============================================================ +[2025-11-05 21:10:57 +0200] [416774] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 21:10:57 +0200] [416774] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 21:10:57 +0200] [416774] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 21:10:57 +0200] [416774] [INFO] ============================================================ +[2025-11-05 21:10:57 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:57 +0200] [416785] [INFO] Booting worker with pid: 416785 +[2025-11-05 21:10:57 +0200] [416785] [INFO] ✨ Worker spawned successfully (pid: 416785) +[2025-11-05 21:10:57 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:57 +0200] [416786] [INFO] Booting worker with pid: 416786 +[2025-11-05 21:10:57 +0200] [416786] [INFO] ✨ Worker spawned successfully (pid: 416786) +[2025-11-05 21:10:57 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:57 +0200] [416787] [INFO] Booting worker with pid: 416787 +[2025-11-05 21:10:57 +0200] [416787] [INFO] ✨ Worker spawned successfully (pid: 416787) +[2025-11-05 21:10:57 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:57 +0200] [416788] [INFO] Booting worker with pid: 416788 +[2025-11-05 21:10:58 +0200] [416788] [INFO] ✨ Worker spawned successfully (pid: 416788) +[2025-11-05 21:10:58 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:58 +0200] [416791] [INFO] Booting worker with pid: 416791 +[2025-11-05 21:10:58 +0200] [416791] [INFO] ✨ Worker spawned successfully (pid: 416791) +[2025-11-05 21:10:58 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:58 +0200] [416796] [INFO] Booting worker with pid: 416796 +[2025-11-05 21:10:58 +0200] [416796] [INFO] ✨ Worker spawned successfully (pid: 416796) +[2025-11-05 21:10:58 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:58 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:58 +0200] [416797] [INFO] Booting worker with pid: 416797 +[2025-11-05 21:10:58 +0200] [416797] [INFO] ✨ Worker spawned successfully (pid: 416797) +[2025-11-05 21:10:58 +0200] [416798] [INFO] Booting worker with pid: 416798 +[2025-11-05 21:10:58 +0200] [416798] [INFO] ✨ Worker spawned successfully (pid: 416798) +[2025-11-05 21:10:58 +0200] [416774] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:10:58 +0200] [416808] [INFO] Booting worker with pid: 416808 +[2025-11-05 21:10:58 +0200] [416808] [INFO] ✨ Worker spawned successfully (pid: 416808) +[2025-11-05 21:18:44 +0200] [416774] [INFO] Handling signal: term +[2025-11-05 21:18:44 +0200] [416788] [INFO] Worker exiting (pid: 416788) +[2025-11-05 21:18:44 +0200] [416786] [INFO] Worker exiting (pid: 416786) +[2025-11-05 21:18:44 +0200] [416785] [INFO] Worker exiting (pid: 416785) +[2025-11-05 21:18:44 +0200] [416787] [INFO] Worker exiting (pid: 416787) +[2025-11-05 21:18:44 +0200] [416797] [INFO] Worker exiting (pid: 416797) +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:18:44 +0200] [416791] [INFO] Worker exiting (pid: 416791) +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:18:44 +0200] [416796] [INFO] Worker exiting (pid: 416796) +[2025-11-05 21:18:44 +0200] [416808] [INFO] Worker exiting (pid: 416808) +INFO:apscheduler.scheduler:Scheduler has been shut down +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:18:44 +0200] [416798] [INFO] Worker exiting (pid: 416798) +INFO:apscheduler.scheduler:Scheduler has been shut down +[2025-11-05 21:18:44 +0200] [416774] [INFO] 👋 Worker 416785 exited +[2025-11-05 21:18:44 +0200] [416774] [INFO] 👋 Worker 416788 exited +[2025-11-05 21:18:44 +0200] [416774] [INFO] 👋 Worker 416797 exited +[2025-11-05 21:18:45 +0200] [416774] [INFO] 👋 Worker 416787 exited +[2025-11-05 21:18:45 +0200] [416774] [INFO] 👋 Worker 416808 exited +[2025-11-05 21:18:45 +0200] [416774] [INFO] 👋 Worker 416786 exited +[2025-11-05 21:18:45 +0200] [416774] [INFO] 👋 Worker 416798 exited +[2025-11-05 21:18:45 +0200] [416774] [INFO] 👋 Worker 416791 exited +[2025-11-05 21:18:45 +0200] [416774] [INFO] 👋 Worker 416796 exited +[2025-11-05 21:18:45 +0200] [416774] [INFO] Shutting down: Master +[2025-11-05 21:18:45 +0200] [416774] [INFO] ============================================================ +[2025-11-05 21:18:45 +0200] [416774] [INFO] 👋 Trasabilitate Application - Shutting Down +[2025-11-05 21:18:45 +0200] [416774] [INFO] ============================================================ +INFO:apscheduler.scheduler:Scheduler has been shut down +Backup directory ensured: /srv/quality_app/backups +INFO:apscheduler.scheduler:Adding job tentatively -- it will be properly scheduled when the scheduler starts +INFO:app.backup_scheduler:✅ Backup schedule configured: data-only backup daily at 03:00 +INFO:apscheduler.scheduler:Added job "Scheduled data-only backup" to job store "default" +INFO:apscheduler.scheduler:Scheduler started +INFO:app.backup_scheduler:Backup scheduler started +✅ Automatic backup scheduler initialized +[2025-11-05 21:18:49 +0200] [417124] [INFO] Starting gunicorn 23.0.0 +[2025-11-05 21:18:49 +0200] [417124] [INFO] ============================================================ +[2025-11-05 21:18:49 +0200] [417124] [INFO] 🚀 Trasabilitate Application - Starting Server +[2025-11-05 21:18:49 +0200] [417124] [INFO] ============================================================ +[2025-11-05 21:18:49 +0200] [417124] [INFO] 📍 Configuration: +[2025-11-05 21:18:49 +0200] [417124] [INFO] • Workers: 9 +[2025-11-05 21:18:49 +0200] [417124] [INFO] • Worker Class: sync +[2025-11-05 21:18:49 +0200] [417124] [INFO] • Timeout: 1800s +[2025-11-05 21:18:49 +0200] [417124] [INFO] • Bind: 0.0.0.0:8781 +[2025-11-05 21:18:49 +0200] [417124] [INFO] • Preload App: True +[2025-11-05 21:18:49 +0200] [417124] [INFO] • Max Requests: 1000 (+/- 100) +[2025-11-05 21:18:49 +0200] [417124] [INFO] ============================================================ +[2025-11-05 21:18:49 +0200] [417124] [INFO] Listening at: http://0.0.0.0:8781 (417124) +[2025-11-05 21:18:49 +0200] [417124] [INFO] Using worker: sync +[2025-11-05 21:18:49 +0200] [417124] [INFO] ============================================================ +[2025-11-05 21:18:49 +0200] [417124] [INFO] ✅ Trasabilitate Application Server is READY! +[2025-11-05 21:18:49 +0200] [417124] [INFO] 📡 Listening on: [('0.0.0.0', 8781)] +[2025-11-05 21:18:49 +0200] [417124] [INFO] 🌐 Access the application at: http://0.0.0.0:8781 +[2025-11-05 21:18:49 +0200] [417124] [INFO] ============================================================ +[2025-11-05 21:18:49 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:49 +0200] [417129] [INFO] Booting worker with pid: 417129 +[2025-11-05 21:18:49 +0200] [417129] [INFO] ✨ Worker spawned successfully (pid: 417129) +[2025-11-05 21:18:49 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:49 +0200] [417130] [INFO] Booting worker with pid: 417130 +[2025-11-05 21:18:49 +0200] [417130] [INFO] ✨ Worker spawned successfully (pid: 417130) +[2025-11-05 21:18:49 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:49 +0200] [417131] [INFO] Booting worker with pid: 417131 +[2025-11-05 21:18:49 +0200] [417131] [INFO] ✨ Worker spawned successfully (pid: 417131) +[2025-11-05 21:18:49 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:49 +0200] [417134] [INFO] Booting worker with pid: 417134 +[2025-11-05 21:18:49 +0200] [417134] [INFO] ✨ Worker spawned successfully (pid: 417134) +[2025-11-05 21:18:49 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:49 +0200] [417138] [INFO] Booting worker with pid: 417138 +[2025-11-05 21:18:49 +0200] [417138] [INFO] ✨ Worker spawned successfully (pid: 417138) +[2025-11-05 21:18:49 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:49 +0200] [417140] [INFO] Booting worker with pid: 417140 +[2025-11-05 21:18:49 +0200] [417140] [INFO] ✨ Worker spawned successfully (pid: 417140) +[2025-11-05 21:18:50 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:50 +0200] [417141] [INFO] Booting worker with pid: 417141 +[2025-11-05 21:18:50 +0200] [417141] [INFO] ✨ Worker spawned successfully (pid: 417141) +[2025-11-05 21:18:50 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:50 +0200] [417142] [INFO] Booting worker with pid: 417142 +[2025-11-05 21:18:50 +0200] [417142] [INFO] ✨ Worker spawned successfully (pid: 417142) +[2025-11-05 21:18:50 +0200] [417124] [INFO] 🔄 Forking new worker (pid: [booting]) +[2025-11-05 21:18:50 +0200] [417143] [INFO] Booting worker with pid: 417143 +[2025-11-05 21:18:50 +0200] [417143] [INFO] ✨ Worker spawned successfully (pid: 417143) +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Backup directory ensured: /srv/quality_app/backups +Session user: superadmin superadmin diff --git a/py_app/app/__init__.py b/py_app/app/__init__.py index 35d434f..2419b3c 100755 --- a/py_app/app/__init__.py +++ b/py_app/app/__init__.py @@ -19,5 +19,10 @@ def create_app(): # Add 'now' function to Jinja2 globals app.jinja_env.globals['now'] = datetime.now + + # Initialize automatic backup scheduler + from app.backup_scheduler import init_backup_scheduler + init_backup_scheduler(app) + print("✅ Automatic backup scheduler initialized") return app \ No newline at end of file diff --git a/py_app/app/backup_scheduler.py b/py_app/app/backup_scheduler.py new file mode 100644 index 0000000..0a40946 --- /dev/null +++ b/py_app/app/backup_scheduler.py @@ -0,0 +1,296 @@ +""" +Automated Backup Scheduler +Quality Recticel Application + +This module manages automatic backup execution based on the configured schedule. +Uses APScheduler to run backups at specified times. +""" + +from apscheduler.schedulers.background import BackgroundScheduler +from apscheduler.triggers.cron import CronTrigger +from datetime import datetime +import logging + +# Configure logging +logger = logging.getLogger(__name__) + + +class BackupScheduler: + """Manages automatic backup scheduling""" + + def __init__(self, app=None): + """ + Initialize the backup scheduler + + Args: + app: Flask application instance + """ + self.scheduler = None + self.app = app + self.job_prefix = 'scheduled_backup' + + if app is not None: + self.init_app(app) + + def init_app(self, app): + """ + Initialize scheduler with Flask app context + + Args: + app: Flask application instance + """ + self.app = app + + # Create scheduler + self.scheduler = BackgroundScheduler( + daemon=True, + timezone='Europe/Bucharest' # Adjust to your timezone + ) + + # Load and apply schedule from configuration + self.update_schedule() + + # Start scheduler + self.scheduler.start() + logger.info("Backup scheduler started") + + # Register shutdown handler + import atexit + atexit.register(lambda: self.scheduler.shutdown()) + + def execute_scheduled_backup(self, schedule_id, backup_type): + """ + Execute a backup based on the schedule configuration + This method runs in the scheduler thread + + Args: + schedule_id: Identifier for the schedule + backup_type: Type of backup ('full' or 'data-only') + """ + try: + from app.database_backup import DatabaseBackupManager + + with self.app.app_context(): + backup_manager = DatabaseBackupManager() + + logger.info(f"Starting scheduled {backup_type} backup (schedule: {schedule_id})...") + + # Execute appropriate backup + if backup_type == 'data-only': + result = backup_manager.create_data_only_backup(backup_name='scheduled') + else: + result = backup_manager.create_backup(backup_name='scheduled') + + if result['success']: + logger.info(f"✅ Scheduled backup completed: {result['filename']} ({result['size']})") + + # Clean up old backups based on retention policy + schedule = backup_manager.get_backup_schedule() + schedules = schedule.get('schedules', []) if isinstance(schedule, dict) and 'schedules' in schedule else [] + + # Find the schedule that triggered this backup + current_schedule = next((s for s in schedules if s.get('id') == schedule_id), None) + if current_schedule: + retention_days = current_schedule.get('retention_days', 30) + cleanup_result = backup_manager.cleanup_old_backups(retention_days) + + if cleanup_result['success'] and cleanup_result['deleted_count'] > 0: + logger.info(f"🗑️ Cleaned up {cleanup_result['deleted_count']} old backup(s)") + else: + logger.error(f"❌ Scheduled backup failed: {result['message']}") + + except Exception as e: + logger.error(f"❌ Error during scheduled backup: {e}", exc_info=True) + + def update_schedule(self): + """ + Reload schedule from configuration and update scheduler jobs + Supports multiple schedules + """ + try: + from app.database_backup import DatabaseBackupManager + + with self.app.app_context(): + backup_manager = DatabaseBackupManager() + schedule_config = backup_manager.get_backup_schedule() + + # Remove all existing backup jobs + for job in self.scheduler.get_jobs(): + if job.id.startswith(self.job_prefix): + self.scheduler.remove_job(job.id) + + # Handle new multi-schedule format + if isinstance(schedule_config, dict) and 'schedules' in schedule_config: + schedules = schedule_config['schedules'] + + for schedule in schedules: + if not schedule.get('enabled', False): + continue + + schedule_id = schedule.get('id', 'default') + time_str = schedule.get('time', '02:00') + frequency = schedule.get('frequency', 'daily') + backup_type = schedule.get('backup_type', 'full') + + # Parse time + hour, minute = map(int, time_str.split(':')) + + # Create appropriate trigger + if frequency == 'daily': + trigger = CronTrigger(hour=hour, minute=minute) + elif frequency == 'weekly': + trigger = CronTrigger(day_of_week='sun', hour=hour, minute=minute) + elif frequency == 'monthly': + trigger = CronTrigger(day=1, hour=hour, minute=minute) + else: + logger.error(f"Unknown frequency: {frequency}") + continue + + # Add job with unique ID + job_id = f"{self.job_prefix}_{schedule_id}" + self.scheduler.add_job( + func=self.execute_scheduled_backup, + trigger=trigger, + args=[schedule_id, backup_type], + id=job_id, + name=f'Scheduled {backup_type} backup ({schedule_id})', + replace_existing=True + ) + + logger.info(f"✅ Schedule '{schedule_id}': {backup_type} backup {frequency} at {time_str}") + + # Handle legacy single-schedule format (backward compatibility) + elif isinstance(schedule_config, dict) and schedule_config.get('enabled', False): + time_str = schedule_config.get('time', '02:00') + frequency = schedule_config.get('frequency', 'daily') + backup_type = schedule_config.get('backup_type', 'full') + + hour, minute = map(int, time_str.split(':')) + + if frequency == 'daily': + trigger = CronTrigger(hour=hour, minute=minute) + elif frequency == 'weekly': + trigger = CronTrigger(day_of_week='sun', hour=hour, minute=minute) + elif frequency == 'monthly': + trigger = CronTrigger(day=1, hour=hour, minute=minute) + else: + logger.error(f"Unknown frequency: {frequency}") + return + + job_id = f"{self.job_prefix}_default" + self.scheduler.add_job( + func=self.execute_scheduled_backup, + trigger=trigger, + args=['default', backup_type], + id=job_id, + name=f'Scheduled {backup_type} backup', + replace_existing=True + ) + + logger.info(f"✅ Backup schedule configured: {backup_type} backup {frequency} at {time_str}") + + except Exception as e: + logger.error(f"Error updating backup schedule: {e}", exc_info=True) + + def get_next_run_time(self, schedule_id='default'): + """ + Get the next scheduled run time for a specific schedule + + Args: + schedule_id: Identifier for the schedule + + Returns: + datetime or None: Next run time if job exists + """ + if not self.scheduler: + return None + + job_id = f"{self.job_prefix}_{schedule_id}" + job = self.scheduler.get_job(job_id) + if job: + return job.next_run_time + return None + + def get_schedule_info(self): + """ + Get information about all schedules + + Returns: + dict: Schedule information including next run times for all jobs + """ + try: + from app.database_backup import DatabaseBackupManager + + with self.app.app_context(): + backup_manager = DatabaseBackupManager() + schedule_config = backup_manager.get_backup_schedule() + + # Get all backup jobs + jobs_info = [] + for job in self.scheduler.get_jobs(): + if job.id.startswith(self.job_prefix): + jobs_info.append({ + 'id': job.id.replace(f"{self.job_prefix}_", ""), + 'name': job.name, + 'next_run_time': job.next_run_time.strftime('%Y-%m-%d %H:%M:%S') if job.next_run_time else None + }) + + return { + 'schedule': schedule_config, + 'jobs': jobs_info, + 'scheduler_running': self.scheduler.running if self.scheduler else False, + 'total_jobs': len(jobs_info) + } + except Exception as e: + logger.error(f"Error getting schedule info: {e}") + return None + + def trigger_backup_now(self): + """ + Manually trigger a backup immediately (outside of schedule) + + Returns: + dict: Result of backup operation + """ + try: + logger.info("Manual backup trigger requested") + self.execute_scheduled_backup() + return { + 'success': True, + 'message': 'Backup triggered successfully' + } + except Exception as e: + logger.error(f"Error triggering manual backup: {e}") + return { + 'success': False, + 'message': f'Failed to trigger backup: {str(e)}' + } + + +# Global scheduler instance (initialized in __init__.py) +backup_scheduler = None + + +def init_backup_scheduler(app): + """ + Initialize the global backup scheduler instance + + Args: + app: Flask application instance + + Returns: + BackupScheduler: Initialized scheduler instance + """ + global backup_scheduler + backup_scheduler = BackupScheduler(app) + return backup_scheduler + + +def get_backup_scheduler(): + """ + Get the global backup scheduler instance + + Returns: + BackupScheduler or None: Scheduler instance if initialized + """ + return backup_scheduler diff --git a/py_app/app/database_backup.py b/py_app/app/database_backup.py index 5e0e50d..5e938d5 100644 --- a/py_app/app/database_backup.py +++ b/py_app/app/database_backup.py @@ -281,6 +281,95 @@ class DatabaseBackupManager: except Exception as e: print(f"Error removing backup metadata: {e}") + def create_data_only_backup(self, backup_name=None): + """ + Create a data-only backup (no schema, triggers, or structure) + Only exports INSERT statements for existing tables + + Args: + backup_name (str, optional): Custom name for the backup file + + Returns: + dict: Result with success status, message, and backup file path + """ + try: + if not self.config: + return { + 'success': False, + 'message': 'Database configuration not loaded' + } + + # Generate backup filename with data_only prefix + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + if backup_name: + filename = f"data_only_{backup_name}_{timestamp}.sql" + else: + filename = f"data_only_{self.config['database']}_{timestamp}.sql" + + backup_file = os.path.join(self.backup_path, filename) + + # Build mysqldump command for data only + # --no-create-info: Skip CREATE TABLE statements + # --skip-triggers: Skip trigger definitions + # --no-create-db: Skip CREATE DATABASE statement + # --complete-insert: Include column names in INSERT (more reliable) + # --extended-insert: Use multi-row INSERT for efficiency + cmd = [ + 'mysqldump', + f"--host={self.config['host']}", + f"--port={self.config['port']}", + f"--user={self.config['user']}", + f"--password={self.config['password']}", + '--no-create-info', # Skip table structure + '--skip-triggers', # Skip triggers + '--no-create-db', # Skip database creation + '--complete-insert', # Include column names + '--extended-insert', # Multi-row INSERTs + '--single-transaction', + '--skip-lock-tables', + self.config['database'] + ] + + # Execute mysqldump and save to file + with open(backup_file, 'w') as f: + result = subprocess.run( + cmd, + stdout=f, + stderr=subprocess.PIPE, + text=True + ) + + if result.returncode == 0: + # Get file size + file_size = os.path.getsize(backup_file) + file_size_mb = file_size / (1024 * 1024) + + # Save backup metadata + self._save_backup_metadata(filename, file_size) + + return { + 'success': True, + 'message': f'Data-only backup created successfully', + 'filename': filename, + 'file_path': backup_file, + 'size': f"{file_size_mb:.2f} MB", + 'timestamp': timestamp + } + else: + error_msg = result.stderr + print(f"Data backup error: {error_msg}") + return { + 'success': False, + 'message': f'Data backup failed: {error_msg}' + } + + except Exception as e: + print(f"Exception during data backup: {e}") + return { + 'success': False, + 'message': f'Data backup failed: {str(e)}' + } + def restore_backup(self, filename): """ Restore database from a backup file @@ -345,6 +434,127 @@ class DatabaseBackupManager: 'message': f'Restore failed: {str(e)}' } + def restore_data_only(self, filename): + """ + Restore data from a data-only backup file + Assumes database schema already exists + Truncates tables before inserting data to avoid duplicates + + Args: + filename (str): Name of the data-only backup file to restore + + Returns: + dict: Result with success status and message + """ + try: + # Security: ensure filename doesn't contain path traversal + if '..' in filename or '/' in filename: + return { + 'success': False, + 'message': 'Invalid filename' + } + + file_path = os.path.join(self.backup_path, filename) + + if not os.path.exists(file_path): + return { + 'success': False, + 'message': 'Backup file not found' + } + + # First, disable foreign key checks and truncate all tables + # This ensures clean data import without constraint violations + try: + conn = mariadb.connect( + host=self.config['host'], + port=int(self.config['port']), + user=self.config['user'], + password=self.config['password'], + database=self.config['database'] + ) + cursor = conn.cursor() + + # Disable foreign key checks + cursor.execute("SET FOREIGN_KEY_CHECKS = 0;") + + # Get list of all tables in the database + cursor.execute("SHOW TABLES;") + tables = cursor.fetchall() + + # Truncate each table (except system tables) + for (table_name,) in tables: + # Skip metadata and system tables + if table_name not in ['backups_metadata', 'backup_schedule']: + try: + cursor.execute(f"TRUNCATE TABLE `{table_name}`;") + print(f"Truncated table: {table_name}") + except Exception as e: + print(f"Warning: Could not truncate {table_name}: {e}") + + conn.commit() + cursor.close() + conn.close() + + except Exception as e: + print(f"Warning during table truncation: {e}") + # Continue anyway - the restore might still work + + # Build mysql restore command for data + cmd = [ + 'mysql', + f"--host={self.config['host']}", + f"--port={self.config['port']}", + f"--user={self.config['user']}", + f"--password={self.config['password']}", + self.config['database'] + ] + + # Execute mysql restore + with open(file_path, 'r') as f: + result = subprocess.run( + cmd, + stdin=f, + stderr=subprocess.PIPE, + text=True + ) + + # Re-enable foreign key checks + try: + conn = mariadb.connect( + host=self.config['host'], + port=int(self.config['port']), + user=self.config['user'], + password=self.config['password'], + database=self.config['database'] + ) + cursor = conn.cursor() + cursor.execute("SET FOREIGN_KEY_CHECKS = 1;") + conn.commit() + cursor.close() + conn.close() + except Exception as e: + print(f"Warning: Could not re-enable foreign key checks: {e}") + + if result.returncode == 0: + return { + 'success': True, + 'message': f'Data restored successfully from {filename}' + } + else: + error_msg = result.stderr + print(f"Data restore error: {error_msg}") + return { + 'success': False, + 'message': f'Data restore failed: {error_msg}' + } + + except Exception as e: + print(f"Exception during data restore: {e}") + return { + 'success': False, + 'message': f'Data restore failed: {str(e)}' + } + def get_backup_schedule(self): """Get current backup schedule configuration""" try: @@ -352,13 +562,18 @@ class DatabaseBackupManager: if os.path.exists(schedule_file): with open(schedule_file, 'r') as f: - return json.load(f) + schedule = json.load(f) + # Ensure backup_type exists (for backward compatibility) + if 'backup_type' not in schedule: + schedule['backup_type'] = 'full' + return schedule # Default schedule return { 'enabled': False, 'time': '02:00', # 2 AM 'frequency': 'daily', # daily, weekly, monthly + 'backup_type': 'full', # full or data-only 'retention_days': 30 # Keep backups for 30 days } @@ -607,3 +822,112 @@ class DatabaseBackupManager: 'success': False, 'message': f'Cleanup failed: {str(e)}' } + + def upload_backup(self, uploaded_file): + """ + Upload and validate an external backup file + + Args: + uploaded_file: Werkzeug FileStorage object from request.files + + Returns: + dict: Result with success status, filename, and validation details + """ + try: + from werkzeug.utils import secure_filename + from pathlib import Path + + # Validate file extension + if not uploaded_file.filename.lower().endswith('.sql'): + return { + 'success': False, + 'message': 'Invalid file format. Only .sql files are allowed.' + } + + # Ensure backup_path is a Path object + backup_path = Path(self.backup_path) + backup_path.mkdir(parents=True, exist_ok=True) + + # Generate secure filename with timestamp to avoid conflicts + original_filename = secure_filename(uploaded_file.filename) + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + + # If filename already starts with "backup_", keep it; otherwise add prefix + if original_filename.startswith('backup_'): + new_filename = f"{original_filename.rsplit('.', 1)[0]}_{timestamp}.sql" + else: + new_filename = f"backup_uploaded_{timestamp}_{original_filename}" + + # Save file to backup directory + file_path = backup_path / new_filename + uploaded_file.save(str(file_path)) + + # Get file size + file_size = file_path.stat().st_size + size_mb = round(file_size / (1024 * 1024), 2) + + # Validate the uploaded file for integrity and compatibility + validation_result = self.validate_backup_file(new_filename) + + if not validation_result['success']: + # Validation failed - remove the uploaded file + file_path.unlink() # Delete the invalid file + return { + 'success': False, + 'message': f'Validation failed: {validation_result["message"]}', + 'validation_details': validation_result.get('details', {}), + 'warnings': validation_result.get('warnings', []) + } + + # Build response with validation details + response = { + 'success': True, + 'message': 'Backup file uploaded and validated successfully', + 'filename': new_filename, + 'size': f'{size_mb} MB', + 'path': str(file_path), + 'validation': { + 'status': 'passed', + 'message': validation_result['message'], + 'details': validation_result.get('details', {}), + 'warnings': validation_result.get('warnings', []) + } + } + + # Add warning flag if there are warnings + if validation_result.get('warnings'): + response['message'] = f'Backup uploaded with warnings: {"; ".join(validation_result["warnings"])}' + + # Save metadata + self._save_backup_metadata(new_filename, file_size) + + return response + + except Exception as e: + print(f"Error uploading backup: {e}") + return { + 'success': False, + 'message': f'Upload failed: {str(e)}' + } + + def get_backup_file_path(self, filename): + """ + Get the full path to a backup file (with security validation) + + Args: + filename (str): Name of the backup file + + Returns: + str or None: Full file path if valid, None if security check fails + """ + # Security: ensure filename doesn't contain path traversal + if '..' in filename or '/' in filename: + return None + + file_path = os.path.join(self.backup_path, filename) + + if os.path.exists(file_path): + return file_path + + return None + diff --git a/py_app/app/db_create_scripts/setup_complete_database.py b/py_app/app/db_create_scripts/setup_complete_database.py index 7063dc3..f3ca639 100755 --- a/py_app/app/db_create_scripts/setup_complete_database.py +++ b/py_app/app/db_create_scripts/setup_complete_database.py @@ -394,56 +394,76 @@ def create_database_triggers(): conn = mariadb.connect(**DB_CONFIG) cursor = conn.cursor() - # Drop existing triggers if they exist + # Drop existing triggers if they exist (old and new names) trigger_drops = [ "DROP TRIGGER IF EXISTS increment_approved_quantity;", "DROP TRIGGER IF EXISTS increment_rejected_quantity;", "DROP TRIGGER IF EXISTS increment_approved_quantity_fg;", - "DROP TRIGGER IF EXISTS increment_rejected_quantity_fg;" + "DROP TRIGGER IF EXISTS increment_rejected_quantity_fg;", + "DROP TRIGGER IF EXISTS set_quantities_scan1;", + "DROP TRIGGER IF EXISTS set_quantities_fg;" ] for drop_query in trigger_drops: cursor.execute(drop_query) - # Create trigger for scan1_orders approved quantity - scan1_approved_trigger = """ - CREATE TRIGGER increment_approved_quantity - AFTER INSERT ON scan1_orders + # Create trigger for scan1_orders - BEFORE INSERT to set quantities + scan1_trigger = """ + CREATE TRIGGER set_quantities_scan1 + BEFORE INSERT ON scan1_orders FOR EACH ROW BEGIN - IF NEW.quality_code = 000 THEN - UPDATE scan1_orders - SET approved_quantity = approved_quantity + 1 - WHERE CP_base_code = NEW.CP_base_code; + -- Count existing approved for this CP_base_code + SET @approved = (SELECT COUNT(*) FROM scan1_orders + WHERE CP_base_code = LEFT(NEW.CP_full_code, 10) + AND quality_code = 0); + + -- Count existing rejected for this CP_base_code + SET @rejected = (SELECT COUNT(*) FROM scan1_orders + WHERE CP_base_code = LEFT(NEW.CP_full_code, 10) + AND quality_code != 0); + + -- Add 1 to appropriate counter for this new row + IF NEW.quality_code = 0 THEN + SET NEW.approved_quantity = @approved + 1; + SET NEW.rejected_quantity = @rejected; ELSE - UPDATE scan1_orders - SET rejected_quantity = rejected_quantity + 1 - WHERE CP_base_code = NEW.CP_base_code; + SET NEW.approved_quantity = @approved; + SET NEW.rejected_quantity = @rejected + 1; END IF; END; """ - cursor.execute(scan1_approved_trigger) - print_success("Trigger 'increment_approved_quantity' created for scan1_orders") + cursor.execute(scan1_trigger) + print_success("Trigger 'set_quantities_scan1' created for scan1_orders") - # Create trigger for scanfg_orders approved quantity - scanfg_approved_trigger = """ - CREATE TRIGGER increment_approved_quantity_fg - AFTER INSERT ON scanfg_orders + # Create trigger for scanfg_orders - BEFORE INSERT to set quantities + scanfg_trigger = """ + CREATE TRIGGER set_quantities_fg + BEFORE INSERT ON scanfg_orders FOR EACH ROW BEGIN - IF NEW.quality_code = 000 THEN - UPDATE scanfg_orders - SET approved_quantity = approved_quantity + 1 - WHERE CP_base_code = NEW.CP_base_code; + -- Count existing approved for this CP_base_code + SET @approved = (SELECT COUNT(*) FROM scanfg_orders + WHERE CP_base_code = LEFT(NEW.CP_full_code, 10) + AND quality_code = 0); + + -- Count existing rejected for this CP_base_code + SET @rejected = (SELECT COUNT(*) FROM scanfg_orders + WHERE CP_base_code = LEFT(NEW.CP_full_code, 10) + AND quality_code != 0); + + -- Add 1 to appropriate counter for this new row + IF NEW.quality_code = 0 THEN + SET NEW.approved_quantity = @approved + 1; + SET NEW.rejected_quantity = @rejected; ELSE - UPDATE scanfg_orders - SET rejected_quantity = rejected_quantity + 1 - WHERE CP_base_code = NEW.CP_base_code; + SET NEW.approved_quantity = @approved; + SET NEW.rejected_quantity = @rejected + 1; END IF; END; """ - cursor.execute(scanfg_approved_trigger) - print_success("Trigger 'increment_approved_quantity_fg' created for scanfg_orders") + cursor.execute(scanfg_trigger) + print_success("Trigger 'set_quantities_fg' created for scanfg_orders") conn.commit() cursor.close() diff --git a/py_app/app/routes.py b/py_app/app/routes.py index 729c359..7a5c384 100755 --- a/py_app/app/routes.py +++ b/py_app/app/routes.py @@ -473,36 +473,25 @@ def scan(): conn = get_db_connection() cursor = conn.cursor() - # Always insert a new entry - each scan is a separate record + # Insert new entry - the BEFORE INSERT trigger 'set_quantities_scan1' will automatically + # calculate and set approved_quantity and rejected_quantity for this new record insert_query = """ INSERT INTO scan1_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time) VALUES (%s, %s, %s, %s, %s, %s, %s) """ cursor.execute(insert_query, (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time)) + conn.commit() - # Get the CP_base_code (first 10 characters of CP_full_code) + # Get the quantities from the newly inserted row for the flash message cp_base_code = cp_code[:10] - - # Count approved quantities (quality_code = 0) for this CP_base_code cursor.execute(""" - SELECT COUNT(*) FROM scan1_orders - WHERE CP_base_code = %s AND quality_code = 0 - """, (cp_base_code,)) - approved_count = cursor.fetchone()[0] - - # Count rejected quantities (quality_code != 0) for this CP_base_code - cursor.execute(""" - SELECT COUNT(*) FROM scan1_orders - WHERE CP_base_code = %s AND quality_code != 0 - """, (cp_base_code,)) - rejected_count = cursor.fetchone()[0] - - # Update all records with the same CP_base_code with new quantities - cursor.execute(""" - UPDATE scan1_orders - SET approved_quantity = %s, rejected_quantity = %s - WHERE CP_base_code = %s - """, (approved_count, rejected_count, cp_base_code)) + SELECT approved_quantity, rejected_quantity + FROM scan1_orders + WHERE CP_full_code = %s + """, (cp_code,)) + result = cursor.fetchone() + approved_count = result[0] if result else 0 + rejected_count = result[1] if result else 0 # Flash appropriate message if int(defect_code) == 0: @@ -510,8 +499,6 @@ def scan(): else: flash(f'❌ REJECTED scan recorded for {cp_code} (defect: {defect_code}). Total rejected: {rejected_count}') - # Commit the transaction - conn.commit() conn.close() except mariadb.Error as e: @@ -566,35 +553,25 @@ def fg_scan(): cursor = conn.cursor() # Always insert a new entry - each scan is a separate record + # Note: The trigger 'increment_approved_quantity_fg' will automatically + # update approved_quantity or rejected_quantity for all records with same CP_base_code insert_query = """ INSERT INTO scanfg_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time) VALUES (%s, %s, %s, %s, %s, %s, %s) """ cursor.execute(insert_query, (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time)) + conn.commit() - # Get the CP_base_code (first 10 characters of CP_full_code) + # Get the quantities from the newly inserted row for the flash message cp_base_code = cp_code[:10] - - # Count approved quantities (quality_code = 0) for this CP_base_code cursor.execute(""" - SELECT COUNT(*) FROM scanfg_orders - WHERE CP_base_code = %s AND quality_code = 0 - """, (cp_base_code,)) - approved_count = cursor.fetchone()[0] - - # Count rejected quantities (quality_code != 0) for this CP_base_code - cursor.execute(""" - SELECT COUNT(*) FROM scanfg_orders - WHERE CP_base_code = %s AND quality_code != 0 - """, (cp_base_code,)) - rejected_count = cursor.fetchone()[0] - - # Update all records with the same CP_base_code with new quantities - cursor.execute(""" - UPDATE scanfg_orders - SET approved_quantity = %s, rejected_quantity = %s - WHERE CP_base_code = %s - """, (approved_count, rejected_count, cp_base_code)) + SELECT approved_quantity, rejected_quantity + FROM scanfg_orders + WHERE CP_full_code = %s + """, (cp_code,)) + result = cursor.fetchone() + approved_count = result[0] if result else 0 + rejected_count = result[1] if result else 0 # Flash appropriate message if int(defect_code) == 0: @@ -602,8 +579,6 @@ def fg_scan(): else: flash(f'❌ REJECTED scan recorded for {cp_code} (defect: {defect_code}). Total rejected: {rejected_count}') - # Commit the transaction - conn.commit() conn.close() except mariadb.Error as e: @@ -3628,25 +3603,16 @@ def api_backup_download(filename): try: from app.database_backup import DatabaseBackupManager from flask import send_file - import os backup_manager = DatabaseBackupManager() - backup_path = backup_manager.backup_path - file_path = os.path.join(backup_path, filename) + file_path = backup_manager.get_backup_file_path(filename) - # Security: ensure filename doesn't contain path traversal - if '..' in filename or '/' in filename: - return jsonify({ - 'success': False, - 'message': 'Invalid filename' - }), 400 - - if os.path.exists(file_path): + if file_path: return send_file(file_path, as_attachment=True, download_name=filename) else: return jsonify({ 'success': False, - 'message': 'Backup file not found' + 'message': 'Backup file not found or invalid filename' }), 404 except Exception as e: return jsonify({ @@ -3677,18 +3643,56 @@ def api_backup_schedule(): """Get or save backup schedule configuration""" try: from app.database_backup import DatabaseBackupManager + from app.backup_scheduler import get_backup_scheduler backup_manager = DatabaseBackupManager() if request.method == 'POST': schedule = request.json result = backup_manager.save_backup_schedule(schedule) + + if result['success']: + # Reload the scheduler to apply new configuration + scheduler = get_backup_scheduler() + if scheduler: + scheduler.update_schedule() + info = scheduler.get_schedule_info() + + if info and info.get('jobs'): + jobs = info['jobs'] + result['message'] += f'. {len(jobs)} active schedule(s)' + return jsonify(result) else: schedule = backup_manager.get_backup_schedule() + + # Auto-migrate legacy format to multi-schedule format + if 'schedules' not in schedule: + schedule = { + 'schedules': [{ + 'id': 'default', + 'name': 'Default Schedule', + 'enabled': schedule.get('enabled', True), + 'time': schedule.get('time', '02:00'), + 'frequency': schedule.get('frequency', 'daily'), + 'backup_type': schedule.get('backup_type', 'full'), + 'retention_days': schedule.get('retention_days', 30) + }] + } + # Save migrated format + backup_manager.save_backup_schedule(schedule) + + # Get scheduler info with all jobs + scheduler = get_backup_scheduler() + jobs = [] + if scheduler: + info = scheduler.get_schedule_info() + jobs = info.get('jobs', []) if info else [] + return jsonify({ 'success': True, - 'schedule': schedule + 'schedule': schedule, + 'jobs': jobs }) except Exception as e: return jsonify({ @@ -3718,9 +3722,6 @@ def api_backup_upload(): """Upload an external backup file (superadmin only)""" try: from app.database_backup import DatabaseBackupManager - from werkzeug.utils import secure_filename - import os - from datetime import datetime # Check if file was uploaded if 'backup_file' not in request.files: @@ -3738,79 +3739,302 @@ def api_backup_upload(): 'message': 'No file selected' }), 400 - # Validate file extension - if not file.filename.lower().endswith('.sql'): - return jsonify({ - 'success': False, - 'message': 'Invalid file format. Only .sql files are allowed.' - }), 400 - - # Get backup manager and backup path + # Use DatabaseBackupManager to handle upload backup_manager = DatabaseBackupManager() - backup_path = backup_manager.backup_path + result = backup_manager.upload_backup(file) - # Ensure backup_path is a Path object - from pathlib import Path - if not isinstance(backup_path, Path): - backup_path = Path(backup_path) - - # Create backup directory if it doesn't exist - backup_path.mkdir(parents=True, exist_ok=True) - - # Generate secure filename with timestamp to avoid conflicts - original_filename = secure_filename(file.filename) - timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') - - # If filename already starts with "backup_", keep it; otherwise add prefix - if original_filename.startswith('backup_'): - new_filename = f"{original_filename.rsplit('.', 1)[0]}_{timestamp}.sql" - else: - new_filename = f"backup_uploaded_{timestamp}_{original_filename}" - - # Save file to backup directory - file_path = backup_path / new_filename - file.save(str(file_path)) - - # Get file size - file_size = file_path.stat().st_size - size_mb = round(file_size / (1024 * 1024), 2) - - # Validate the uploaded file for integrity and compatibility - validation_result = backup_manager.validate_backup_file(new_filename) - - if not validation_result['success']: - # Validation failed - remove the uploaded file - file_path.unlink() # Delete the invalid file - return jsonify({ - 'success': False, - 'message': f'Validation failed: {validation_result["message"]}', - 'validation_details': validation_result.get('details', {}), - 'warnings': validation_result.get('warnings', []) - }), 400 - - # Build response with validation details - response = { - 'success': True, - 'message': 'Backup file uploaded and validated successfully', - 'filename': new_filename, - 'size': f'{size_mb} MB', - 'path': str(file_path), - 'validation': { - 'status': 'passed', - 'message': validation_result['message'], - 'details': validation_result.get('details', {}), - 'warnings': validation_result.get('warnings', []) - } - } - - # Add warning flag if there are warnings - if validation_result.get('warnings'): - response['message'] = f'Backup uploaded with warnings: {"; ".join(validation_result["warnings"])}' - - return jsonify(response) + # Return appropriate status code + status_code = 200 if result['success'] else 400 + return jsonify(result), status_code except Exception as e: return jsonify({ 'success': False, 'message': f'Upload failed: {str(e)}' }), 500 + +@bp.route('/api/backup/create-data-only', methods=['POST']) +@admin_plus +def api_backup_create_data_only(): + """Create a data-only backup (no schema, triggers, or structure)""" + try: + from app.database_backup import DatabaseBackupManager + + backup_manager = DatabaseBackupManager() + result = backup_manager.create_data_only_backup() + + return jsonify(result) + except Exception as e: + return jsonify({ + 'success': False, + 'message': f'Data backup failed: {str(e)}' + }), 500 + +@bp.route('/api/backup/restore-data-only/', methods=['POST']) +@superadmin_only +def api_backup_restore_data_only(filename): + """Restore data from a data-only backup file (superadmin only) + Assumes database schema already exists + """ + try: + from app.database_backup import DatabaseBackupManager + + backup_manager = DatabaseBackupManager() + result = backup_manager.restore_data_only(filename) + + return jsonify(result) + except Exception as e: + return jsonify({ + 'success': False, + 'message': f'Data restore failed: {str(e)}' + }), 500 + +@bp.route('/api/backup/schedule-info', methods=['GET']) +@admin_plus +def api_backup_schedule_info(): + """Get detailed backup schedule information including next run time""" + try: + from app.backup_scheduler import get_backup_scheduler + + scheduler = get_backup_scheduler() + if not scheduler: + return jsonify({ + 'success': False, + 'message': 'Backup scheduler not initialized' + }), 500 + + info = scheduler.get_schedule_info() + + return jsonify({ + 'success': True, + 'info': info + }) + except Exception as e: + return jsonify({ + 'success': False, + 'message': f'Failed to get schedule info: {str(e)}' + }), 500 + +@bp.route('/api/backup/reload-schedule', methods=['POST']) +@admin_plus +def api_backup_reload_schedule(): + """Reload the backup schedule after configuration changes""" + try: + from app.backup_scheduler import get_backup_scheduler + + scheduler = get_backup_scheduler() + if not scheduler: + return jsonify({ + 'success': False, + 'message': 'Backup scheduler not initialized' + }), 500 + + scheduler.update_schedule() + + info = scheduler.get_schedule_info() + next_run = info['next_run_time'] if info else None + + message = 'Backup schedule reloaded successfully' + if next_run: + message += f'. Next backup: {next_run}' + + return jsonify({ + 'success': True, + 'message': message, + 'next_run_time': next_run + }) + except Exception as e: + return jsonify({ + 'success': False, + 'message': f'Failed to reload schedule: {str(e)}' + }), 500 + +@bp.route('/api/backup/schedule/toggle/', methods=['POST']) +@admin_plus +def api_backup_schedule_toggle(schedule_id): + """Toggle a specific schedule on/off""" + try: + from app.database_backup import DatabaseBackupManager + from app.backup_scheduler import get_backup_scheduler + + backup_manager = DatabaseBackupManager() + schedule_config = backup_manager.get_backup_schedule() + + # Handle new multi-schedule format + if isinstance(schedule_config, dict) and 'schedules' in schedule_config: + schedules = schedule_config['schedules'] + + # Find and toggle the schedule + schedule_found = False + for schedule in schedules: + if schedule.get('id') == schedule_id: + schedule['enabled'] = not schedule.get('enabled', False) + schedule_found = True + break + + if not schedule_found: + return jsonify({ + 'success': False, + 'message': f'Schedule {schedule_id} not found' + }), 404 + + # Save updated configuration + result = backup_manager.save_backup_schedule(schedule_config) + + if result['success']: + # Reload scheduler + scheduler = get_backup_scheduler() + if scheduler: + scheduler.update_schedule() + + enabled_count = sum(1 for s in schedules if s.get('enabled', False)) + result['message'] = f'Schedule {schedule_id} toggled successfully. {enabled_count} schedule(s) active.' + + return jsonify(result) + + # Handle legacy single schedule format + else: + schedule_config['enabled'] = not schedule_config.get('enabled', False) + result = backup_manager.save_backup_schedule(schedule_config) + + if result['success']: + scheduler = get_backup_scheduler() + if scheduler: + scheduler.update_schedule() + + return jsonify(result) + + except Exception as e: + return jsonify({ + 'success': False, + 'message': f'Failed to toggle schedule: {str(e)}' + }), 500 + +@bp.route('/api/backup/schedule/delete/', methods=['DELETE']) +@admin_plus +def api_backup_schedule_delete(schedule_id): + """Delete a specific schedule""" + try: + from app.database_backup import DatabaseBackupManager + from app.backup_scheduler import get_backup_scheduler + + # Don't allow deleting the default schedule + if schedule_id == 'default': + return jsonify({ + 'success': False, + 'message': 'Cannot delete the default schedule' + }), 400 + + backup_manager = DatabaseBackupManager() + schedule_config = backup_manager.get_backup_schedule() + + if isinstance(schedule_config, dict) and 'schedules' in schedule_config: + schedules = schedule_config['schedules'] + + # Remove the schedule + new_schedules = [s for s in schedules if s.get('id') != schedule_id] + + if len(new_schedules) == len(schedules): + return jsonify({ + 'success': False, + 'message': f'Schedule {schedule_id} not found' + }), 404 + + schedule_config['schedules'] = new_schedules + result = backup_manager.save_backup_schedule(schedule_config) + + if result['success']: + # Reload scheduler + scheduler = get_backup_scheduler() + if scheduler: + scheduler.update_schedule() + + result['message'] = f'Schedule {schedule_id} deleted successfully' + + return jsonify(result) + else: + return jsonify({ + 'success': False, + 'message': 'Multi-schedule format not enabled' + }), 400 + + except Exception as e: + return jsonify({ + 'success': False, + 'message': f'Failed to delete schedule: {str(e)}' + }), 500 + +@bp.route('/api/backup/schedule/add', methods=['POST']) +@admin_plus +def api_backup_schedule_add(): + """Add a new schedule""" + try: + from app.database_backup import DatabaseBackupManager + from app.backup_scheduler import get_backup_scheduler + import uuid + + new_schedule = request.json + + # Validate required fields + required_fields = ['time', 'frequency', 'backup_type', 'retention_days'] + for field in required_fields: + if field not in new_schedule: + return jsonify({ + 'success': False, + 'message': f'Missing required field: {field}' + }), 400 + + backup_manager = DatabaseBackupManager() + schedule_config = backup_manager.get_backup_schedule() + + # Migrate to multi-schedule format if needed + if 'schedules' not in schedule_config: + # Convert legacy format to multi-schedule + schedule_config = { + 'schedules': [{ + 'id': 'default', + 'name': 'Default Schedule', + 'enabled': schedule_config.get('enabled', True), + 'time': schedule_config.get('time', '02:00'), + 'frequency': schedule_config.get('frequency', 'daily'), + 'backup_type': schedule_config.get('backup_type', 'full'), + 'retention_days': schedule_config.get('retention_days', 30) + }] + } + + # Generate unique ID + schedule_id = new_schedule.get('id') or str(uuid.uuid4())[:8] + + # Add new schedule + new_schedule_entry = { + 'id': schedule_id, + 'name': new_schedule.get('name', f'Schedule {schedule_id}'), + 'enabled': new_schedule.get('enabled', True), + 'time': new_schedule['time'], + 'frequency': new_schedule['frequency'], + 'backup_type': new_schedule['backup_type'], + 'retention_days': int(new_schedule['retention_days']) + } + + schedule_config['schedules'].append(new_schedule_entry) + + # Save configuration + result = backup_manager.save_backup_schedule(schedule_config) + + if result['success']: + # Reload scheduler + scheduler = get_backup_scheduler() + if scheduler: + scheduler.update_schedule() + + result['message'] = f'Schedule {schedule_id} added successfully' + result['schedule_id'] = schedule_id + + return jsonify(result) + + except Exception as e: + return jsonify({ + 'success': False, + 'message': f'Failed to add schedule: {str(e)}' + }), 500 + diff --git a/py_app/app/templates/settings.html b/py_app/app/templates/settings.html index db4d1cc..879386d 100755 --- a/py_app/app/templates/settings.html +++ b/py_app/app/templates/settings.html @@ -55,292 +55,1103 @@

💾 Database Backup Management

Automated Backup System: Schedule and manage database backups

+ {% if session.role in ['superadmin', 'admin'] %} +
+

+ 💾 Database Backup Management + Active +

- -
-

Quick Actions

- - -
- - -
-

Backup Schedule

-
-
- + +
+ + +
+
+

⚡ Quick Actions

-
- - -
-
- - -
-
- - -
-
- + +
- +
+ + +
+
+

⏰ Automatic Schedules

+
+ 0 + +
+
+
+ +
+ + + +
+
+
- -
-

Available Backups

-
-

Loading backups...

+ +
+
+

📂 Available Backups

+ 0 +
+
+
+
+
+

Loading backups...

+
+
- -
- ℹ️ Backup Location: /srv/quality_app/backups -
- Configure backup path in docker-compose.yml (BACKUP_PATH environment variable) -
- - + {% if current_user.role == 'superadmin' %} -
-

⚠️ Restore Database

-

- WARNING: Restoring will permanently replace ALL current data with the backup data. This action cannot be undone! -

- - -
-
📤 Upload External Backup File
-

- Upload a backup file from another server or external source. File will be saved to the backups directory. -

-
- - +
+ SQL files only • Max 10GB +
+ + +
+
+ + +
+ +
+ +
+ + +
+
+ +
- - Accepted format: .sql files only | Max size: 100MB -
- - -
- - -
-
{% endif %} + + +
+ 💾 Backup Location: /srv/quality_app/backups + Configure in docker(BACKUP_PATH) +
+ {% endif %} +
+ padding: 20px; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); } {% endif %} @@ -435,19 +1246,107 @@ document.getElementById('close-delete-popup-btn').onclick = function() { // Database Backup Management Functions // ======================================== -// Load backup schedule on page load +// Load backup schedules on page load function loadBackupSchedule() { fetch('/api/backup/schedule') .then(response => response.json()) .then(data => { if (data.success) { - document.getElementById('schedule-enabled').checked = data.schedule.enabled; - document.getElementById('schedule-time').value = data.schedule.time; - document.getElementById('schedule-frequency').value = data.schedule.frequency; - document.getElementById('retention-days').value = data.schedule.retention_days; + const scheduleConfig = data.schedule; + const jobs = data.jobs || []; + const schedules = scheduleConfig.schedules || []; + + // Update count badge + const enabledCount = schedules.filter(s => s.enabled).length; + document.getElementById('schedule-count-badge').textContent = enabledCount; + + // Render schedules list + const schedulesList = document.getElementById('schedules-list'); + + if (schedules.length === 0) { + schedulesList.innerHTML = ` +
+
+

No schedules configured

+ Click "Add Schedule" to create automatic backups +
+ `; + return; + } + + let html = ''; + schedules.forEach(schedule => { + const job = jobs.find(j => j.id === schedule.id); + const nextRun = job ? job.next_run_time : null; + const isEnabled = schedule.enabled; + const disabledClass = isEnabled ? '' : 'disabled'; + + // Format frequency + const freqMap = { + 'daily': 'Daily', + 'weekly': 'Weekly (Sun)', + 'monthly': 'Monthly (1st)' + }; + const freqDisplay = freqMap[schedule.frequency] || schedule.frequency; + + // Format backup type + const typeDisplay = schedule.backup_type === 'data-only' ? '📦 Data-Only' : '🗄️ Full'; + + html += ` +
+
+
+ ${isEnabled ? '✅' : '⏸️'} + ${schedule.name || schedule.id} +
+
+ + + ${schedule.id !== 'default' ? ` + + ` : ''} +
+
+
+
+ ${schedule.time} +
+
+ 📅 ${freqDisplay} +
+
+ 💾 ${typeDisplay} +
+
+ 🗓️ Keep ${schedule.retention_days}d +
+
+ ${nextRun && isEnabled ? ` +
+ Next Backup: + ${nextRun} +
+ ` : ''} +
+ `; + }); + + schedulesList.innerHTML = html; } }) - .catch(error => console.error('Error loading schedule:', error)); + .catch(error => console.error('Error loading schedules:', error)); } // Load backup list @@ -455,41 +1354,64 @@ function loadBackupList() { const backupList = document.getElementById('backup-list'); if (!backupList) return; - backupList.innerHTML = '

Loading backups...

'; + backupList.innerHTML = ` +
+
+

Loading backups...

+
+ `; fetch('/api/backup/list') .then(response => response.json()) .then(data => { if (data.success && data.backups.length > 0) { - let html = ''; - html += ''; - html += ''; + // Update count badge + document.getElementById('backup-count-badge').textContent = data.backups.length; + let html = ''; data.backups.forEach(backup => { - html += ` - - - - - `; + html += ` +
+
+
📄 ${backup.filename}
+
+ 💾 ${backup.size_mb} MB • 📅 ${backup.created} +
+
+
+ + +
+
+ `; }); - html += '
FilenameSizeCreatedActions
${backup.filename}${backup.size_mb} MB${backup.created} - - -
'; backupList.innerHTML = html; // Populate restore dropdown const restoreSelect = document.getElementById('restore-backup-select'); if (restoreSelect) { - restoreSelect.innerHTML = ''; + restoreSelect.innerHTML = ''; data.backups.forEach(backup => { restoreSelect.innerHTML += ``; }); } } else { - backupList.innerHTML = '

No backups available

'; + // Update count badge + document.getElementById('backup-count-badge').textContent = '0'; + + backupList.innerHTML = ` +
+
📂
+

No backups available

+ Create your first backup using the buttons above +
+ `; + // Clear restore dropdown const restoreSelect = document.getElementById('restore-backup-select'); if (restoreSelect) { @@ -499,15 +1421,28 @@ function loadBackupList() { }) .catch(error => { console.error('Error loading backups:', error); - backupList.innerHTML = '

Error loading backups

'; + backupList.innerHTML = ` +
+
⚠️
+

Error loading backups

+ Please try refreshing the page +
+ `; }); } // Backup now button document.getElementById('backup-now-btn')?.addEventListener('click', function() { const btn = this; + const originalHTML = btn.innerHTML; btn.disabled = true; - btn.innerHTML = '⏳ Creating backup...'; + btn.innerHTML = ` + + + Creating... + Please wait + + `; fetch('/api/backup/create', { method: 'POST' @@ -515,19 +1450,54 @@ document.getElementById('backup-now-btn')?.addEventListener('click', function() .then(response => response.json()) .then(data => { if (data.success) { - alert('✅ ' + data.message + '\nFile: ' + data.filename + '\nSize: ' + data.size); + alert('✅ ' + data.message + '\n\nFile: ' + data.filename + '\nSize: ' + data.size); loadBackupList(); } else { alert('❌ ' + data.message); } btn.disabled = false; - btn.innerHTML = '⚡ Backup Now'; + btn.innerHTML = originalHTML; }) .catch(error => { console.error('Error creating backup:', error); alert('❌ Failed to create backup'); btn.disabled = false; - btn.innerHTML = '⚡ Backup Now'; + btn.innerHTML = originalHTML; + }); +}); + +// Data-only backup button +document.getElementById('backup-data-only-btn')?.addEventListener('click', function() { + const btn = this; + const originalHTML = btn.innerHTML; + btn.disabled = true; + btn.innerHTML = ` + + + Creating... + Please wait + + `; + + fetch('/api/backup/create-data-only', { + method: 'POST' + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + alert('✅ ' + data.message + '\n\nFile: ' + data.filename + '\nSize: ' + data.size + '\n\n📦 This backup contains only data (no schema or triggers)'); + loadBackupList(); + } else { + alert('❌ ' + data.message); + } + btn.disabled = false; + btn.innerHTML = originalHTML; + }) + .catch(error => { + console.error('Error creating data backup:', error); + alert('❌ Failed to create data backup'); + btn.disabled = false; + btn.innerHTML = originalHTML; }); }); @@ -536,36 +1506,186 @@ document.getElementById('refresh-backups-btn')?.addEventListener('click', functi loadBackupList(); }); -// Save schedule form -document.getElementById('backup-schedule-form')?.addEventListener('submit', function(e) { - e.preventDefault(); +// Add schedule button - show form +document.getElementById('add-schedule-btn')?.addEventListener('click', function() { + // Clear form + document.getElementById('schedule-id').value = ''; + document.getElementById('schedule-name').value = ''; + document.getElementById('schedule-enabled').checked = true; + document.getElementById('schedule-time').value = '02:00'; + document.getElementById('schedule-frequency').value = 'daily'; + document.getElementById('schedule-backup-type').value = 'full'; + document.getElementById('retention-days').value = '30'; - const formData = { - enabled: document.getElementById('schedule-enabled').checked, - time: document.getElementById('schedule-time').value, - frequency: document.getElementById('schedule-frequency').value, - retention_days: parseInt(document.getElementById('retention-days').value) - }; + // Hide schedules list, show form + document.getElementById('schedules-list').style.display = 'none'; + document.getElementById('backup-schedule-form').style.display = 'block'; +}); + +// Edit schedule function +function editSchedule(scheduleId) { + fetch('/api/backup/schedule') + .then(response => response.json()) + .then(data => { + if (data.success) { + const schedule = data.schedule.schedules.find(s => s.id === scheduleId); + if (schedule) { + // Populate form + document.getElementById('schedule-id').value = schedule.id; + document.getElementById('schedule-name').value = schedule.name || schedule.id; + document.getElementById('schedule-enabled').checked = schedule.enabled; + document.getElementById('schedule-time').value = schedule.time; + document.getElementById('schedule-frequency').value = schedule.frequency; + document.getElementById('schedule-backup-type').value = schedule.backup_type; + document.getElementById('retention-days').value = schedule.retention_days; + + // Hide schedules list, show form + document.getElementById('schedules-list').style.display = 'none'; + document.getElementById('backup-schedule-form').style.display = 'block'; + } + } + }) + .catch(error => console.error('Error loading schedule:', error)); +} + +// Toggle schedule function +function toggleSchedule(scheduleId) { + if (!confirm(`Are you sure you want to toggle this schedule ${scheduleId}?`)) { + return; + } - fetch('/api/backup/schedule', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(formData) + fetch(`/api/backup/schedule/toggle/${scheduleId}`, { + method: 'POST' }) .then(response => response.json()) .then(data => { if (data.success) { alert('✅ ' + data.message); + loadBackupSchedule(); } else { alert('❌ ' + data.message); } }) .catch(error => { - console.error('Error saving schedule:', error); - alert('❌ Failed to save schedule'); + console.error('Error toggling schedule:', error); + alert('❌ Failed to toggle schedule'); }); +} + +// Delete schedule function +function deleteSchedule(scheduleId) { + if (!confirm(`Are you sure you want to delete schedule "${scheduleId}"?\n\nThis action cannot be undone.`)) { + return; + } + + fetch(`/api/backup/schedule/delete/${scheduleId}`, { + method: 'DELETE' + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + alert('✅ ' + data.message); + loadBackupSchedule(); + } else { + alert('❌ ' + data.message); + } + }) + .catch(error => { + console.error('Error deleting schedule:', error); + alert('❌ Failed to delete schedule'); + }); +} + +// Cancel schedule button - hide form +document.getElementById('cancel-schedule-btn')?.addEventListener('click', function() { + document.getElementById('backup-schedule-form').style.display = 'none'; + document.getElementById('schedules-list').style.display = 'block'; +}); + +// Save schedule form +document.getElementById('backup-schedule-form')?.addEventListener('submit', function(e) { + e.preventDefault(); + + const scheduleId = document.getElementById('schedule-id').value; + const isEdit = scheduleId !== ''; + + const formData = { + id: scheduleId || undefined, + name: document.getElementById('schedule-name').value, + enabled: document.getElementById('schedule-enabled').checked, + time: document.getElementById('schedule-time').value, + frequency: document.getElementById('schedule-frequency').value, + backup_type: document.getElementById('schedule-backup-type').value, + retention_days: parseInt(document.getElementById('retention-days').value) + }; + + // Build informative success message + const backupTypeText = formData.backup_type === 'data-only' ? 'Data-Only' : 'Full'; + const freqText = formData.frequency.charAt(0).toUpperCase() + formData.frequency.slice(1); + const scheduleInfo = `${backupTypeText} backups ${freqText} at ${formData.time}`; + + const endpoint = isEdit ? '/api/backup/schedule' : '/api/backup/schedule/add'; + const method = 'POST'; + + // For edit, we need to update the entire schedule config + if (isEdit) { + // Load current config and update the specific schedule + fetch('/api/backup/schedule') + .then(response => response.json()) + .then(data => { + if (data.success) { + const config = data.schedule; + const scheduleIndex = config.schedules.findIndex(s => s.id === scheduleId); + + if (scheduleIndex >= 0) { + config.schedules[scheduleIndex] = formData; + } + + return fetch('/api/backup/schedule', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(config) + }); + } + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + alert(`✅ Schedule updated successfully!\n\n${scheduleInfo}`); + document.getElementById('backup-schedule-form').style.display = 'none'; + document.getElementById('schedules-list').style.display = 'block'; + loadBackupSchedule(); + } else { + alert('❌ ' + data.message); + } + }) + .catch(error => { + console.error('Error saving schedule:', error); + alert('❌ Failed to save schedule'); + }); + } else { + // Add new schedule + fetch(endpoint, { + method: method, + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(formData) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + alert(`✅ Schedule added successfully!\n\n${scheduleInfo}`); + document.getElementById('backup-schedule-form').style.display = 'none'; + document.getElementById('schedules-list').style.display = 'block'; + loadBackupSchedule(); + } else { + alert('❌ ' + data.message); + } + }) + .catch(error => { + console.error('Error saving schedule:', error); + alert('❌ Failed to save schedule'); + }); + } }); // Download backup function @@ -608,36 +1728,73 @@ document.getElementById('restore-backup-select')?.addEventListener('change', fun // Restore backup function document.getElementById('restore-btn')?.addEventListener('click', function() { const filename = document.getElementById('restore-backup-select').value; + const restoreType = document.querySelector('input[name="restore-type"]:checked').value; if (!filename) { alert('❌ Please select a backup file to restore'); return; } + // Check if it's a data-only backup being restored as full + const isDataOnlyFile = filename.includes('data_only_'); + + if (restoreType === 'full' && isDataOnlyFile) { + alert('⚠️ Warning: You selected a data-only backup file but chose "Full Restore".\n\n' + + 'Data-only backups do not contain database schema or triggers.\n' + + 'Please select "Data-Only Restore" instead, or choose a full backup file.'); + return; + } + + // Prepare warning message based on restore type + let warningMessage, confirmMessage; + + if (restoreType === 'data-only') { + warningMessage = `⚠️ DATA-ONLY RESTORE WARNING ⚠️\n\n` + + `You are about to RESTORE ONLY THE DATA from:\n${filename}\n\n` + + `This will:\n` + + `• TRUNCATE all tables (delete all current data)\n` + + `• INSERT data from backup\n` + + `• KEEP existing database schema and triggers\n\n` + + `This action CANNOT be undone!\n\n` + + `Do you want to continue?`; + + confirmMessage = `⚠️ FINAL CONFIRMATION ⚠️\n\n` + + `Type "RESTORE DATA" in capital letters to confirm you understand:\n` + + `• All current data will be PERMANENTLY DELETED\n` + + `• Database structure will remain unchanged\n` + + `• This action is IRREVERSIBLE\n\n` + + `Type RESTORE DATA to continue:`; + } else { + warningMessage = `⚠️ FULL RESTORE WARNING ⚠️\n\n` + + `You are about to RESTORE the entire database from:\n${filename}\n\n` + + `This will PERMANENTLY DELETE:\n` + + `• All current data\n` + + `• Database schema\n` + + `• All triggers\n\n` + + `And replace them with the backup content.\n\n` + + `This action CANNOT be undone!\n\n` + + `Do you want to continue?`; + + confirmMessage = `⚠️ FINAL CONFIRMATION ⚠️\n\n` + + `Type "RESTORE" in capital letters to confirm you understand:\n` + + `• All current database data will be PERMANENTLY DELETED\n` + + `• This action is IRREVERSIBLE\n` + + `• Users may experience downtime during restore\n\n` + + `Type RESTORE to continue:`; + } + // First confirmation - const firstConfirm = confirm( - `⚠️ CRITICAL WARNING ⚠️\n\n` + - `You are about to RESTORE the database from:\n${filename}\n\n` + - `This will PERMANENTLY DELETE all current data and replace it with the backup data.\n\n` + - `This action CANNOT be undone!\n\n` + - `Do you want to continue?` - ); + const firstConfirm = confirm(warningMessage); if (!firstConfirm) { return; } // Second confirmation (require typing confirmation) - const secondConfirm = prompt( - `⚠️ FINAL CONFIRMATION ⚠️\n\n` + - `Type "RESTORE" in capital letters to confirm you understand:\n` + - `• All current database data will be PERMANENTLY DELETED\n` + - `• This action is IRREVERSIBLE\n` + - `• Users may experience downtime during restore\n\n` + - `Type RESTORE to continue:` - ); + const expectedText = restoreType === 'data-only' ? 'RESTORE DATA' : 'RESTORE'; + const secondConfirm = prompt(confirmMessage); - if (secondConfirm !== 'RESTORE') { + if (secondConfirm !== expectedText) { alert('❌ Restore cancelled - confirmation text did not match'); return; } @@ -645,30 +1802,43 @@ document.getElementById('restore-btn')?.addEventListener('click', function() { // Perform restore const btn = this; btn.disabled = true; - btn.innerHTML = '⏳ Restoring database... Please wait...'; - fetch(`/api/backup/restore/${filename}`, { + const restoreEndpoint = restoreType === 'data-only' + ? `/api/backup/restore-data-only/${filename}` + : `/api/backup/restore/${filename}`; + + const restoreTypeText = restoreType === 'data-only' ? 'data' : 'database'; + btn.innerHTML = `⏳ Restoring ${restoreTypeText}... Please wait...`; + + fetch(restoreEndpoint, { method: 'POST' }) .then(response => response.json()) .then(data => { if (data.success) { - alert( - `✅ DATABASE RESTORE COMPLETE!\n\n` + - `${data.message}\n\n` + - `The application will now reload to apply changes.` - ); + const successMsg = restoreType === 'data-only' + ? `✅ DATA RESTORE COMPLETE!\n\n${data.message}\n\n` + + `Data has been refreshed. Database schema and triggers remain unchanged.\n\n` + + `The application will now reload to apply changes.` + : `✅ DATABASE RESTORE COMPLETE!\n\n${data.message}\n\n` + + `The application will now reload to apply changes.`; + + alert(successMsg); // Reload the page to ensure all data is fresh window.location.reload(); } else { - alert(`❌ RESTORE FAILED\n\n${data.message}`); + const errorMsg = restoreType === 'data-only' + ? `❌ DATA RESTORE FAILED\n\n${data.message}` + : `❌ RESTORE FAILED\n\n${data.message}`; + + alert(errorMsg); btn.disabled = false; btn.innerHTML = '🔄 Restore Database from Selected Backup'; } }) .catch(error => { console.error('Error restoring backup:', error); - alert(`❌ RESTORE FAILED\n\nAn error occurred while restoring the database.`); + alert(`❌ RESTORE FAILED\n\nAn error occurred while restoring the ${restoreTypeText}.`); btn.disabled = false; btn.innerHTML = '🔄 Restore Database from Selected Backup'; }); diff --git a/py_app/requirements.txt b/py_app/requirements.txt index 1e2dc61..e27d0cb 100755 --- a/py_app/requirements.txt +++ b/py_app/requirements.txt @@ -7,4 +7,5 @@ mariadb reportlab requests pandas -openpyxl \ No newline at end of file +openpyxl +APScheduler \ No newline at end of file diff --git a/run/trasabilitate.pid b/run/trasabilitate.pid index bf438eb..7ce7073 100644 --- a/run/trasabilitate.pid +++ b/run/trasabilitate.pid @@ -1 +1 @@ -402172 +417124