The map was one picture of one floor. A second floor was added, the blueprint changed size, and machines moved, so a position now records WHICH DRAWING its coordinates belong to. Buildings and levels (ADR-017). Each level owns its blueprint per theme and its own native pixel size; assets.mapx/mapy are pixels of assets.levelid, not of the site. A position whose level is unknown renders "level unknown" and is never drawn on the default level, because a marker on the wrong floor plan looks entirely correct while pointing at the wrong place. Repositioning in bulk: filter by unplaced, needs-review or level, search, place, confirm. Landmark recalibration solves the transform PER AXIS from landmark pairs and never from image dimensions - the canvas grew taller without rescaling, so a dimension-derived scale would stretch Y by 1.57 and be wrong everywhere. It defaults to a dry run, reports what would land off the drawing, snapshots before applying, and clears mapverifiedat because a transform is a guess awaiting review. Snapshots restore, including the level and the review state, and a restore snapshots first so an undo is undoable. Search: gaugelabreference was matched only for measuring tools and maintenancereference was matched nowhere at all, for any asset type, while Settings happily offers both identifiers on machines and PCs. A tag an operator is told to record has to be findable or it is a write-only field. USB devices and printed items were unreachable from search entirely - neither is an asset, so the generic asset search could not see them and no searcher existed; they now match on serial, asset tag, label, bin code and gage-lab tag, honouring isactive, with Settings toggles and result labels to match. The retired-application rule was half a rule: GET /api/knowledgebase hid articles whose topic application is retired while global search still returned them and printed the retired application as the subject. A filter is only real if every path that reaches the row applies it. Contract to 0.20.0 (additive): Asset gained levelid and mapverifiedat, Location gained levelid, and resolve_asset_position returns the levelid belonging to whichever source supplied the coordinates. The five plugins that write a map position are re-pinned. The install-list text format gained levelid as a NINTH field, appended, because the shipped Pascal installer reads fields 0-7 by index. That installer still compiles in one drawing's dimensions and bundles one blueprint, so its map is accurate for the default level only; /api/maplevels is deliberately unauthenticated so it can read both at runtime once rebuilt. Recorded in PRINTER-INSTALLER.md section 6 along with the other known gaps. Migration 7d33 converts an existing single-map site into one building and one default level carrying the old map_* settings, then assigns every placed asset and location to it. Nothing moves on screen. Old settings rows are kept so a rollback still finds them. Verified end to end on MySQL 5.6 from a production-shaped database.
294 lines
11 KiB
Markdown
294 lines
11 KiB
Markdown
# ShopDB Flask
|
|
|
|
A modern rewrite of the classic ASP/VBScript ShopDB application using Flask (Python) and Vue 3. This application manages shop floor machines, PCs, printers, applications, and related infrastructure for manufacturing environments.
|
|
|
|
## Overview
|
|
|
|
ShopDB tracks and manages:
|
|
- **Machines** - CNC equipment, CMMs, inspection systems, etc.
|
|
- **PCs** - Shopfloor computers, engineering workstations
|
|
- **Printers** - Network printers with Zabbix supply integration
|
|
- **Network devices** - Switches, routers, and the subnet browser
|
|
- **Measuring tools** - Gage-lab instruments with calibration tracking
|
|
- **Applications** - Software deployed across the shop floor, with per-PC install tracking
|
|
- **Employees** - Directory, recognition and training notifications
|
|
- **Warranties** - Coverage records with Dell warranty lookups
|
|
- **USB devices** - CMMC check-in/out tracking
|
|
- **Knowledge Base** - Documentation and troubleshooting guides
|
|
- **GE-Enforce manifests** - Imaging/software manifest editing and fleet compliance
|
|
|
|
## Tech Stack
|
|
|
|
**Backend:**
|
|
- Python 3.14 with Flask
|
|
- SQLAlchemy ORM
|
|
- MySQL 5.7+ database (5.6 works with extra utf8mb4 config; see docs/DEPLOY.md)
|
|
- JWT authentication
|
|
- Plugin architecture for extensibility
|
|
|
|
**Frontend:**
|
|
- Vue 3 with Composition API
|
|
- Vue Router for navigation
|
|
- Pinia for state management
|
|
- Vite build system
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
shopdb-flask/
|
|
+-- shopdb/ # Flask application
|
|
| +-- core/
|
|
| | +-- api/ # REST API endpoints
|
|
| | +-- models/ # SQLAlchemy models
|
|
| | +-- schemas/ # Validation schemas
|
|
| | `-- services/ # Business logic
|
|
| +-- plugins/ # Plugin system
|
|
| `-- utils/ # Shared utilities
|
|
+-- frontend/ # Vue 3 application
|
|
| +-- src/
|
|
| | +-- api/ # API client
|
|
| | +-- components/ # Reusable components
|
|
| | +-- views/ # Page components
|
|
| | +-- router/ # Route definitions
|
|
| | `-- stores/ # Pinia stores
|
|
| `-- public/ # Static assets
|
|
+-- plugins/ # Bundled and external plugins
|
|
+-- migrations/ # Alembic migration chain (flask db upgrade)
|
|
+-- scripts/ # Import and utility scripts
|
|
`-- tests/ # Test suite
|
|
```
|
|
|
|
## Naming Conventions
|
|
|
|
To maintain consistency with the legacy ShopDB database and codebase, the following naming standards apply:
|
|
|
|
### Database
|
|
|
|
- **Table names:** Lowercase, single word, no underscores or dashes
|
|
- Examples: `assets`, `computers`, `printers`, `businessunits`
|
|
- **Column names:** Lowercase, single word, no underscores or dashes
|
|
- Examples: `assetid`, `assetnumber`, `hostname`, `isactive`, `createddate`
|
|
- **Foreign keys:** Referenced table name + `id`
|
|
- Examples: `locationid`, `vendorid`, `modelnumberid`, `computertypeid`
|
|
- **Boolean columns:** Prefixed with `is` or `has`
|
|
- Examples: `isactive`, `isshopfloor`, `iscolor`, `isdhcp`, `islicenced`
|
|
|
|
### Code
|
|
|
|
- **Python variables:** Follow database naming where applicable (lowercase, no underscores for model fields)
|
|
- **JavaScript variables:** camelCase for local variables, but match API field names from backend
|
|
- **Vue components:** PascalCase for component names
|
|
- **CSS classes:** Lowercase with dashes for multi-word classes
|
|
|
|
### API
|
|
|
|
- **Endpoints:** Lowercase, plural nouns
|
|
- Examples: `/api/machines`, `/api/computers`, `/api/locations`
|
|
- **Query parameters:** Lowercase, single word
|
|
- Examples: `?locationid=5`, `?isactive=true`, `?assettype=computer`
|
|
|
|
## Style Guidelines
|
|
|
|
- No emojis in code, comments, documentation, or UI
|
|
- Keep UI functional and professional
|
|
- Dark theme is the default
|
|
- Consistent table layouts across all list views
|
|
|
|
## Setup
|
|
|
|
### Prerequisites
|
|
|
|
- Python 3.14
|
|
- Node.js 18+
|
|
- MySQL 5.7+ (5.6 works with extra utf8mb4 config; see docs/DEPLOY.md)
|
|
|
|
ShopDB Flask uses MySQL as the canonical database. SQLite is used only for the
|
|
test suite (`TestingConfig` in `shopdb/config.py` points at an in-memory
|
|
SQLite). Do not run dev or production against SQLite.
|
|
|
|
### Distribution
|
|
|
|
Source lives here. The Windows installer ships as a release asset rather than a
|
|
file in the repository - it is around 240 MB, well past what a repository takes
|
|
and well inside what a release asset does. There is no package or image
|
|
registry; a site installs from that `.exe` or builds from source.
|
|
|
|
### Fast path (Docker)
|
|
|
|
The Docker image builds the Vue frontend and serves it from the API container,
|
|
so a container deploy needs no separate Node build step.
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# Edit .env: set SECRET_KEY, JWT_SECRET_KEY, DATABASE_URL, CORS_ORIGINS,
|
|
# and the MYSQL_* passwords (see docs/CONFIG.md for every variable).
|
|
|
|
docker compose up -d --build
|
|
|
|
# Create the schema and seed the platform data (idempotent, safe to re-run):
|
|
docker compose exec api flask db upgrade
|
|
docker compose exec api flask seed permissions
|
|
docker compose exec api flask seed settings
|
|
docker compose exec api flask seed reference-data
|
|
```
|
|
|
|
Then browse to the site and complete the first-run setup wizard at `/setup`
|
|
(it creates the first admin account and captures site identity). To create the
|
|
admin headlessly instead of using the wizard:
|
|
|
|
```bash
|
|
docker compose exec api flask seed admin --username admin --email admin@facility.example.com
|
|
```
|
|
|
|
### Manual path (venv + Node)
|
|
|
|
```bash
|
|
# Backend
|
|
python -m venv venv
|
|
source venv/bin/activate
|
|
pip install -r requirements.txt
|
|
cp .env.example .env
|
|
# Edit .env with your database credentials and secrets.
|
|
|
|
export FLASK_APP=shopdb
|
|
flask db upgrade
|
|
flask plugin upgrade-all # per-plugin schema (ADR-008)
|
|
flask seed permissions
|
|
flask seed settings
|
|
flask seed reference-data
|
|
flask run --port 5001 # MUST be 5001 - the frontend dev server proxies here
|
|
|
|
# Frontend (separate terminal)
|
|
cd frontend
|
|
npm install
|
|
npm run dev # dev server on :5173
|
|
npm run build # production build into frontend/dist (served by Flask)
|
|
```
|
|
|
|
Complete first-run setup at `/setup`, or run `flask seed admin` for a headless
|
|
admin account. The repo ships VS Code config in `.vscode/` (F5 debugs the
|
|
backend; a "Dev site" task runs both servers). A fuller day-one walkthrough,
|
|
including VS Code and troubleshooting, is the DEVELOPMENT-SETUP page in the
|
|
project wiki.
|
|
|
|
To import a site's legacy data, use the HTTP import surface: an admin API
|
|
token plus [docs/IMPORT-API.md](docs/IMPORT-API.md) drive the whole migration
|
|
through documented endpoints (`X-Import-Mode` preserves original timestamps).
|
|
`scripts/site_imports/wjf/` is the reference site's loader, kept as a worked
|
|
example of the whole sequence.
|
|
|
|
### Which deployment route
|
|
|
|
| Target | Use |
|
|
|---|---|
|
|
| **Windows Server + IIS** (how sister sites run) | **[docs/INSTALL-WINDOWS.md](docs/INSTALL-WINDOWS.md)** - one installer `.exe`, offline, no manual IIS work. Day 2: [docs/OPERATE-WINDOWS.md](docs/OPERATE-WINDOWS.md) |
|
|
| Linux / Docker, air-gapped | [docs/DEPLOY-AIRGAP.md](docs/DEPLOY-AIRGAP.md) |
|
|
| Linux / Docker, connected | [docs/DEPLOY.md](docs/DEPLOY.md) |
|
|
|
|
For every environment variable and Setting key see [docs/CONFIG.md](docs/CONFIG.md).
|
|
|
|
### What the Windows installer requires
|
|
|
|
The installer checks all of this before it changes anything and refuses rather
|
|
than half-installing.
|
|
|
|
| | Minimum | Notes |
|
|
|---|---|---|
|
|
| Windows Server | **2019** (build 10.0.17763) | Ships **IIS 10.0**, which is therefore the earliest IIS supported. Server 2016 is also IIS 10.0 but falls below the build floor and is refused. |
|
|
| Windows client (test boxes) | **10 22H2** (build 10.0.19045) or 11 | **Pro or higher** - Home has no IIS at all. |
|
|
| Architecture | 64-bit | The payload is cp314 win_amd64. |
|
|
| IIS Web Server role | installed beforehand | `Install-WindowsFeature -Name Web-Server -IncludeManagementTools`. Needs no internet. |
|
|
| Free disk | 5 GB | Refused below this. 40 GB is comfortable once uploads and config backups accumulate. |
|
|
| Database | bundled MySQL 8.4 LTS, or your own | Bring credentials if you use an existing server. |
|
|
|
|
The binding constraint is the operating system rather than IIS: the payload is
|
|
Python 3.14 plus HttpPlatformHandler and URL Rewrite, and the handler itself runs
|
|
on older IIS. An older host is untested rather than known-broken.
|
|
|
|
If you must deploy onto something older, [docs/INSTALL-WINDOWS-IIS.md](docs/INSTALL-WINDOWS-IIS.md)
|
|
is the manual procedure and has no OS gate - it even documents MySQL 5.6, which is
|
|
that era of machine. The trade is stated there: it produces a server the
|
|
installer will not subsequently upgrade.
|
|
|
|
## Configuration
|
|
|
|
Environment variables (`.env`):
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `DATABASE_URL` | MySQL connection string |
|
|
| `SECRET_KEY` | Flask secret key |
|
|
| `JWT_SECRET_KEY` | JWT signing key |
|
|
| `JWT_ACCESS_TOKEN_EXPIRES` | Access token TTL (seconds) |
|
|
| `LOG_LEVEL` | Logging verbosity |
|
|
|
|
## API Documentation
|
|
|
|
The REST API follows standard conventions:
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/api/machines` | List machines (filterable by type) |
|
|
| GET | `/api/machines/:id` | Get machine details |
|
|
| POST | `/api/machines` | Create machine |
|
|
| PUT | `/api/machines/:id` | Update machine |
|
|
| DELETE | `/api/machines/:id` | Soft delete machine |
|
|
|
|
Each asset plugin exposes the same CRUD pattern on its own prefix
|
|
(`/api/computers`, `/api/printers`, `/api/network`, `/api/measuringtools`),
|
|
and cross-cutting asset endpoints live under `/api/assets`.
|
|
|
|
Query parameters for list endpoints:
|
|
- `page` - Page number (default: 1)
|
|
- `perpage` - Items per page
|
|
- `sort` - Sort field
|
|
- `dir` - Sort direction (asc/desc)
|
|
- `search` - Search term
|
|
- `assettype` - Filter by asset type (computer, printer, machine, networkdevice, measuringtool)
|
|
|
|
## Where to start
|
|
|
|
[docs/START-HERE.md](docs/START-HERE.md) routes by what you are here to do -
|
|
standing up a site, deploying the shop-floor tools, writing a plugin,
|
|
integrating with the API, or diagnosing something. On the published mirror the
|
|
same page is the wiki's front door.
|
|
|
|
## Plugin System
|
|
|
|
ShopDB supports plugins for extending functionality. See `CONTRIBUTING.md` for plugin development guidelines.
|
|
|
|
The image bundles these plugins; only the ones a site installs are loaded. The
|
|
current count and each plugin's version and migration head are in
|
|
[docs/PROJECT-MAP.md](docs/PROJECT-MAP.md), which is generated:
|
|
|
|
- **backups** - Machine configuration backups (NTLARS/DNC, CMM, part marker, UDC) with revision history and diffs
|
|
- **computers** - Shopfloor PCs and workstations, collector fleet ingest
|
|
- **employees** - Employee directory
|
|
- **geenforce** - GE-Enforce imaging/software manifests and fleet compliance
|
|
- **machines** - CNC, CMM, and other shop-floor machines
|
|
- **measuringtools** - Gage-lab instruments with calibration tracking
|
|
- **knowledgebase** - Documentation and troubleshooting guides
|
|
- **network** - Network devices and subnets
|
|
- **notifications** - Shopfloor notifications and recognition feed
|
|
- **printedparts** - 3D-printed part catalogue, kiosk issue tracking and stock alerts
|
|
- **printers** - Extended printer management with Zabbix integration
|
|
- **slides** - TV/kiosk slideshows
|
|
- **tools** - Tech Tools: barcode and QR generation laid out for real label stock
|
|
- **usb** - CMMC USB check-in/out tracking
|
|
- **warranty** - Warranty records with Dell lookups
|
|
|
|
## Legacy Migration
|
|
|
|
This project replicates functionality from the classic ASP/VBScript ShopDB site. Key mappings:
|
|
|
|
| Legacy | Modern |
|
|
|--------|--------|
|
|
| ASP/VBScript | Flask/Python |
|
|
| Classic ADO | SQLAlchemy |
|
|
| Server-side HTML | Vue 3 SPA |
|
|
| Session auth | JWT tokens |
|
|
|
|
## License
|
|
|
|
Internal use only.
|