Migration runner ready and a sister site can deploy from a clean
checkout with one .env file.
ADRs relocated (migrations/adr/ -> docs/adr/):
- migrations/ is now Alembic territory, not docs.
- All cross-references updated: CLAUDE.md, docs/PLUGIN-HOOKS.md,
docs/PLUGIN-QUICKSTART.md.
Alembic initialized (migrations/):
- env.py, script.py.mako, alembic.ini copied from Flask-Migrate
templates so `flask db migrate` and `flask db upgrade` work without
a one-time `flask db init` (which would clash with the existing
migrations/ directory).
- Baseline migration generated via autogenerate, captures all 47
tables (core models + 6 plugins) as the upgrade target. Ready for
per-site `flask db upgrade` from an empty schema.
Deploy artifacts:
- Dockerfile: python:3.12-slim base, gunicorn server, non-root user,
healthcheck against /api/auth/login. Single image bundles all six
plugins; sites enable via `flask plugin install <name>`.
- docker-compose.yml: MySQL 8 + API container, healthcheck-gated
startup, env-driven secrets that fail loud on missing values
(`${SECRET_KEY:?}` form).
- .env.example: full env-var inventory with comments. Calls out
required vs optional. Matches what ProductionConfig.validate
enforces.
docs/DEPLOY.md:
- Step-by-step per-site runbook: clone, configure .env, bring up
stack, run migrations, seed reference data, install plugins,
create admin, front with TLS, backups, updates.
- Common-issues table.
- Cross-links to ADR-004 (per-site rationale), ADR-003 (plugin
distribution), and the config source.
Skills:
- migrating-asset-schema: Alembic + one-shot data migration policy.
Rules: additive first, renames are three steps, destructive ops
need rollback, equipment migration filter per ADR-001 + ADR-005.
- hardening-flask-config: production validation, CORS allowlist
policy, JWT cookie hardening, per-site deploy isolation per ADR-004.
CLAUDE.md updated to reflect the post-Phase-5 state. No tests added
this commit; the Alembic baseline is exercised by the existing
db.create_all-based test suite (tests do not touch the migration
runner; that's by design until per-plugin migrations land).
Test count unchanged: 101 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
2.1 KiB
Plaintext
61 lines
2.1 KiB
Plaintext
# shopdb-flask environment template.
|
|
#
|
|
# Copy to .env and fill in the values. .env is gitignored. ProductionConfig
|
|
# refuses to boot when SECRET_KEY, JWT_SECRET_KEY, DATABASE_URL, or
|
|
# CORS_ORIGINS are missing or use the dev defaults.
|
|
#
|
|
# See docs/DEPLOY.md for the full per-site deployment runbook.
|
|
|
|
# ---- Flask ----
|
|
FLASK_APP=wsgi.py
|
|
|
|
# Set to 'production' for live sites. Other valid values: 'development',
|
|
# 'testing'. Production triggers ProductionConfig.validate() at boot.
|
|
FLASK_ENV=production
|
|
|
|
# ---- Required secrets (production refuses to boot without these) ----
|
|
|
|
# Generate strong random values, e.g.:
|
|
# python -c "import secrets; print(secrets.token_urlsafe(64))"
|
|
SECRET_KEY=change-this-to-a-secure-random-string
|
|
JWT_SECRET_KEY=change-this-to-another-secure-random-string
|
|
|
|
# ---- Database (required) ----
|
|
|
|
# Format: mysql+pymysql://<user>:<password>@<host>:<port>/<database>
|
|
# In docker-compose, host is `db` (the service name).
|
|
DATABASE_URL=mysql+pymysql://shopdb:CHANGE_ME@db:3306/shopdb_flask
|
|
|
|
# ---- CORS (required, no wildcards in production) ----
|
|
|
|
# Comma-separated list of explicit origins permitted to call the API.
|
|
# Example for a single-host facility deploy:
|
|
# CORS_ORIGINS=https://shopdb.facility-a.example.com
|
|
# Wildcard '*' is rejected by ProductionConfig.validate().
|
|
CORS_ORIGINS=http://localhost:5173
|
|
|
|
# ---- JWT lifecycle (optional, defaults shown) ----
|
|
JWT_ACCESS_TOKEN_EXPIRES=3600
|
|
JWT_REFRESH_TOKEN_EXPIRES=2592000
|
|
|
|
# ---- Logging (optional) ----
|
|
LOG_LEVEL=INFO
|
|
|
|
# ---- docker-compose only ----
|
|
# These are read by docker-compose.yml; not used by the Flask app directly.
|
|
MYSQL_ROOT_PASSWORD=CHANGE_ME_ROOT_PASSWORD
|
|
MYSQL_PASSWORD=CHANGE_ME_APP_PASSWORD
|
|
MYSQL_PORT=3306
|
|
API_PORT=5001
|
|
|
|
# ---- Zabbix integration (optional, for printer supply monitoring) ----
|
|
ZABBIX_URL=
|
|
ZABBIX_TOKEN=
|
|
|
|
# ---- Per-plugin collector API keys (optional) ----
|
|
# Per ADR-006, each plugin can accept external collector input at
|
|
# /api/collector/<pluginname>. The framework checks
|
|
# COLLECTOR_API_KEY_<PLUGINNAME> first, then COLLECTOR_API_KEY as fallback.
|
|
# COLLECTOR_API_KEY=
|
|
# COLLECTOR_API_KEY_COMPUTERS=
|