Files
shopdb-flask/CLAUDE.md
cproudlock bfc30f4c7c
Some checks failed
CI / naming (push) Successful in 3s
CI / frontend (push) Successful in 1m37s
CI / migrations-mysql (push) Successful in 42s
CI / backend (push) Failing after 4m49s
docs: branch model documents one branch per instance
CONTRIBUTING.md still said "main is the product every site runs and the
publication mirror exports" and framed wj/wilm as site branches feeding it.
That was true when main was the only thing anyone deployed. It is not now:
WJ production runs wj, the /ops instance runs dev, and main deploys nowhere.
Nothing in the repository mentioned dev at all, so the branch a deploy script
refuses to run without was undocumented.

Replaces that section with the branch/instance table and the dev -> wj -> main
promotion order, and says why promoting before validating is the wrong way
round. Keeps the wilm note but moves it up with the reason it cannot be
merged locally: it sits on the publication lineage and shares no ancestor.

CLAUDE.md gains the branch-to-server pointer and records that
export-github.sh now builds a dist only for wj and dev.

docs/DEPLOY.md is deliberately left alone: `git pull origin main` is correct
there. That document is the generic connected-Docker deploy another site
follows, and main is exactly what another site adopts.

Scope: product
2026-09-03 18:52:55 -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. The plugin system is the product.

This site is not the only site. Anything that names West Jefferson - a hostname, a share path, a subnet, a machine-number format, a label prefix - is a defect unless it is a setting with a neutral default, a site-namespaced directory, or seed data. That is ADR-015, and it is the rule most often broken in the places tooling cannot see: PowerShell, the installer, JSON, the imaging share.

Facts that move live in the map

docs/PROJECT-MAP.md is GENERATED. It carries the product and contract versions, the plugin inventory, every Alembic chain head, the ADR index with status, and the size of the codebase. Read it instead of asking; regenerate it rather than correcting it by hand:

venv/bin/python scripts/gen_project_map.py           # write
venv/bin/python scripts/gen_project_map.py --check   # CI form

Hand-written version numbers in this file were wrong by two contract releases and 400 tests before the map existed. Nothing that the generator can derive should be typed here again.

Where to look

question read
what a name may be called CONTRIBUTING.md
why the architecture is like that docs/adr/ (index in the map)
what a plugin may touch docs/PLUGIN-HOOKS.md
what the collector sends docs/COLLECTOR-INTEGRATION.md, ADR-006
how a site is deployed docs/INSTALL-WINDOWS.md, docs/OPERATE-WINDOWS.md
how code reaches GitHub tools/export-github.sh
which branch reaches which server devnotes/deploy-and-branch-model.html

Standards are gates, not prose

Compliance is checked, not remembered. Run these rather than re-reading the rules:

bash scripts/check-naming-and-style.sh    # naming, style, site literals (ADR-015)
venv/bin/python -m pytest -q              # includes the docs publishability gate
venv/bin/python -m pytest tests/test_plugin_migrations.py   # chain heads registry
venv/bin/python scripts/gen_project_map.py --check

A new plugin table means updating PLUGIN_TABLE_OWNERS and EXPECTED_HEAD_REVISION in tests/test_plugin_migrations.py.

Dependencies have their own check. It needs the network, so it is not in the suite - run it before a release, and see docs/DEPENDENCY-SECURITY.md:

venv/bin/python scripts/scan_sbom.py --gate    # exit 1 on a SHIPPED finding

Database

  • Active: shopdb_flask (MySQL, asset-based schema)
  • Legacy: shopdb (classic ASP schema; one-time import only)
  • Connection: .env, see .env.example

Core migrations run with flask db upgrade; every plugin owns its own chain (ADR-008) and runs with flask plugin upgrade-all. A deploy needs both - skipping the second is how a new column reaches production as a 1054 error.

Tests run on SQLite, production is MySQL. Dialect drift is not caught by the suite: ORDER BY ... NULLS LAST parses on SQLite and is rejected by MySQL. Sort in Python when in doubt.

Coding convention

CONTRIBUTING.md is authoritative: lowercase concatenated DB columns, snake_case pure-code identifiers, a closed acronym list, banned shorthand. The pre-commit hook scripts/check-naming-and-style.sh enforces what it can.

Plugin structure

plugins/<name>/
  manifest.json      # metadata, single source of truth (ADR-002)
  plugin.py          # BasePlugin implementation
  models/            # __init__.py exports every model
  api/routes.py      # Flask blueprint
  migrations/        # this plugin's own Alembic chain
  services/ schemas/ frontend/ client/   # as needed

No plugin imports core directly - everything goes through the shopdb.api contract surface. A manifest-less directory under plugins/ is core frontend surface and always ships.

Key files

  • shopdb/__init__.py - app factory, version constants
  • shopdb/plugins/base.py - BasePlugin, PluginMeta
  • shopdb/plugins/loader.py - discovery and dependency-aware loading
  • shopdb/plugins/alembic_template.py - the env every plugin chain runs through
  • frontend/src/router/index.js, frontend/src/components/AppSidebar.vue
  • tools/export-github.sh - scrub and publication gate; builds the dist for the branch it is on (wj -> /shopdb, dev -> /ops) and refuses on any other
  • tools/mirror-wilm.sh - push a carried wilm bundle to gitea

State

Refactor phases 0-5 landed; phase 6 (multi-site distribution readiness) largely complete. The last milestone before 1.0 is unchanged and still open: the legacy-data import plus a production pilot (scripts/site_imports/wjf/ is the reference loader, validated end to end).

Pre-1.0 framework. Sister sites pin tight core_version ranges until the contract reaches 1.0.

Deferred

  • Equipment data migration (legacy ASP -> assets). Per ADR-001 only category='Equipment' AND machinenumber IS NOT NULL migrates.
  • Printers retirement: legacy PrinterData model, coordinated with the above.

Quick start

source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env          # DB credentials, JWT secrets

flask db upgrade              # core chain
flask plugin upgrade-all      # every plugin chain
flask seed permissions && flask seed settings && flask seed reference-data

pm2 restart shopdb-flask-api shopdb-flask-ui

Dev API on :5001, dev UI on :5173. venv/bin/python tools/shot.py /route logs in and screenshots a page.