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

142 lines
5.4 KiB
Markdown

# 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:
```bash
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
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`:
```bash
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
```bash
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.