343 lines
9.5 KiB
Markdown
343 lines
9.5 KiB
Markdown
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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)
|
|
```bash
|
|
# 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)
|
|
```bash
|
|
# 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)
|
|
```python
|
|
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)
|
|
```python
|
|
def get_db_connection():
|
|
# Also reads external_server.conf
|
|
# Each module manages its own connections
|
|
```
|
|
|
|
#### C. SQLAlchemy (app/__init__.py)
|
|
```python
|
|
# 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
|
|
```python
|
|
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:
|
|
```python
|
|
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
|
|
```yaml
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
mysqldump -u trasabilitate -p trasabilitate > backup.sql
|
|
```
|
|
|
|
2. **Update docker-compose.yml paths to existing data:**
|
|
```yaml
|
|
db:
|
|
volumes:
|
|
- /path/to/existing/mariadb:/var/lib/mysql
|
|
```
|
|
|
|
3. **Or restore to new Docker MariaDB:**
|
|
```bash
|
|
docker-compose exec -T db mysql -utrasabilitate -pInitial01! trasabilitate < backup.sql
|
|
```
|
|
|
|
4. **Verify data:**
|
|
```bash
|
|
docker-compose exec db mysql -utrasabilitate -pInitial01! trasabilitate -e "SELECT COUNT(*) FROM users;"
|
|
```
|
|
|
|
## Environment Variable Examples
|
|
|
|
### Development (.env)
|
|
```bash
|
|
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)
|
|
```bash
|
|
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
|
|
```
|