Feature work from the 2026-07 session: Settings IA - Replace the flat 27-card settings hub with a persistent two-pane shell (SettingsLayout.vue): grouped, searchable left rail + content pane. - Nest all settings/* routes under the shell via router post-processing; shared nav catalog in settingsNav.js. Group by asset class (PCs, Printers, Equipment, Network) so per-type settings stop scattering. Custom fields (core) - customfields + customfieldvalues tables (migration 7d14), CRUD API at /api/customfields, per-asset value get/save. - Settings management page + reusable CustomFieldsSection (detail) and CustomFieldsInputs (form) wired into all four asset types. Warranty (new plugin) - plugins/warranty: warranties + warrantyassets (migration 7d15), derived coverage status, provider abstraction (manual now; Dell/Lenovo/HP stubs). - API CRUD + per-asset panel + report buckets; WarrantyPanel on all four detail pages; Warranties management page; Warranty report + Reports card. - Seed warranty.* permissions. Printer drivers - printerdrivers table (migration 7d13) linked to printer models; drivers now surface on the matching printer's detail page. Other - PCDetail rebalanced (Network + Status + Warranty + custom fields on the right). - Rename PCs list "Features" column to "Remote Access"; fix badge hover underline. - Drop equipment islocationonly field. - Centralize asset-type label/route maps into utils/assetTypes.js. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
181 lines
7.2 KiB
Markdown
181 lines
7.2 KiB
Markdown
# Deploy shopdb-flask to Windows IIS (MySQL 5.6)
|
|
|
|
Runbook for standing up a single-site instance on the production Windows Server
|
|
that already runs the classic ASP shopdb, using IIS + HttpPlatformHandler +
|
|
waitress, against the existing MySQL 5.6. This is the test-instance path; keep
|
|
developing on the Linux dev box and redeploy as needed.
|
|
|
|
The Docker path in `DEPLOY.md` does NOT apply on Windows (gunicorn is Linux
|
|
only, and there is no MySQL container here). This file replaces it for IIS.
|
|
|
|
Notation: `APP_ROOT` = the deploy folder, e.g. `C:\shopdb-flask`. The IIS site
|
|
physical path must be `APP_ROOT` (where `wsgi.py` lives).
|
|
|
|
## 0. Prerequisites on the box
|
|
|
|
- Python 3.12 (same minor as dev). `py -3.12 --version` to confirm.
|
|
- IIS with the **HttpPlatformHandler** module:
|
|
https://www.iis.net/downloads/microsoft/httpplatformhandler
|
|
- **URL Rewrite** module (only for the optional real-client-IP rule).
|
|
- Network access to the MySQL 5.6 server.
|
|
- If the box is air-gapped, you cannot `pip install` live. On the dev box run
|
|
`pip download -r requirements.txt waitress -d wheels\` (on a matching
|
|
Windows/Python target, or use `--platform` wheels), copy `wheels\` over, and
|
|
install with `pip install --no-index --find-links wheels\ ...`.
|
|
|
|
## 1. Copy the code
|
|
|
|
Copy the repo to `APP_ROOT`, INCLUDING `frontend/dist` (the built SPA the API
|
|
serves). Build it on dev first if stale:
|
|
|
|
```bash
|
|
# on the dev box
|
|
cd frontend && npm run build # produces frontend/dist
|
|
```
|
|
|
|
Ship `frontend/dist` with the code (Node is not needed on the prod box).
|
|
|
|
## 2. Python venv + dependencies
|
|
|
|
```powershell
|
|
cd C:\shopdb-flask
|
|
py -3.12 -m venv venv
|
|
venv\Scripts\python -m pip install --upgrade pip
|
|
venv\Scripts\pip install -r requirements.txt
|
|
venv\Scripts\pip install waitress
|
|
```
|
|
|
|
The DB driver is `pymysql` (pure Python) so no C compiler / MySQL client libs
|
|
are needed. `waitress` is the WSGI server (installed separately, same as the
|
|
Docker image installs gunicorn separately).
|
|
|
|
## 3. Prepare MySQL 5.6 (the utf8mb4 gotcha)
|
|
|
|
MySQL 5.6 defaults cannot index utf8mb4 VARCHAR(255) columns (767-byte prefix
|
|
limit) and often defaults the server charset to latin1. The schema is utf8mb4,
|
|
so the server needs Barracuda + large-prefix, made durable in `my.ini` under
|
|
`[mysqld]`, then restart the MySQL service:
|
|
|
|
```ini
|
|
[mysqld]
|
|
innodb_file_per_table = 1
|
|
innodb_file_format = Barracuda
|
|
innodb_large_prefix = 1
|
|
```
|
|
|
|
Then create the database as utf8mb4 and a least-privilege app user:
|
|
|
|
```sql
|
|
CREATE DATABASE shopdb_flask CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
CREATE USER 'shopdb'@'%' IDENTIFIED BY 'CHANGE_ME';
|
|
GRANT ALL PRIVILEGES ON shopdb_flask.* TO 'shopdb'@'%';
|
|
FLUSH PRIVILEGES;
|
|
```
|
|
|
|
Without the `[mysqld]` flags, `flask db upgrade` fails with error 1071
|
|
("Specified key was too long"). The migration chain emits `ROW_FORMAT=DYNAMIC`
|
|
per table (see `migrations/env.py`), which fits the 3072-byte prefix those
|
|
flags unlock.
|
|
|
|
## 4. Configure secrets and connection (.env)
|
|
|
|
Create `APP_ROOT\.env` (loaded by `wsgi.py` via `load_dotenv()`). Keep secrets
|
|
here, not in `web.config`. Lock the file's ACLs to the IIS app-pool identity +
|
|
administrators.
|
|
|
|
```
|
|
FLASK_ENV=production
|
|
SECRET_KEY=<64+ random chars>
|
|
JWT_SECRET_KEY=<another 64+ random chars>
|
|
DATABASE_URL=mysql+pymysql://shopdb:CHANGE_ME@<mysql-host>:3306/shopdb_flask?charset=utf8mb4
|
|
CORS_ORIGINS=https://<the site's own hostname>
|
|
```
|
|
|
|
`ProductionConfig.validate()` refuses to boot if any of `SECRET_KEY`,
|
|
`JWT_SECRET_KEY`, `DATABASE_URL`, `CORS_ORIGINS` is missing or left at a dev
|
|
default. `CORS_ORIGINS` is the browser origin users hit (the IIS binding).
|
|
|
|
Generate a key: `venv\Scripts\python -c "import secrets;print(secrets.token_urlsafe(64))"`.
|
|
|
|
## 5. Initialize schema, data, plugins, admin
|
|
|
|
Run from `APP_ROOT` with the venv active and `.env` present:
|
|
|
|
```powershell
|
|
$env:FLASK_APP="shopdb"
|
|
venv\Scripts\flask db upgrade
|
|
venv\Scripts\flask seed reference-data
|
|
|
|
# Enable the plugins this site tracks (registry lives in the gitignored
|
|
# instance/plugins.json, so a fresh box starts with none enabled):
|
|
venv\Scripts\flask plugin list
|
|
venv\Scripts\flask plugin install computers
|
|
venv\Scripts\flask plugin install equipment
|
|
venv\Scripts\flask plugin install network
|
|
venv\Scripts\flask plugin install notifications
|
|
venv\Scripts\flask plugin install printers
|
|
venv\Scripts\flask plugin install usb
|
|
venv\Scripts\flask plugin install knowledgebase
|
|
venv\Scripts\flask plugin install slides
|
|
venv\Scripts\flask plugin install employees
|
|
|
|
# First admin (password is generated and printed once):
|
|
venv\Scripts\flask seed admin --username admin --email admin@yourfacility.example.com
|
|
```
|
|
|
|
(Alternatively copy the dev box's `instance/plugins.json` to `APP_ROOT\instance\`
|
|
to reproduce the exact enabled set, then just run `flask plugin upgrade-all`.)
|
|
|
|
## 6. Create the IIS site + web.config
|
|
|
|
1. In IIS Manager, add a new **Site** (separate from the classic ASP site):
|
|
- Physical path: `APP_ROOT`
|
|
- Binding: a free port or a dedicated hostname (e.g. `https` 443 with the
|
|
facility cert, or `http` on a test port like 8081 to start).
|
|
- App pool: No Managed Code, and an identity that can read `APP_ROOT`.
|
|
2. Copy `deploy\windows\web.config` to `APP_ROOT\web.config` and edit the paths
|
|
(`C:\shopdb-flask` -> your `APP_ROOT`). It launches
|
|
`waitress-serve --port=%HTTP_PLATFORM_PORT% wsgi:app` and sets
|
|
`FLASK_ENV=production` + `PYTHONPATH`.
|
|
3. Create `APP_ROOT\logs` for the HttpPlatform stdout log.
|
|
4. Recycle the app pool / restart the site.
|
|
|
|
TLS terminates at the IIS binding. The optional URL Rewrite rule in the
|
|
web.config sets `X-Forwarded-For` to the real client IP (HttpPlatformHandler
|
|
otherwise forwards from loopback, so audit logs and the kiosk visitor-location
|
|
feature would see 127.0.0.1). Drop that block if URL Rewrite is not installed.
|
|
|
|
## 7. Smoke test
|
|
|
|
```powershell
|
|
# SPA loads:
|
|
curl.exe -k https://<host>/ # returns index.html
|
|
# API rejects an empty login with a validation error (health signal):
|
|
curl.exe -k -X POST https://<host>/api/auth/login -H "Content-Type: application/json" -d "{}"
|
|
# expect JSON containing VALIDATION_ERROR
|
|
```
|
|
|
|
Then log in through the browser as the admin from step 5 and confirm the
|
|
dashboard renders.
|
|
|
|
## 8. Redeploying as dev advances
|
|
|
|
Because this is a test instance you keep iterating on:
|
|
|
|
1. Pull/copy new code to `APP_ROOT` (rebuild `frontend/dist` on dev if the UI
|
|
changed).
|
|
2. `venv\Scripts\pip install -r requirements.txt` (if deps changed).
|
|
3. `venv\Scripts\flask db upgrade` (if new migrations).
|
|
4. Recycle the app pool.
|
|
|
|
## Troubleshooting
|
|
|
|
| Symptom | Cause / fix |
|
|
|---|---|
|
|
| Site 502 / process won't start | Check `APP_ROOT\logs\httpplatform*`. Usually a bad `processPath`, missing waitress, or `wsgi:app` not importable (set `PYTHONPATH`). |
|
|
| Boots but SQL echoes / debug on | `FLASK_ENV` not `production` (web.config env var or `.env`). |
|
|
| `flask db upgrade` error 1071 | MySQL 5.6 `[mysqld]` flags in step 3 not applied / server not restarted. |
|
|
| ConfigError on boot | A required var (SECRET_KEY / JWT_SECRET_KEY / DATABASE_URL / CORS_ORIGINS) missing or left at a dev default in `.env`. |
|
|
| Login works, CORS errors in browser | `CORS_ORIGINS` does not match the exact origin (scheme + host + port) the browser used. |
|
|
| Audit logs show 127.0.0.1 | Expected without the URL Rewrite X-Forwarded-For rule (step 6). |
|