Files
quality_app/DATABASE_DOCKER_SETUP.md
Quality System Admin 8d47e6e82d updated structure and app
2025-11-03 19:48:53 +02:00

9.5 KiB

Database Setup for Docker Deployment

Overview

The Recticel Quality Application uses a dual-database approach:

  1. MariaDB (Primary) - Production data, users, permissions, orders
  2. SQLite (Backup/Legacy) - Local user authentication fallback

Database Configuration Flow

1. Docker Environment Variables → Database Connection

Docker .env file
    ↓
docker-compose.yml (environment section)
    ↓
Docker container environment variables
    ↓
setup_complete_database.py (reads from env)
    ↓
external_server.conf file (generated)
    ↓
Application runtime (reads conf file)

2. Environment Variables Used

Variable Default Purpose Used By
DB_HOST db Database server hostname All DB operations
DB_PORT 3306 MariaDB port All DB operations
DB_NAME trasabilitate Database name All DB operations
DB_USER trasabilitate Database username All DB operations
DB_PASSWORD Initial01! Database password All DB operations
MYSQL_ROOT_PASSWORD rootpassword MariaDB root password DB initialization
INIT_DB true Run schema setup docker-entrypoint.sh
SEED_DB true Create superadmin user docker-entrypoint.sh

3. Database Initialization Process

Phase 1: MariaDB Container Startup

# docker-compose.yml starts MariaDB container
# init-db.sql runs automatically:
1. CREATE DATABASE trasabilitate
2. CREATE USER 'trasabilitate'@'%'
3. GRANT ALL PRIVILEGES

Phase 2: Application Container Waits

# docker-entrypoint.sh:
1. Waits for MariaDB to be ready (health check)
2. Tests connection with credentials
3. Retries up to 60 times (2s intervals = 120s timeout)

Phase 3: Configuration File Generation

# docker-entrypoint.sh creates:
/app/instance/external_server.conf
    server_domain=db          # From DB_HOST
    port=3306                  # From DB_PORT
    database_name=trasabilitate # From DB_NAME
    username=trasabilitate     # From DB_USER
    password=Initial01!        # From DB_PASSWORD

Phase 4: Schema Creation (if INIT_DB=true)

# setup_complete_database.py creates:
- scan1_orders (quality scans - station 1)
- scanfg_orders (quality scans - finished goods)
- order_for_labels (production orders for labels)
- warehouse_locations (warehouse management)
- users (user authentication)
- roles (user roles)
- permissions (permission definitions)
- role_permissions (role-permission mappings)
- role_hierarchy (role inheritance)
- permission_audit_log (permission change tracking)

# Also creates triggers:
- increment_approved_quantity (auto-count approved items)
- increment_approved_quantity_fg (auto-count finished goods)

Phase 5: Data Seeding (if SEED_DB=true)

# seed.py creates:
- Superadmin user (username: superadmin, password: superadmin123)

# setup_complete_database.py also creates:
- Default permission set (35+ permissions)
- Role hierarchy (7 roles: superadmin → admin → manager → workers)
- Role-permission mappings

4. How Application Connects to Database

A. Settings Module (app/settings.py)

def get_external_db_connection():
    # Reads /app/instance/external_server.conf
    # Returns mariadb.connect() using conf values

B. Other Modules (order_labels.py, print_module.py, warehouse.py)

def get_db_connection():
    # Also reads external_server.conf
    # Each module manages its own connections

C. SQLAlchemy (app/init.py)

# Currently hardcoded to SQLite (NOT DOCKER-FRIENDLY!)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'

Current Issues & Recommendations

Problem 1: Hardcoded SQLite in init.py

Issue: app/__init__.py uses hardcoded SQLite connection

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'

Impact:

  • Not using environment variables
  • SQLAlchemy not connected to MariaDB
  • Inconsistent with external_server.conf approach

Solution: Update to read from environment:

import os

def create_app():
    app = Flask(__name__)
    
    # Database configuration from environment
    db_user = os.getenv('DB_USER', 'trasabilitate')
    db_pass = os.getenv('DB_PASSWORD', 'Initial01!')
    db_host = os.getenv('DB_HOST', 'localhost')
    db_port = os.getenv('DB_PORT', '3306')
    db_name = os.getenv('DB_NAME', 'trasabilitate')
    
    # Use MariaDB/MySQL connection
    app.config['SQLALCHEMY_DATABASE_URI'] = (
        f'mysql+mariadb://{db_user}:{db_pass}@{db_host}:{db_port}/{db_name}'
    )

Problem 2: Dual Connection Methods

Issue: Application uses two different connection methods:

  1. SQLAlchemy ORM (for User model)
  2. Direct mariadb.connect() (for everything else)

Impact:

  • Complexity in maintenance
  • Potential connection pool exhaustion
  • Inconsistent transaction handling

