Roughly 2500 lines of tested installer had been living in ~/Downloads and an untracked folder - nothing was under version control. It goes here rather than in a repo of its own because it depends on application internals: the `flask plugin` verbs, site-profile.json, MOUNT_PATH, and the plugin registry. Versioned separately it would drift out of step with the thing it installs. Contents: the read-only preflight, the staged installer (bundled MySQL, runtime, schema, IIS, verify, uninstall), the operator console, the Inno Setup wizard, the bundle builder and the artwork generator. bundle/ and Output/ are ignored - regenerable, and ~220MB. plugins.iss is ignored because build-installer.sh generates it from the staged payload. The artwork IS committed so a Windows build box does not need Python and cairosvg. Verified end to end on Windows Server 2025 against a bundled MySQL 8.0 and an existing MySQL 5.6: fresh install, upgrade with backup and rollback, re-run idempotency, uninstall, and both deployment methods including switching between them. Not yet verified: a hypervisor-level air-gapped run, and any load from a real browser (every HTTP check so far used curl, which sends no Origin header).
84 lines
3.8 KiB
Markdown
84 lines
3.8 KiB
Markdown
# Windows installer
|
|
|
|
Builds a single self-contained `.exe` that installs ShopDB-Flask on an
|
|
**air-gapped** Windows Server. Nothing here ever touches the network at install
|
|
time: Python, the wheels, the SPA and (optionally) MySQL all ship inside it.
|
|
|
|
Lives with the application on purpose. The installer depends on app internals -
|
|
`flask plugin` verbs, `site-profile.json`, `MOUNT_PATH`, the plugin registry -
|
|
so a separate repo would drift out of step with the thing it installs.
|
|
|
|
## Files
|
|
|
|
| File | What it is |
|
|
|---|---|
|
|
| `shopdb-preflight.ps1` | Stage 1. Read-only. Changes nothing, reports what this server is missing. |
|
|
| `shopdb-install.ps1` | Stages 0 and 2-5 plus `uninstall`. All the actual work. |
|
|
| `shopdb-admin.ps1` | Operator console installed alongside the app: status, restart, logs, backup, plugins. |
|
|
| `ShopDBFlask.iss` | Inno Setup wizard. A thin wrapper - it collects input and runs the stages. |
|
|
| `build-installer.sh` | Stages the bundle from a site profile. |
|
|
| `make-branding.py` | Generates wizard artwork and the icon from `frontend/public/*.svg`. |
|
|
| `*.bmp`, `shopdb.ico` | Generated artwork, committed so a Windows build box needs no Python. |
|
|
|
|
## Building
|
|
|
|
```bash
|
|
# 1. Stage the bundle for a site's plugin set.
|
|
./build-installer.sh ../../site-profile.example.json
|
|
|
|
# 2. Add the pieces that cannot be built on Linux:
|
|
# bundle/wheels/ ~47 cp314 win_amd64 wheels, built ON Windows:
|
|
# pip download -r requirements.txt -d wheels --only-binary=:all:
|
|
# bundle/python/ python-3.14.x-amd64.exe
|
|
# bundle/httpplatformhandler/ httpPlatformHandler_amd64.msi
|
|
# bundle/mysql/ mysql-8.0.x-winx64.msi (bundled-database option only)
|
|
|
|
# 3. Compile on Windows.
|
|
iscc ShopDBFlask.iss
|
|
```
|
|
|
|
The wheelhouse is **cp314-locked**. A different Python minor version means a
|
|
different wheelhouse; the installer will not use a Python it did not install.
|
|
|
|
## Deployment methods
|
|
|
|
Chosen in the wizard, and the bundle carries a SPA build for each because Vite
|
|
compiles the base path in - it cannot be switched at install time.
|
|
|
|
- **Its own site** on a port (default 8090).
|
|
- **Subpath** under an existing site, e.g. `http://<server-fqdn>/shopdb/`. Needs
|
|
no new DNS record. Three things must agree - the IIS application alias,
|
|
`MOUNT_PATH` in `.env`, and the SPA's build-time base - so the alias is fixed
|
|
per bundle (`SUBPATH_ALIAS`, default `shopdb`) and the installer refuses if the
|
|
bundle's build does not match what was asked for.
|
|
|
|
Switching between methods removes the other one's IIS artifact and reconciles
|
|
`MOUNT_PATH` and `CORS_ORIGINS`, so a server never ends up with both.
|
|
|
|
## Upgrades
|
|
|
|
Run a newer installer over an existing install. It:
|
|
|
|
- backs the database up first, **verifies** the dump is complete, and refuses to
|
|
migrate if it cannot;
|
|
- restores from that backup if migrations fail, and reports honestly that DDL
|
|
the failed migration committed cannot be undone;
|
|
- refuses to run a bundle older than what is installed;
|
|
- keeps `.env` unless new credentials are supplied, and copies it aside first;
|
|
- stops the app pool before replacing files, then starts it again.
|
|
|
|
Whether a run is an upgrade is decided by probing the **target database**, not by
|
|
whether the app directory exists - a rebuilt server pointed at an existing
|
|
database is an upgrade, and treating it as fresh would drop tables.
|
|
|
|
## Testing notes
|
|
|
|
Verified end to end on Windows Server 2025 against both a bundled MySQL 8.0 and
|
|
an existing MySQL 5.6: fresh install, upgrade, re-run idempotency, failure and
|
|
rollback, uninstall, and both deployment methods including switching between
|
|
them.
|
|
|
|
**Not yet verified:** a fully air-gapped run with the network disabled at the
|
|
hypervisor, and any load in a real browser (all HTTP checks so far used curl,
|
|
which sends no `Origin` header - so `CORS_ORIGINS` is untested in anger).
|