Add custom fields + warranty plugin, rework settings into two-pane shell
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>
This commit is contained in:
180
docs/DEPLOY-WINDOWS-IIS.md
Normal file
180
docs/DEPLOY-WINDOWS-IIS.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# 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). |
|
||||
Reference in New Issue
Block a user