Files
shopdb-flask/docs/DEVELOPMENT-SETUP.md
cproudlock 617248ea6e
Some checks failed
CI / backend (push) Failing after 7s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 10s
CI / migrations-mysql (push) Failing after 7s
Installer prerequisites: REQ-D through REQ-G
REQ-D: restore waitress and tzdata to requirements.in. They existed ONLY in the
generated requirements.txt (hand-added in bf9e60e), so the next
`uv pip compile` would have silently removed the WSGI server and the IANA
timezone database from every Windows install.

REQ-E: split production and development requirements. requirements.txt was
installing pytest, pytest-cov, pytest-flask, coverage, iniconfig and pluggy onto
production servers. Verified on a real Windows Server box before this change.
CI, scripts/test-external-plugin.sh and the dev docs now use requirements-dev.txt.

REQ-F: standardise on Python 3.14. The repo declared four different versions
(Dockerfile 3.12, DEPLOY-WINDOWS-IIS 3.12, INSTALL-WINDOWS-IIS 3.13, CI 3.13,
plus README, web.config and PLUGIN-EXTERNAL-REPO). 3.14 is in active bugfix
support until ~Apr 2027 and supported to Oct 2030; 3.13 entered security-only in
Apr 2026. All four compiled dependencies publish win_amd64 wheels for 3.14
(cryptography via an abi3 wheel), verified by building an offline wheelhouse and
installing it on Windows Server 2025.

REQ-G: state MySQL 8.0 as the standard for new installs; 5.7+/5.6 remain
supported on an existing server.

Lockfiles regenerated with uv pip compile. Production deps 44 -> 38.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 14:15:18 -04:00

12 KiB

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.13 (64-bit) - matches CI; prod images run 3.12 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):

winget install Git.Git                    # includes Git Bash (naming hook needs it)
winget install Python.Python.3.13
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.

# 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

# 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

git clone https://github.com/ge-aero/shopdb-flask.git
cd shopdb-flask

Never work on main. Branch for your change:

git checkout -b feat/<short-description>

2a. Fast path - Docker (a working site in one command)

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:

docker compose up -d db                # MySQL on 127.0.0.1:3306

Create the database + app user (skip if compose already did via env):

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

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:

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):

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)

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:

    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:

    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

git push -u origin feat/<short-description>

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.