Files
shopdb-flask/DOCKER-DEPLOYMENT-COMPLETE.md
Proudlock d40f1a6a92 fix: replace unicode characters and fix finalize-restore endpoint
Style check fixes:
- Replace unicode box-drawing characters with ASCII (|-- instead of ├──)
- Replace emoji status markers with [OK]/[FAIL]/[WARN] tags
- Replace arrows (→ with ->, ↔ with <->) and em-dashes (— with --)
- Add venv-quick to excluded directories in check script
- Exclude darkwing report files (findings.sarif, report.md)

Backup finalization fix:
- Fix finalize-restore endpoint to not claim the upgrade sentinel
- Endpoint now checks for pending upgrade and returns {queued: true}
- Leaves UPGRADE_SENTINEL for background watcher to claim and process
- Prevents inline Alembic runs that can outlast request timeout

Claude Code context:
- Add .claude/ directory with INDEX.md and QUICK-REFERENCE.md
- Add CLAUDE.md with project overview and conventions
- Helps Claude Code understand project structure and rules

Fixes failing test: test_the_endpoint_does_not_run_the_upgrade_itself
Fixes naming/style CI check violations

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-09-07 03:48:11 -04:00

236 lines
6.7 KiB
Markdown

# Docker Deployment - Complete and Working
**Date:** 2026-09-07
**Branch:** wj (post-wilm merge)
**Status:** [OK] Core system operational, backup watcher pending
## What's Running
```
CONTAINER STATUS PORT
flask-shopdb-db-1 Up (healthy) 3306/tcp (internal)
flask-shopdb-api-1 Up https://localhost:5001
```
**Gunicorn Workers:** 4 workers with gevent (PIDs 74-77)
**Plugins Enabled:** 12 of 17 installed
**Database:** MySQL 8.4 with all migrations applied
## Access
**URL:** https://localhost:5001
**Expected:** Browser warning for self-signed certificate (click through)
**Login:** admin / (needs password reset - see below)
## How to Use
### Start Stack
```bash
docker compose -f docker-compose.prebuilt.yml up -d
```
### Stop Stack
```bash
docker compose -f docker-compose.prebuilt.yml down
```
### View Logs
```bash
docker logs -f flask-shopdb-api-1
docker logs flask-shopdb-db-1
```
### Reset Admin Password
```bash
# Generate hash
docker exec flask-shopdb-api-1 python -c \
"from werkzeug.security import generate_password_hash; print(generate_password_hash('your-password'))"
# Update database (replace HASH with output above)
docker exec flask-shopdb-db-1 mysql -uroot -p$MYSQL_ROOT_PASSWORD shopdb_flask -e \
"UPDATE users SET passwordhash='HASH', failedlogins=0, lockeduntil=NULL WHERE username='admin';"
```
Quick reset to password "admin":
```bash
docker exec flask-shopdb-db-1 mysql -uroot -proot-dev-password-not-for-production shopdb_flask -e \
"UPDATE users SET
passwordhash='scrypt:32768:8:1\$B4LhpPrM6qxijInK\$b99b47a0bb5fd45761a1823f401f70a3ceccf71a5d38dc433378aa07426ef8eaf7e679ff3dd7b0ce9772600f83368ac642e9419b9beaa49f87483318bae34547',
failedlogins=0, lockeduntil=NULL
WHERE username='admin';"
```
### Rebuild After Code Changes
```bash
# Rebuild frontend (if frontend code changed)
cd frontend
npm run build
cd ..
# Rebuild Docker image
docker compose -f docker-compose.prebuilt.yml build api
# Restart
docker compose -f docker-compose.prebuilt.yml up -d
```
### Run Database Migrations
```bash
docker exec flask-shopdb-api-1 flask db upgrade
```
### Plugin Management
```bash
# List plugins
docker exec flask-shopdb-api-1 flask plugin list
# Enable plugin
docker exec flask-shopdb-api-1 flask plugin enable PLUGIN_NAME
# Disable plugin
docker exec flask-shopdb-api-1 flask plugin disable PLUGIN_NAME
```
## Build Process Used
### Why Pre-Built Frontend?
**Problem:** Zscaler corporate proxy causes npm to fail inside Docker builds
**Solution:** Build frontend on host, copy into Docker image
### Build Steps Taken
1. **Build Frontend on Host**
```bash
cd frontend
npm ci
npm run build
# Creates frontend/dist/
```
2. **Build Docker Image (Simple)**
```bash
# Uses Dockerfile.prebuilt (Python only, no npm)
docker compose -f docker-compose.prebuilt.yml build
```
3. **Start Services**
```bash
docker compose -f docker-compose.prebuilt.yml up -d
```
4. **Auto-Bootstrap**
- Container entrypoint runs migrations
- Detects first deployment (no instance/plugins.json)
- Auto-installs all 17 plugins (disabled by default)
- Starts gunicorn
## Architecture
### Volumes
- `flask-shopdb_db_data` - MySQL database (persistent)
- `flask-shopdb_instance_data` - Plugin state, uploads, branding (persistent)
### Networks
- `flask-shopdb_default` - Internal bridge network
### Image
- **Built:** 2026-09-07 00:26:27 EDT
- **Size:** 914MB
- **Base:** python:3.14-slim
- **Frontend:** Pre-built Vue 3 SPA (from host)
## What's Not Working Yet
### Backup Watcher Service
**Status:** [FAIL] Build failed
**Reason:** Oracle Linux base image can't download packages due to SSL cert issues with Zscaler
**Impact:** Can't auto-execute backups on schedule (manual backups still work via one-shot container)
**Error:**
```
Cannot download repomd.xml: Curl error (60): SSL peer certificate or SSH remote key was not OK
```
**Workaround Attempted:**
- Copied Zscaler cert to scripts/backup/zscaler-root-ca.pem
- Dockerfile.backup copies cert and runs update-ca-trust
- Still fails because microdnf runs BEFORE cert is trusted
**Fix Needed:**
- Pre-download restic binary and bake into image OR
- Use different base image (Alpine/Debian instead of Oracle Linux) OR
- Skip backup watcher entirely, use cron on host to trigger one-shot backup container
## Production Readiness
**Core Application:** [OK] Production ready
**Deployment Process:** [WARN] Requires npm on host + Docker build
**Backup System:** [FAIL] Not complete (watcher service build fails)
### Recommended Next Steps
1. **CI/CD Pipeline** - Build images automatically, push to registry
2. **Pre-Built Images** - Sites pull instead of building (2 min deploy)
3. **Backup Watcher Fix** - Switch to Alpine base or pre-download restic
4. **TLS Certificates** - Use proper certs from CA (not self-signed)
5. **Secrets Management** - Externalize passwords (.env with strong values)
## Files Created
- `Dockerfile.prebuilt` - Simplified Docker build (no npm)
- `docker-compose.prebuilt.yml` - Docker Compose for pre-built approach
- `.dockerignore.prebuilt` - Allows frontend/dist to be copied
- `start-docker-quick.sh` - Quick restart script
- `DOCKER-PREBUILT-APPROACH.md` - Documents workaround
- `PRODUCTION-READINESS.md` - Honest assessment
## Comparison to Previous Attempts
| Approach | Result | Time | Issue |
|----------|--------|------|-------|
| Multi-stage Dockerfile | [FAIL] Failed | 15+ min | npm fails with Zscaler |
| Pre-built frontend | [OK] Success | 3 min | Works! |
| Backup containers | [FAIL] Failed | N/A | Oracle Linux SSL issues |
## Verification
```bash
# Test frontend
curl -k https://localhost:5001/
# Should return: <!DOCTYPE html>
# Test API
curl -k https://localhost:5001/api/settings
# Should return: {"data":[...]}
# Test database
docker exec flask-shopdb-db-1 mysql -uroot -p$MYSQL_ROOT_PASSWORD \
-e "SELECT COUNT(*) FROM shopdb_flask.users;"
# Should return: count of users
# Check workers
docker logs flask-shopdb-api-1 2>&1 | grep "Booting worker"
# Should show: 4 workers with PIDs
# Check plugins
docker exec flask-shopdb-api-1 flask plugin list | grep Enabled | wc -l
# Should return: 12
```
## Summary
ShopDB Docker deployment is **operational** for core functionality:
- [OK] Database running
- [OK] API serving requests
- [OK] Frontend built and accessible
- [OK] Plugins installed and working
- [OK] HTTPS configured
- [WARN] Backup watcher needs work (but manual backups functional)
The pre-built frontend approach successfully bypasses Zscaler corporate proxy issues. Build time is 2-3 minutes (vs 15+ for failed multi-stage approach).
For production deployment, recommend setting up CI/CD to build images automatically and push to registry so sites can pull pre-built images instead of building locally.