This guide covers local development, executable builds, and installer builds.
- Windows
- Python 3.10+
- TWAIN-compatible scanner and driver for real scan testing
- Inno Setup for installer builds
- Optional:
mkcert.exein the project root for trusted localhost HTTPS support
Install Python dependencies:
pip install -r requirements.txtRun from source:
python main.pyGenerate trusted localhost certificates and exit:
python main.py --generate-sslRun the test suite:
python -m unittest discover -s tests -t . -vThe unit tests cover server, worker, protocol, scanner-profile, scan lifecycle, result retrieval, and shutdown behavior.
After each x86/x64 installer is compiled in GitHub Actions,
tests/windows_install_smoke.ps1 silently installs it on the Windows runner and
checks installed assets, the Start menu shortcut, HKCU startup and scanlink://
registration, packaged version/architecture, live REST responses, protocol
launch, and graceful shutdown.
Regenerate the icon assets:
python generate_icon.pyThis creates:
app_icon.pngapp_icon.ico
Use build_exe.py to create PyInstaller one-file executables.
Build both x86 and x64 when matching Python interpreters are configured:
python build_exe.py --arch both --python-x64 C:\Python310\python.exe --python-x86 C:\Python310-32\python.exeBuild only the current Python architecture:
python build_exe.py --arch currentBuild x86 only:
python build_exe.py --arch x86 --python-x86 C:\Python310-32\python.exeDry run:
python build_exe.py --arch current --dry-runOutputs are written to dist/:
dist/ScanLink_<version>_<arch>.exe
The version comes from the VERSION file.
If mkcert.exe exists in the project root, build_exe.py bundles it into the PyInstaller executable.
Without mkcert.exe:
- HTTP scanning still works.
- HTTPS is unavailable until certificates are provided another way.
The installer is defined in setup.iss.
Compile with Inno Setup:
ISCC /DMyAppArch=x64 setup.iss
ISCC /DMyAppArch=x86 setup.issInstaller outputs:
ScanLinkSetup_<version>_<arch>.exe
The installer:
- Installs per user under
%LOCALAPPDATA%\Programs\ScanLink. - Registers the
scanlink://protocol underHKCU. - Optionally registers ScanLink at Windows startup under
HKCU. - Installs
static/scanlink.js. - Removes local config/log/certificate files on uninstall.
- Update
VERSION. - Update
CHANGELOG.md. - Run tests.
- Build x86 and x64 executables.
- Compile x86 and x64 installers.
- Install on a Windows test machine.
- Verify tray launch,
/health, scanner selection, scan result download, protocol launch, and uninstall cleanup. - Test both HTTP and HTTPS behavior when certificates are present.
GitHub Actions handles steps 3–6 automatically, including an installed-app smoke test for both architectures:
.github/workflows/ci.ymlruns on every push/PR tomainorbeta: it runs the unit tests (python -m unittest discover -s tests -t . -v) and verifies that both the x86 and x64 executable and installer build viabuild_exe.pyandsetup.iss. Each installer must then passtests/windows_install_smoke.ps1. Inno Setup is provisioned on the runner withchoco install innosetup; the 32/64-bit split comes fromactions/setup-python's architecture matrix..github/workflows/release.ymlruns on a pushedv*tag: it runs the same unit-test command and blocks both builds unless that test job passes, verifies the tag equals theVERSIONfile, builds and smoke-tests both installers, and publishes a GitHub Release with notes from the matching## vX.Y.ZCHANGELOG.mdsection. No secrets are required — it uses the built-inGITHUB_TOKEN.
To cut a release: set VERSION to X.Y.Z, add the matching ## vX.Y.Z
CHANGELOG.md section, commit, then:
git tag -a vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.ZPhysical tray visibility, real TWAIN source discovery/acquisition, generated PDF quality, HTTPS certificate trust, and uninstall cleanup still require a Windows test machine with the target scanner and driver.
Check health:
Invoke-RestMethod http://127.0.0.1:5000/healthStart a scan:
Invoke-RestMethod `
-Uri http://127.0.0.1:5000/scan `
-Method Post `
-ContentType "application/json" `
-Body '{"doc_id":"DOC-123"}'Poll status:
Invoke-RestMethod http://127.0.0.1:5000/scan/<job_id>Download result:
Invoke-WebRequest `
-Uri http://127.0.0.1:5000/scan/<job_id>/result `
-OutFile scan.pdfOpen a protocol link:
Start-Process "scanlink://scan?docId=DOC-123"