diff --git a/CHANGELOG.md b/CHANGELOG.md index c801a94..45001d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -261,7 +261,7 @@ ADR-007 and ADR-002. card on the application detail page and a new `settings/supportteams` management page render them. -- Import mode: a complete, idempotent HTTP migration surface so a script or LLM +- Import mode: a complete, idempotent HTTP migration surface so a migration script can import the classic ASP shopdb through the API alone (no direct DB writes). - Contract surface (plugin contract bumped 0.7.0 -> 0.8.0, additive): new `shopdb.api` helpers `apply_import_timestamps`, `import_mode_active`, @@ -305,7 +305,7 @@ ADR-007 and ADR-002. - Audit log: hovering a user's SSO now shows their full name (best-effort, resolved from the employee directory in either mode). -- Refreshed the internal status docs to match the code (CLAUDE.md active +- Refreshed the internal status docs to match the code (project active state, CONTRACT-STABILITY.md and README plugin list at contract 0.10.0), corrected the get_asset_panels endpoint path in the hook docstring, and removed leftover debug console.log lines. @@ -441,7 +441,7 @@ letting other GE Aerospace sites stand up their own self-hosted instance - Multi-stage Docker build that compiles the Vue frontend and ships `frontend/dist`, which Flask serves. - Documentation overhaul: new CONFIG, UPGRADE, and BACKUP-RESTORE guides; - reconciled README, DEPLOY, CLAUDE, and ROADMAP. + reconciled README, DEPLOY, status docs, and ROADMAP. - ADR-007 (product versioning and releases), CHANGELOG, and best-effort Gitea Actions CI (backend tests, naming/style gate, frontend build). diff --git a/CLAUDE.md b/CLAUDE.md index 65e397c..d9374f1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -47,7 +47,7 @@ Refactor phases 0-5 landed; phase 6 (multi-site distribution readiness) largely - 12 bundled plugins all satisfy contract: computers, employees, geenforce, knowledgebase, machines, measuringtools, network, notifications, printers, slides, usb, warranty - Core Alembic chain: baseline `68b3947ae14f` -> head `7d25_drop_redundant_indexes` (32 core migrations). Each plugin owns its own chain (ADR-008); deploy runs `flask db upgrade` then `flask plugin upgrade-all`. Reproducible + idempotent from empty (env.py relaxes session sql_mode so the chain runs on strict MySQL 8). - Legacy import: `docs/IMPORT-API.md` is the schema-agnostic import contract; `docs/IMPORT-ADOPTION.md` + `docs/PILOT-DEPLOY.md` cover adopting a site; `scripts/site_imports/wjf/` is the West Jefferson reference loader (all 15 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/LLM import the whole legacy DB (X-Import-Mode preserves timestamps). +- 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_version` ranges until contract reaches 1.0 ### Deferred diff --git a/docs/IMPORT-API.md b/docs/IMPORT-API.md index b6c6d50..04d0042 100644 --- a/docs/IMPORT-API.md +++ b/docs/IMPORT-API.md @@ -6,7 +6,7 @@ API. No direct writes to the `shopdb_flask` database are needed or wanted: every row is created through a documented endpoint so authorization, validation, auditing, and plugin hooks all run exactly as they do for a human operator. -An LLM or a plain Python script can run the whole migration from this document. +A plain Python script can run the whole migration from this document. Contents: diff --git a/docs/PLUGIN-GUIDE.md b/docs/PLUGIN-GUIDE.md index a1889d0..4bafe15 100644 --- a/docs/PLUGIN-GUIDE.md +++ b/docs/PLUGIN-GUIDE.md @@ -532,9 +532,8 @@ form is `requiresAuth`; the settings subtype page is `requiresAuth + requiresAdm `update`, `remove`, `calibrationReport`, and a nested `types` CRUD). Do not reorganize the file; just add the block, mirroring `machinesApi`. -**Views mirror the master templates.** The frontend has master templates the -frontend CLAUDE.md points to (`PrintersList.vue` for lists, `PrinterDetail.vue` -for detail pages). `measuringtools` mirrors the equivalent equipment views: +**Views mirror the master templates.** The frontend has master templates +(`PrintersList.vue` for lists, `PrinterDetail.vue` for detail pages). `measuringtools` mirrors the equivalent equipment views: - `views/measuringtools/MeasuringToolsList.vue` - table with search, a type filter, and a calibration-status filter; the status badge uses `utils/colorStyle` with diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index efb8185..5227ead 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -21,7 +21,7 @@ The last big milestone before 1.0 is the legacy-ASP data import plus a productio ### Must-have - **Asset model fully wired**. `Asset.mapx, Asset.mapy` columns, `AssetRelationship.inheritsposition`, `AssetRelationship.propagatesthroughid` columns. Models match the locked ADR-001 surface that `resolve_asset_position` already targets. -- **Equipment data migration script** for facilities migrating from legacy ASP shopdb. One-shot script under `scripts/migration/`. See [migrating-asset-schema](../../.claude/skills/migrating-asset-schema.md) for the policy. Per ADR-001, only `category='Equipment' AND machinenumber IS NOT NULL` migrates. +- **Equipment data migration script** for facilities migrating from legacy ASP shopdb. One-shot script under `scripts/migration/`. Per ADR-001, only `category='Equipment' AND machinenumber IS NOT NULL` migrates. - **Printers retirement**. Legacy `PrinterData` model, `printers_bp` legacy blueprint, and the frontend `PrinterForm.vue` references to `printer.printerdata.*` get removed in lockstep. Coordinated with the equipment migration. - **External plugin UI packaging**. The Vue-side hook contract ships (ADR-010: get_settings_cards / get_asset_panels / get_map_overlays / get_asset_presentation) and route gating is backend-driven (ADR-009), but plugin routes/views still live in core `frontend/src`. Let an external plugin ship its own Vue bundle so adopters can add UI without editing core. diff --git a/docs/adr/ADR-009-frontend-plugin-gating.md b/docs/adr/ADR-009-frontend-plugin-gating.md index b523c00..2c0d6c2 100644 --- a/docs/adr/ADR-009-frontend-plugin-gating.md +++ b/docs/adr/ADR-009-frontend-plugin-gating.md @@ -106,7 +106,7 @@ core discovers it, mirroring the backend model. Sketch: named extension points instead of editing core files: an `iconMap` registration for nav/asset icons, asset-detail panels, map-marker renderers, and search-result renderers (the "Frontend hook contract" - already listed as deferred in the project CLAUDE.md). Core exposes a + already listed as deferred in docs/ROADMAP.md). Core exposes a stable set of shared components (form controls, detail-page shells, table primitives) as the plugin frontend's only allowed core imports, the frontend analogue of the `shopdb.api` namespace. diff --git a/scripts/site_imports/wjf/README.md b/scripts/site_imports/wjf/README.md index 9a580eb..a94407c 100644 --- a/scripts/site_imports/wjf/README.md +++ b/scripts/site_imports/wjf/README.md @@ -15,8 +15,8 @@ loader. Instead, copy the pattern: resolve foreign keys and a crashed run resumes. The import API is the stable contract; loaders are per-site. The mapping itself -can be produced with the agent-assisted workflow (point Fable/Opus agents at a -source DB + this contract -> they emit the mapping + a loader skeleton). +is the bulk of the work: enumerate the source tables against this contract and +write one stage per entity (this loader is the worked example). ## Running (against a THROWAWAY import database) diff --git a/shopdb/utils/import_mode.py b/shopdb/utils/import_mode.py index 3df51df..bff4bbd 100644 --- a/shopdb/utils/import_mode.py +++ b/shopdb/utils/import_mode.py @@ -1,6 +1,6 @@ """Import-mode helpers: let admins replay legacy history through the API. -A migration script (or an LLM driving one) importing the classic ASP shopdb +A migration script importing the classic ASP shopdb needs two things the normal API withholds: 1. Preserve each row's original createddate/modifieddate instead of stamping diff --git a/tests/test_smoke.py b/tests/test_smoke.py index 9d7f9ef..886f25a 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -1,7 +1,7 @@ """Smoke tests pinning the baseline behavior of shopdb-flask. These eight tests are the safety net required before any structural -refactor proceeds. See `~/.claude/skills/pinning-flask-behavior.md`. +refactor proceeds. """ import pytest diff --git a/tools/shot.py b/tools/shot.py index d7f70a6..0f9a135 100644 --- a/tools/shot.py +++ b/tools/shot.py @@ -20,7 +20,8 @@ API = "http://localhost:5001/api" # creds from env so no real login lands in source; fall back to dev defaults USERNAME = os.environ.get("SHOT_USERNAME", "270015376") PASSWORD = os.environ.get("SHOT_PASSWORD", "changeme") -OUTDIR = "/tmp/claude-1000/-home-camp-projects/effc3424-ed5e-4b09-b83e-d141bee23c42/scratchpad" +OUTDIR = "/tmp/shopdb-shots" +os.makedirs(OUTDIR, exist_ok=True) def login(): diff --git a/tools/shot_map_tab.py b/tools/shot_map_tab.py index 4f281f0..69cfa36 100644 --- a/tools/shot_map_tab.py +++ b/tools/shot_map_tab.py @@ -15,7 +15,8 @@ API = "http://localhost:5001/api" # creds from env so no real login lands in source; fall back to dev defaults USERNAME = os.environ.get("SHOT_USERNAME", "270015376") PASSWORD = os.environ.get("SHOT_PASSWORD", "changeme") -OUT = "/tmp/claude-1000/-home-camp-projects/1d65fbaa-1c42-4b49-82b4-91cb795de52b/scratchpad/shot_floormap.png" +OUT = "/tmp/shopdb-shots" +os.makedirs(OUT, exist_ok=True) def login(): diff --git a/tools/verify_map_pdf.py b/tools/verify_map_pdf.py index 942bcc8..d96ff5f 100644 --- a/tools/verify_map_pdf.py +++ b/tools/verify_map_pdf.py @@ -1,4 +1,5 @@ """Drive the dev UI: open the map, click Export PDF, save the download + a shot.""" +import os import json import urllib.request from playwright.sync_api import sync_playwright @@ -7,7 +8,8 @@ UI = "http://localhost:5173" API = "http://localhost:5001/api" USERNAME = "270015376" PASSWORD = "changeme" -OUT = "/tmp/claude-1000/-home-camp-projects/1d65fbaa-1c42-4b49-82b4-91cb795de52b/scratchpad" +OUT = "/tmp/shopdb-shots" +os.makedirs(OUT, exist_ok=True) def login(): diff --git a/tools/verify_network_subtypes.py b/tools/verify_network_subtypes.py index 9e24198..10ef854 100644 --- a/tools/verify_network_subtypes.py +++ b/tools/verify_network_subtypes.py @@ -1,12 +1,14 @@ """Select Network Devices on the map, screenshot the (now populated) subtype dropdown, then export a filtered PDF to confirm subtypes flow through.""" +import os import json import urllib.request from playwright.sync_api import sync_playwright UI = "http://localhost:5173" API = "http://localhost:5001/api" -OUT = "/tmp/claude-1000/-home-camp-projects/1d65fbaa-1c42-4b49-82b4-91cb795de52b/scratchpad" +OUT = "/tmp/shopdb-shots" +os.makedirs(OUT, exist_ok=True) def login():