Initial import: shopdb-flask multi-site asset platform

Flask + Vue rewrite of the classic-ASP shopdb, built as a plugin
framework so sister GE Aerospace sites can adopt it. Product version
0.7.0-pre-0.8.0, plugin contract 0.11.0, 966 backend tests.

Key entry points:
- docs/INSTALL-WINDOWS-IIS.md - tested Windows + IIS install runbook
  (own-site and subpath deployment methods)
- docs/PILOT-DEPLOY.md - production pilot: stand up + import + verify
- docs/IMPORT-API.md - schema-agnostic legacy data import contract
- scripts/site_imports/wjf/ - West Jefferson reference import loader
- docs/adr/ - twelve accepted architecture decision records
This commit is contained in:
2026-07-14 07:58:51 -04:00
commit a9d0dfff4a
599 changed files with 88557 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
# scripts/migration (superseded)
The direct-SQL migrators that used to live here (`migrate_assets.py`,
`migrate_communications.py`, `migrate_notifications.py`, `migrate_usb.py`,
`run_migration.py`, `verify_migration.py`) and `scripts/import_from_mysql.py`
were **removed** - they had drifted badly out of sync with the current schema
(they targeted a nonexistent `equipment` table, the retired `Machine` model, and
columns that no longer exist) and were actively misleading.
## Use the import API + a site loader instead
Legacy data is imported through the maintained, schema-agnostic contract in
the IMPORT-API page in the project wiki (create through real endpoints
with an admin PAT + `X-Import-Mode`). Each adopting site writes a thin loader
that reads its own source database and drives that API.
- Reference implementation: [`scripts/site_imports/wjf/`](../site_imports/wjf/)
(West Jefferson classic-ASP -> flask).
- Adoption playbook: the IMPORT-ADOPTION page in the project wiki.
## What's kept here
- `fix_legacy_schema.sql` - one-time SQL fixups against a legacy source DB.
- `one-offs/` - individual one-shot SQL snippets (see its README).

View File

@@ -0,0 +1 @@
"""Data migration scripts for VBScript ShopDB to Flask migration."""

View File

@@ -0,0 +1,88 @@
-- =============================================================================
-- Legacy Schema Migration Script
-- Adds missing columns to make VBScript ShopDB compatible with Flask ShopDB
-- =============================================================================
-- -----------------------------------------------------------------------------
-- appowners table
-- -----------------------------------------------------------------------------
ALTER TABLE appowners
ADD COLUMN IF NOT EXISTS email VARCHAR(100) NULL,
ADD COLUMN IF NOT EXISTS phone VARCHAR(50) NULL,
ADD COLUMN IF NOT EXISTS createddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifieddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS isactive TINYINT(1) DEFAULT 1;
-- -----------------------------------------------------------------------------
-- pctypes / computertypes alignment
-- -----------------------------------------------------------------------------
-- The Flask app uses pctype table but expects certain columns
ALTER TABLE pctype
ADD COLUMN IF NOT EXISTS createddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifieddate DATETIME DEFAULT NOW();
-- Ensure isactive is correct type
ALTER TABLE pctype MODIFY COLUMN isactive TINYINT(1) DEFAULT 1;
-- -----------------------------------------------------------------------------
-- statuses table (if needed - Flask uses assetstatuses)
-- -----------------------------------------------------------------------------
-- assetstatuses already populated earlier
-- -----------------------------------------------------------------------------
-- subnets table
-- -----------------------------------------------------------------------------
ALTER TABLE subnets
ADD COLUMN IF NOT EXISTS createddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifieddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS isactive TINYINT(1) DEFAULT 1;
-- -----------------------------------------------------------------------------
-- vlans table
-- -----------------------------------------------------------------------------
ALTER TABLE vlans
ADD COLUMN IF NOT EXISTS createddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifieddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS isactive TINYINT(1) DEFAULT 1;
-- -----------------------------------------------------------------------------
-- usbdevices table
-- -----------------------------------------------------------------------------
ALTER TABLE usbdevices
ADD COLUMN IF NOT EXISTS createddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifieddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS isactive TINYINT(1) DEFAULT 1;
-- -----------------------------------------------------------------------------
-- usbcheckouts table
-- -----------------------------------------------------------------------------
ALTER TABLE usbcheckouts
ADD COLUMN IF NOT EXISTS createddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifieddate DATETIME DEFAULT NOW();
-- -----------------------------------------------------------------------------
-- notifications table
-- -----------------------------------------------------------------------------
ALTER TABLE notifications
ADD COLUMN IF NOT EXISTS createddate DATETIME DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifieddate DATETIME DEFAULT NOW();
-- Copy dates from existing columns if they exist
UPDATE notifications SET createddate = startdate WHERE createddate IS NULL;
UPDATE notifications SET modifieddate = startdate WHERE modifieddate IS NULL;
-- -----------------------------------------------------------------------------
-- Verify key counts
-- -----------------------------------------------------------------------------
SELECT 'Migration complete. Record counts:' as status;
SELECT 'vendors' as tbl, COUNT(*) as cnt FROM vendors
UNION ALL SELECT 'models', COUNT(*) FROM models
UNION ALL SELECT 'machinetypes', COUNT(*) FROM machinetypes
UNION ALL SELECT 'operatingsystems', COUNT(*) FROM operatingsystems
UNION ALL SELECT 'businessunits', COUNT(*) FROM businessunits
UNION ALL SELECT 'applications', COUNT(*) FROM applications
UNION ALL SELECT 'machines', COUNT(*) FROM machines
UNION ALL SELECT 'printers', COUNT(*) FROM printers
UNION ALL SELECT 'assets', COUNT(*) FROM assets
UNION ALL SELECT 'knowledgebase', COUNT(*) FROM knowledgebase
UNION ALL SELECT 'notifications', COUNT(*) FROM notifications;

View File

@@ -0,0 +1,16 @@
# One-off migration scripts (historical)
These are hand-run SQL scripts kept for reference. They are NOT part of the
Alembic chain (`migrations/versions/`) and are not run by `flask db upgrade`. A
fresh install never needs them; they exist for databases that predate the
corresponding change.
- `add_recertification_type.sql` - inserts the blue "Recertification"
notification type into an already-existing database. Historical: the
notifications plugin now seeds this type on install
(`plugins/notifications/plugin.py`), so any fresh install already has it. Only
a pre-existing DB that was never re-installed needs this script. Idempotent.
A related one-off, widening `notifications.employeesso` / `employeename` to
TEXT, has been removed because it is fully superseded by Alembic migration
`7d02_widen_notification_employee_cols`.

View File

@@ -0,0 +1,21 @@
-- Recertification notification type (shopdb-flask)
--
-- Employee-photo type (blue, like recognition) for employees who must retake a
-- training course. The shopfloor feed splits it one card per employee and the
-- dashboard shows it in a blue "Recertification Required" carousel; the display
-- window is two weeks (computed server-side in the notifications API).
--
-- Idempotent - safe to re-run. The notifications plugin also seeds this type on
-- install (plugins/notifications/plugin.py); this file is for databases that
-- already exist and are not re-installed.
INSERT INTO notificationtypes (typename, typedescription, typecolor, isactive)
SELECT * FROM (
SELECT 'Recertification' AS typename,
'Employees due to retake a training course (shows two weeks)' AS typedescription,
'recertification' AS typecolor,
1 AS isactive
) AS t
WHERE NOT EXISTS (
SELECT 1 FROM notificationtypes WHERE typename = 'Recertification'
);