Running & packaging Schedy on Windows¶
Schedy is cross-platform — every dependency (OR-Tools, FastAPI, uvicorn, openpyxl, reportlab, SQLite) ships Windows wheels, and the React frontend is OS-agnostic. This page covers two things:
- Running it on a developer's Windows machine (conda + Node).
- Packaging a one-click app for a non-technical planner — a single
.exethat needs neither Python, conda, nor Node installed.
The key idea for both: FastAPI serves the built frontend itself, so the planner runs one process and opens a browser. No Node at runtime.
1. Run on a Windows dev machine¶
Install Miniforge and Node 20+.
# from the repo root (PowerShell)
conda env create -f environment.yml
conda activate schedy
pip install -e backend
# build the frontend once -> frontend/dist
cd frontend
npm install
npm run build
cd ..
# run single-process: FastAPI serves API + the built SPA
$env:SCHEDY_STATIC = "frontend\dist"
uvicorn schedy.api:create_app --factory --app-dir backend --port 8000
# open http://localhost:8000
For active frontend development use two processes instead (Vite proxies /api):
uvicorn schedy.api:create_app --factory --app-dir backend --port 8000
# in another terminal:
cd frontend; npm run dev # http://localhost:5173
How the API base is resolved. In dev the frontend calls
/api/*and Vite proxies to the backend. The production build (frontend/.env.productionsetsVITE_API_BASE=) calls the same origin that serves it, so no proxy is needed.
2. Package a one-click .exe (recommended: PyInstaller)¶
This produces a self-contained folder the planner can copy and double-click.
backend/launcher.py is the entry point: it starts the server, serves the
bundled SPA, opens the browser, and stores the catalog under
%APPDATA%\Schedy\schedy.sqlite.
Build steps (on a Windows machine, in the schedy env)¶
conda activate schedy
pip install -e backend
pip install pyinstaller
# 1. Build the frontend
cd frontend; npm install; npm run build; cd ..
# 2. Bundle backend + built frontend into one folder
pyinstaller backend\launcher.py ^
--name Schedy ^
--collect-all ortools ^
--collect-all reportlab ^
--collect-submodules uvicorn ^
--add-data "frontend\dist;dist" ^
--noconfirm
Notes on the flags:
--collect-all ortools— OR-Tools ships native binaries and data the analysis step misses; this grabs them. (Same reason forreportlab.)--collect-submodules uvicorn— uvicorn imports its workers/loops lazily.--add-data "frontend\dist;dist"— bundles the built SPA;launcher.pyreads it fromsys._MEIPASS\dist. The;separator is Windows-specific (use:on macOS/Linux).- Add
--noconsoleonce stable to hide the terminal window (keep the console while testing so you can see errors).
The result is dist\Schedy\Schedy.exe plus its dependency folder. Zip
dist\Schedy\ and hand it over. The planner double-clicks Schedy.exe; a browser
opens at http://127.0.0.1:8000.
Optional: a desktop shortcut / launcher¶
Create Schedy.bat next to the exe if you prefer a visible launcher:
@echo off
start "" "%~dp0Schedy.exe"
3. Alternative: conda env + .bat (no PyInstaller)¶
Simpler to produce, but the target machine needs Miniforge installed. Ship the repo + a launcher:
@echo off
call conda activate schedy
set SCHEDY_STATIC=%~dp0frontend\dist
start "" http://localhost:8000
uvicorn schedy.api:create_app --factory --app-dir "%~dp0backend" --port 8000
Known gaps to address before shipping to end users¶
- Hebrew text in PDF export. The current
reportlabexport uses Helvetica, which cannot render Hebrew glyphs (a gap on every OS, not just Windows). Before relying on PDF, embed a Hebrew-capable TTF (e.g. Noto Sans Hebrew) and apply RTL shaping. CSV and the on-screen grid are unaffected. - Port already in use. If
8000is taken, setSCHEDY_PORTbefore launch. - Antivirus / SmartScreen. Unsigned PyInstaller exes may trigger SmartScreen on first run. For wide distribution, code-sign the executable.
- Catalog location. Data lives at
%APPDATA%\Schedy\schedy.sqlite. Document this for backups; deleting it resets the catalog.
Cross-platform packaging note¶
PyInstaller is not a cross-compiler — build the Windows artifact on Windows
(a Windows VM or CI runner is fine). The same launcher.py + --add-data recipe
produces a macOS/Linux bundle when run on those platforms (swap ; for :).