Recommendation: Standardize on one approach:

  • Option A: Use SQLAlchemy for everything (preferred)
  • Option B: Use direct mariadb connections everywhere

Problem 3: external_server.conf Redundancy

Issue: Configuration is duplicated:

  1. Environment variables → external_server.conf
  2. Application reads external_server.conf

Impact:

  • Unnecessary file I/O
  • Potential sync issues
  • Not 12-factor app compliant

Recommendation: Read directly from environment variables

Docker Deployment Database Schema

MariaDB Container Configuration

# docker-compose.yml
db:
  image: mariadb:11.3
  environment:
    MYSQL_ROOT_PASSWORD: rootpassword
    MYSQL_DATABASE: trasabilitate
    MYSQL_USER: trasabilitate
    MYSQL_PASSWORD: Initial01!
  volumes:
    - /srv/docker-test/mariadb:/var/lib/mysql  # Persistent storage
    - ./init-db.sql:/docker-entrypoint-initdb.d/01-init.sql

Database Tables Created

Table Purpose Records
scan1_orders Quality scan records (station 1) 1000s
scanfg_orders Finished goods scan records 1000s
order_for_labels Production orders needing labels 100s
warehouse_locations Warehouse location codes 50-200
users User accounts 10-50
roles Role definitions 7
permissions Permission definitions 35+
role_permissions Role-permission mappings 100+
role_hierarchy Role inheritance tree 7
permission_audit_log Permission change audit trail Growing

Default Users & Roles

Superadmin User:

  • Username: superadmin
  • Password: superadmin123
  • Role: superadmin
  • Access: Full system access

Role Hierarchy:

superadmin (level 1)
  └─ admin (level 2)
      └─ manager (level 3)
          ├─ quality_manager (level 4)
          │   └─ quality_worker (level 5)
          └─ warehouse_manager (level 4)
              └─ warehouse_worker (level 5)

Production Deployment Checklist

  • Change MYSQL_ROOT_PASSWORD from default
  • Change DB_PASSWORD from default (Initial01!)
  • Change superadmin password from default (superadmin123)
  • Set INIT_DB=false after first deployment
  • Set SEED_DB=false after first deployment
  • Set strong SECRET_KEY in environment
  • Backup MariaDB data directory regularly
  • Enable MariaDB binary logging for point-in-time recovery
  • Configure proper DB_MAX_RETRIES and DB_RETRY_INTERVAL
  • Monitor database connections and performance
  • Set up database user with minimal required privileges

Troubleshooting

Database Connection Failed

# Check if MariaDB container is running
docker-compose ps

# Check MariaDB logs
docker-compose logs db

# Test connection from app container
docker-compose exec web python3 -c "
import mariadb
conn = mariadb.connect(
    user='trasabilitate',
    password='Initial01!',
    host='db',
    port=3306,
    database='trasabilitate'
)
print('Connection successful!')
"

Tables Not Created

# Run setup script manually
docker-compose exec web python3 /app/app/db_create_scripts/setup_complete_database.py

# Check tables
docker-compose exec db mysql -utrasabilitate -pInitial01! trasabilitate -e "SHOW TABLES;"

external_server.conf Not Found

# Verify file exists
docker-compose exec web cat /app/instance/external_server.conf

# Recreate if missing (entrypoint should do this automatically)
docker-compose restart web

Migration from Non-Docker to Docker

If migrating from a non-Docker deployment:

  1. Backup existing MariaDB database:

    mysqldump -u trasabilitate -p trasabilitate > backup.sql
    
  2. Update docker-compose.yml paths to existing data:

    db:
      volumes:
        - /path/to/existing/mariadb:/var/lib/mysql
    
  3. Or restore to new Docker MariaDB:

    docker-compose exec -T db mysql -utrasabilitate -pInitial01! trasabilitate < backup.sql
    
  4. Verify data:

    docker-compose exec db mysql -utrasabilitate -pInitial01! trasabilitate -e "SELECT COUNT(*) FROM users;"
    

Environment Variable Examples

Development (.env)

DB_HOST=db
DB_PORT=3306
DB_NAME=trasabilitate
DB_USER=trasabilitate
DB_PASSWORD=Initial01!
MYSQL_ROOT_PASSWORD=rootpassword
INIT_DB=true
SEED_DB=true
FLASK_ENV=development
GUNICORN_LOG_LEVEL=debug

Production (.env)

DB_HOST=db
DB_PORT=3306
DB_NAME=trasabilitate
DB_USER=trasabilitate
DB_PASSWORD=SuperSecurePassword123!@#
MYSQL_ROOT_PASSWORD=SuperSecureRootPass456!@#
INIT_DB=false
SEED_DB=false
FLASK_ENV=production
GUNICORN_LOG_LEVEL=info
SECRET_KEY=your-super-secret-key-change-this