Files
shopdb-flask/CLAUDE.md
cproudlock d4e3ac9fc8 Phase 5: Alembic baseline, per-site deploy, ADRs to docs/adr
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>
2026-05-08 17:56:19 -04:00

5.4 KiB

ShopDB Flask Project

Modern rewrite of the classic-ASP shopdb. Built as a framework so sister GE Aerospace sites can adopt it. Plugin system is the product.

Database

  • Active database: shopdb_flask (MySQL, asset-based schema)
  • Legacy database: shopdb (Classic ASP schema, used only for one-time data import via scripts/import_from_mysql.py)
  • Connection: .env file. See .env.example.

Architecture decisions live in docs/adr/. Read those before making schema or contract changes.

  • ADR-001: Asset model is the platform contract (Machine retires) - ACCEPTED
  • ADR-002: Plugin contract versioning (semver) - ACCEPTED
  • ADR-003: Plugin distribution model (in-tree bundled + filesystem-based external) - ACCEPTED
  • ADR-004: Deployment topology (per-site instances, not multi-tenant) - ACCEPTED
  • ADR-005: Equipment vs measuringtools plugin scope - ACCEPTED
  • ADR-006: Plugin collector contract pattern - ACCEPTED

Coding convention

CONTRIBUTING.md defines naming rules (DB tables, columns, Python, JS, Vue, API). Pre-commit hook at scripts/check-naming-and-style.sh enforces them. Read CONTRIBUTING.md before naming any new identifier.

Current state (as of 2026-05-08)

Refactor phases 0-5 landed. Five commits on main, all pushed to gitea origin.

Phases done

  • Phase 0: 6 ADRs accepted, naming convention v1, pre-commit style hook
  • Phase 1: 8 smoke tests + 7 production-config tests, Flask-SQLAlchemy 3 fixtures, uv lockfile, hardened ProductionConfig
  • Phase 2: contract surface defined (__contract_version__, BasePlugin hooks, docs/PLUGIN-HOOKS.md), 51 contract tests
  • Phase 3: manifest-first loader, fail-loud/isolate policy, contract-version range checking, auto-register core blueprints, shopdb.api namespace, BasePlugin.get_setting/set_setting helpers
  • Phase 4: flask plugin new <name> CLI, scaffold templates, 14 canary tests, docs/PLUGIN-QUICKSTART.md
  • Phase 5: ADRs moved to docs/adr/, Alembic baseline migration, per-site deploy artifacts (Dockerfile, docker-compose.yml, docs/DEPLOY.md)

Active state

  • 101+ tests passing, naming/style check green
  • __contract_version__ at 0.2.0
  • 6 bundled plugins all satisfy contract: computers, equipment, network, notifications, printers, usb
  • Pre-1.0 framework; sister sites should pin tight core_version ranges until contract reaches 1.0

Deferred

  • Equipment data migration (one-shot script for legacy ASP shopdb -> assets). Per ADR-001, only category='Equipment' AND machinenumber IS NOT NULL migrates. Skill migrating-asset-schema documents the pattern; the actual one-shot script lives in scripts/migration/ when run.
  • Printers retirement: legacy PrinterData model + frontend changes. Coordinated with the equipment data migration.
  • measuringtools plugin (ADR-005). First plugin to be built using the scaffold.
  • Frontend hook contract for asset-detail, map markers, search results
  • Alembic per-plugin migration chains (the framework supports them; bundled plugins haven't moved off db.create_all() yet)

Quick start

# Start dev environment
~/start-dev-env.sh

# Activate venv and install deps
cd /home/camp/projects/shopdb-flask
source venv/bin/activate
pip install -r requirements.txt

# Configure environment
cp .env.example .env
# Edit .env with DB credentials, JWT secrets

# Create / update database tables
flask db-utils create-all

# Seed reference data
flask seed reference-data

# Restart services
pm2 restart shopdb-flask-api shopdb-flask-ui

Service URLs

Plugin structure

plugins/
  <plugin_name>/
    __init__.py
    plugin.py          # BasePlugin implementation
    manifest.json      # Plugin metadata (name, version, dependencies, api_prefix)
    models/
      __init__.py      # Export all models
      <model>.py       # SQLAlchemy models
    api/
      __init__.py
      routes.py        # Flask Blueprint
    services/          # Optional, business logic
    schemas/           # Optional, marshmallow schemas
    migrations/        # Optional, plugin-specific Alembic migrations

Each plugin must have:

  • models/__init__.py exports all models
  • plugin.py extends BasePlugin
  • manifest.json with metadata (single source of truth per ADR-002)
  • No direct imports from core code (use the contract surface defined in ADR-001)

Key files

  • shopdb/__init__.py - app factory, blueprint registration
  • shopdb/plugins/base.py - BasePlugin ABC, PluginMeta dataclass
  • shopdb/plugins/loader.py - filesystem discovery, dependency-aware loading
  • shopdb/core/api/assets.py - example of optional plugin imports
  • frontend/src/router/index.js - frontend routing
  • frontend/src/components/AppSidebar.vue - navigation menu
  • docs/adr/ - architecture decision records

Migration notes

  • migrations/DATA_MIGRATION_GUIDE.md - one-time import from legacy ASP shopdb
  • migrations/MIGRATE_USB_DEVICES_FROM_EQUIPMENT.md - USB device migration from equipment table
  • migrations/FIX_LOCATIONONLY_EQUIPMENT_TYPES.md - LocationOnly equipment type fix
  • migrations/PRODUCTION_MIGRATION_GUIDE.md - production import methods
  • migrations/rename_underscore_columns.sql - one-time rename of snake_case columns to lowercase concatenated (per CONTRIBUTING.md)
  • migrations/versions/ - Alembic versions (currently empty)