# Development setup: from clone to first change The goal of this page: a new developer clones the repo and has a working dev site plus a change they can see in the browser, in one sitting. Reference material lives elsewhere - naming rules in `CONTRIBUTING.md`, every config variable in the CONFIG guide, plugin authoring in the PLUGIN docs - this is just the on-ramp. **Most developers here are on Windows in VS Code** - commands below are PowerShell first, with the bash equivalent in a comment where they differ. Install **Git for Windows** (it ships Git Bash, which VS Code and the git hooks use to run the shell-based naming check) and **VS Code** with the extensions this repo recommends (you'll be prompted - section 2c). Two ways to run it. **Docker** (Docker Desktop on Windows) is the fastest to a working site. **Manual (venv + Node)** is the daily driver - frontend hot-reloads, backend restarts on save. Do Docker once to confirm the box is sane, then use manual for day-to-day work. --- ## 0. Prerequisites | Need | Version | Check | | --- | --- | --- | | Python | 3.14 (64-bit) - matches CI, the container image and the Windows installer wheelhouse | `python --version` | | Node.js | 18+ | `node --version` | | MySQL | 8.0 (or Docker, below) | `mysql --version` | | Git | any recent | `git --version` | On Windows, install all of them with winget (accept each license, then reopen the terminal so PATH updates): ```powershell winget install Git.Git # includes Git Bash (naming hook needs it) winget install Python.Python.3.14 winget install OpenJS.NodeJS.LTS # LTS; may install v24, fine for this SPA winget install Microsoft.VisualStudioCode winget install Oracle.MySQL # or Docker.DockerDesktop for the DB ``` CI runs Node 20; the LTS package may be newer. This Vite/Vue frontend builds identically across 20-24, so it does not matter. To pin exactly: `winget install CoreyButler.NVMforWindows` then `nvm install 20; nvm use 20`. --- ## 0b. Corp network (SSL cert) - if you are behind a GE/Zscaler proxy A proxy that inspects HTTPS (Zscaler on GE PCs) re-signs every connection with a corporate root CA. `git`, `npm`, `pip`, and Node each keep their own trust store and do not trust that CA by default, so downloads fail: | Tool | Symptom | | --- | --- | | npm | `UNABLE_TO_GET_ISSUER_CERT_LOCALLY` | | git | `SSL certificate problem: unable to get local issuer certificate` | | pip | `SSLError` / `CERTIFICATE_VERIFY_FAILED` | Fix once - export the corp root CA, point every tool at it. PowerShell mangles multi-line pastes, so each step below is **one physical line**: paste it, press Enter, then the next. Do not paste both at once. ```powershell # 1) Bundle EVERY trusted root into one PEM (one line). Guessing which single cert is the proxy's is fragile; bundling all always includes it. $sb = New-Object System.Text.StringBuilder; Get-ChildItem Cert:\LocalMachine\Root | ForEach-Object { [void]$sb.AppendLine("-----BEGIN CERTIFICATE-----"); [void]$sb.AppendLine([Convert]::ToBase64String($_.RawData,'InsertLineBreaks')); [void]$sb.AppendLine("-----END CERTIFICATE-----") }; [IO.File]::WriteAllText("$HOME\corp-root-ca.pem", $sb.ToString()) ``` Confirm it has many certs (dozens, not 1): `(Select-String "BEGIN CERTIFICATE" $HOME\corp-root-ca.pem).Count` ```powershell # 2) Point every tool at it (one line, persistent). NODE_EXTRA_CA_CERTS also fixes Vite / npm run dev. git config --global http.sslCAInfo "$HOME\corp-root-ca.pem"; npm config set cafile "$HOME\corp-root-ca.pem"; setx NODE_EXTRA_CA_CERTS "$HOME\corp-root-ca.pem"; setx PIP_CERT "$HOME\corp-root-ca.pem" ``` Reopen the terminal so `setx` takes effect. Quick unblock if you cannot export right now (skips verification - use briefly, then set back): `npm config set strict-ssl false`, `git config --global http.sslVerify false`. --- ## 1. Get the code ```powershell git clone https://github.com/ge-aero/shopdb-flask.git cd shopdb-flask ``` Never work on `main`. Branch for your change: ```powershell git checkout -b feat/ ``` --- ## 2a. Fast path - Docker (a working site in one command) ```powershell copy .env.example .env # Edit .env: set SECRET_KEY, JWT_SECRET_KEY, and the MYSQL_* passwords. # Generate a secret: python -c "import secrets;print(secrets.token_urlsafe(64))" docker compose up -d --build # MySQL + the app (frontend built in-image) # Schema + platform data (idempotent, safe to re-run): docker compose exec api flask db upgrade docker compose exec api flask plugin upgrade-all docker compose exec api flask seed permissions docker compose exec api flask seed settings docker compose exec api flask seed reference-data docker compose exec api flask seed admin --username admin --email you@example.com docker compose exec api flask seed demo # OPTIONAL: sample data (undo: flask seed demo-clear) ``` The app is on the port the compose file maps (see `docker-compose.yml`). Good for a smoke test; for active development use the manual path so the frontend hot-reloads. --- ## 2b. Manual path - venv + Node (the daily driver) ### Database Either point at an existing MySQL 8, or bring one up with just the db service from compose: ```powershell docker compose up -d db # MySQL on 127.0.0.1:3306 ``` Create the database + app user (skip if compose already did via env): ```sql CREATE DATABASE shopdb_flask CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'shopdb'@'%' IDENTIFIED BY 'devpassword'; GRANT ALL PRIVILEGES ON shopdb_flask.* TO 'shopdb'@'%'; FLUSH PRIVILEGES; ``` ### Backend ```powershell python -m venv venv venv\Scripts\Activate.ps1 # bash/mac: source venv/bin/activate # If PowerShell blocks the activate script (execution policy), run once: # Set-ExecutionPolicy -Scope CurrentUser RemoteSigned pip install -r requirements-dev.txt copy .env.example .env # bash/mac: cp .env.example .env # Edit .env - set SECRET_KEY, JWT_SECRET_KEY, and # DATABASE_URL=mysql+pymysql://shopdb:devpassword@127.0.0.1:3306/shopdb_flask?charset=utf8mb4 # CORS_ORIGINS=http://localhost:5173 $env:FLASK_APP = "shopdb" # bash/mac: export FLASK_APP=shopdb flask db upgrade # core schema flask plugin upgrade-all # per-plugin schema (ADR-008) flask seed permissions flask seed settings flask seed reference-data flask seed admin --username admin --email you@example.com # password printed once flask seed demo # OPTIONAL: ~25 sample assets across plugins + printed parts (undo: flask seed demo-clear) ``` Enable the plugins you want visible (they install on a fresh box; some ship disabled). To turn on everything for development: PowerShell: ```powershell foreach ($p in "computers","employees","machines","measuringtools","network", "notifications","printers","slides","usb","warranty", "knowledgebase","geenforce","printedparts") { flask plugin install $p; flask plugin enable $p } ``` (bash/mac: a `for p in ...; do flask plugin install "$p"; ...; done` loop.) Run the backend ON PORT 5001 - the frontend dev server proxies `/api` and `/static` there (a bare `flask run` uses 5000 and nothing will load): ```powershell flask run --port 5001 ``` **Leave this running.** `flask run` does not return to a prompt - that is correct, not a hang. The server holds this terminal until you stop it. Do NOT press Ctrl+C to move on; that kills the backend. Open the frontend in a separate terminal (next section) and leave this one alone. Ctrl+C only when you are done for the day. ### Frontend (a second terminal - leave the backend running) ```powershell cd frontend npm install npm run dev # http://localhost:5173 ``` Open http://localhost:5173, log in as `admin` with the printed password. > Convenience: instead of two terminals you can run both under a process > manager (pm2, honcho, foreman). Keep the backend on 5001. --- ## 2c. VS Code (turnkey) The repo ships shared VS Code config in `.vscode/` (personal `settings.json` stays git-ignored): - **Recommended extensions** - on first open VS Code offers to install them (Python + Pylance, Vue Volar, ESLint, Docker). Accept. - **Run the dev site** - Command Palette > "Tasks: Run Task" > **Dev site (backend + frontend)** starts both servers in parallel (backend on 5001, frontend on 5173). Individual tasks exist too. - **Debug the backend** - the Run panel's **Flask API (:5001)** config runs the app under the debugger (breakpoints in routes/services, full stepping); **Pytest (current file)** debugs the open test file. - **The CI gate** - task **Check: naming + tests + build** runs the same three checks CI runs, before you commit. Prerequisite: the venv and `npm install` from 2b must be done first (the tasks call `venv/` and `frontend/node_modules`). --- ## 3. The development loop 1. Make a change. Backend: `flask run` auto-reloads. Frontend: Vite hot-reloads. 2. Before committing, run the three gates. Easiest: in VS Code, Command Palette > "Tasks: Run Task" > **Check: naming + tests + build**. By hand in PowerShell: ```powershell venv\Scripts\python -m pytest tests/ -q # backend cd frontend; npx vitest run; npm run build; cd .. bash scripts/check-naming-and-style.sh # naming - runs via Git Bash ``` There is NO auto-installed git hook - you run these yourself (or the VS Code task). CI runs all three on every push and pull request (`.github/workflows/ci.yml` on GitHub Actions; the same gate runs on the internal server) and fails the build on a bad name, so nothing bad reaches `main` - running them locally just saves the round trip. The naming check is a shell script, so that one line needs Git Bash (installed with Git for Windows). Want it automatic? The repo ships a hook; enable it once per clone: ```powershell git config core.hooksPath .githooks ``` Now every `git commit` runs the naming check first (Git for Windows executes the hook under its bundled bash) and blocks the commit if a name is wrong. Purely local convenience; CI is the real backstop. 3. Commit in small, working steps. Subject: short, present tense, plain English; body says WHY. Read `CONTRIBUTING.md` before naming anything - the naming hook will reject snake_case DB columns, banned shorthand, and non-ASCII. Seeing a change in the real app (not just tests) is the bar for "done" - drive the actual flow in the browser. --- ## 4. Your first change (suggested) Add a field to an existing list page, or better, build a plugin end to end: `docs/PLUGIN-LAB-PRINTEDPARTS.md` is a literal type-along that constructs the 3D-printed-parts plugin from scratch, with the finished code on branch `feat/printedparts-plugin` (tags `lab-stage-01`..`lab-stage-17`) as the answer key. It touches every hook the framework has. --- ## 5. Contributing back ```powershell git push -u origin feat/ ``` Open a Pull Request against `main` on GitHub. Describe what changed, any plugin hooks implemented, and any contract additions (those need a version bump + `docs/PLUGIN-HOOKS.md` update in the same PR). See the contributor section of the plugin lab for the full review checklist. --- ## Common setup problems | Symptom | Cause / fix | | --- | --- | | Frontend loads but every API call fails / CORS error | backend not on 5001 (`flask run --port 5001`), or `CORS_ORIGINS` missing `http://localhost:5173`. | | App refuses to boot in production config | a required `.env` var (`SECRET_KEY`, `JWT_SECRET_KEY`, `DATABASE_URL`, `CORS_ORIGINS`) missing or a dev default. | | `flask db upgrade` error 1071 (key too long) | MySQL 5.6 without the `innodb_large_prefix`/Barracuda flags; use MySQL 8 for dev. | | Nav missing Machines/PCs/... | plugins not installed/enabled (step 2b), or the backend not restarted after enabling. | | "No time zone found with key America/New_York" | `tzdata` not installed - `pip install -r requirements.txt` includes it. | | npm/git/pip SSL error (`UNABLE_TO_GET_ISSUER_CERT_LOCALLY`, `unable to get local issuer certificate`) | corp proxy (Zscaler) intercepts HTTPS - point each tool at the corp root CA. See section 0b. | | Naming hook rejects a commit | you used snake_case on a DB-mirrored field or a banned acronym - see `CONTRIBUTING.md`. | | Plugin toggle throws an internal error | app cannot write `instance/` (the plugin registry lives there) - fix directory permissions. |