# 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` |

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

## 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

## 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.
