8.0 KiB
8.0 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 viascripts/import_from_mysql.py) - Connection:
.envfile. 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
- ADR-007: Product versioning and releases - ACCEPTED
- ADR-008: Plugin migration ownership (per-plugin chains) - ACCEPTED
- ADR-009: Frontend plugin route gating - ACCEPTED
- ADR-010: Frontend plugin hook contract - ACCEPTED
- ADR-011: Machines rename + modeltypes retyping - ACCEPTED
- ADR-012: GE-Enforce manifest ownership in shopdb - ACCEPTED
- ADR-013: Plugin catalog, curated shelf, and lean per-site builds - PROPOSED
- ADR-014: Schema-lean per-site builds (retire cross-plugin FKs, prune not-installed plugin tables) - 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-07-13)
Refactor phases 0-5 landed; phase 6 (multi-site distribution readiness) largely complete; the last big milestone is the legacy-data import + a production pilot.
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__,BasePluginhooks,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.apinamespace,BasePlugin.get_setting/set_settinghelpers - 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
- 1077 tests, naming/style check green, Gitea Actions CI (backend + naming + frontend build + a lean-build job + a migrations-mysql job that runs the real fresh upgrade on utf8mb4 MySQL 8)
__contract_version__at 0.13.0 (0.12.0 added the mailer, 0.13.0 the User model, to the plugin surface) (product__version__0.7.0, tags v0.5.0/v0.6.0/v0.7.0 - distinct series, ADR-007)- 13 bundled plugins all satisfy contract: computers, employees, geenforce, knowledgebase, machines, measuringtools, network, notifications, printedparts, printers, slides, usb, warranty
- Core Alembic chain: baseline
68b3947ae14f-> head7d26_settings_description_text(33 core migrations). Each plugin owns its own chain (ADR-008); deploy runsflask db upgradethenflask plugin upgrade-all. Reproducible + idempotent from empty (env.py relaxes session sql_mode so the chain runs on strict MySQL 8). - Lean per-site builds (ADR-013 + ADR-014):
scripts/build-site.sh(backend) +SITE_PLUGINSviascripts/stage-frontend.mjs(frontend) ship only chosen plugins;flask plugin prune-schemadrops non-installed plugins' tables at provisioning. Sidebar nav / settings / Displays all gate on staged routes. Manifest-lessplugins/<name>/frontend/dirs (e.g.applications) are core and always ship. - Legacy import:
docs/IMPORT-API.mdis the schema-agnostic import contract;docs/IMPORT-ADOPTION.md+docs/PILOT-DEPLOY.mdcover adopting a site;scripts/site_imports/wjf/is the West Jefferson reference loader (all 16 stages, validated end-to-end including on a Windows + MySQL 8 VM). - API is migration-complete: an admin PAT + docs/IMPORT-API.md let a script import the whole legacy DB (X-Import-Mode preserves timestamps).
- Pre-1.0 framework; sister sites should pin tight
core_versionranges 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 NULLmigrates. Skillmigrating-asset-schemadocuments the pattern; the actual one-shot script lives inscripts/migration/when run. - Printers retirement: legacy
PrinterDatamodel + frontend changes. Coordinated with the equipment data migration. - (DONE 2026-07-11)
measuringtoolsplugin (ADR-005) is built and bundled; docs/PLUGIN-GUIDE.md narrates its construction as the plugin tutorial. - (DONE) Frontend plugin hook contract (ADR-010): get_settings_cards / get_asset_panels / get_map_overlays / get_asset_presentation shipped; generic renderers for panels/overlays land incrementally.
- (DONE) Per-plugin Alembic chains (ADR-008): every bundled plugin carries its own chain; no plugin uses db.create_all().
- Legacy ASP data import against the renamed schema (unblocked; run via docs/IMPORT-API.md) + a production pilot deployment.
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 via the Alembic chain
flask db upgrade
# Seed RBAC, default settings, and reference data (all idempotent)
flask seed permissions
flask seed settings
flask seed reference-data
# Restart services
pm2 restart shopdb-flask-api shopdb-flask-ui
Service URLs
- Flask API: http://localhost:5001
- Flask UI: http://localhost:5173
- Legacy ASP (data source for one-time import): http://192.168.122.151:8080
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__.pyexports all modelsplugin.pyextendsBasePluginmanifest.jsonwith 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 registrationshopdb/plugins/base.py- BasePlugin ABC, PluginMeta dataclassshopdb/plugins/loader.py- filesystem discovery, dependency-aware loadingshopdb/core/api/assets.py- example of optional plugin importsfrontend/src/router/index.js- frontend routingfrontend/src/components/AppSidebar.vue- navigation menudocs/adr/- architecture decision records
Migration notes
migrations/DATA_MIGRATION_GUIDE.md- one-time import from legacy ASP shopdbmigrations/MIGRATE_USB_DEVICES_FROM_EQUIPMENT.md- USB device migration from equipment tablemigrations/FIX_LOCATIONONLY_EQUIPMENT_TYPES.md- LocationOnly equipment type fixmigrations/PRODUCTION_MIGRATION_GUIDE.md- production import methodsmigrations/rename_underscore_columns.sql- one-time rename of snake_case columns to lowercase concatenated (per CONTRIBUTING.md)migrations/versions/- the core Alembic chain (baseline68b3947ae14f-> head7d26_settings_description_text). Runflask db upgradeto apply.