MethodDevelopment
verified checked against the code · what the statuses mean
Getting started — run it locally
In simple terms
The app is a local tool: a Python backend and a browser frontend,
both on your machine, talking over localhost. There’s no cloud and no
deployment. The first time you open it you create your account (name, e-mail,
password); from then on you sign in with it — and a developer’s own server can skip
that with PTX_DEV_PRINCIPAL (see Environment variables). This page gets you from a fresh clone to a running app and tells you how
to check your work. The app also runs as one Docker image — on a server behind a proxy,
or on your own computer with your data in a folder of yours: see
Run with Docker.
Prerequisites (verified on the dev box)
- Python 3.12 (arm64 on Apple Silicon) in a virtual environment.
.python-versionnames the minor; the pinned numpy needs 3.12 or newer, and 3.9 (end of life) no longer works. The API line is FastAPI on Starlette 1.x with pydantic 2; the exact pins are inrequirements.txt(what the code imports, one reason per group) andrequirements.lock(every transitive package, generated). - uv (recommended) — it installs the Python
interpreter itself and the locked set in seconds. Plain
venv+pipworks too. - Node 20 (via nvm:
v20.20.2) for the frontend. - No database server, no secrets — SQLite is a file and Parquet is on disk.
Backend
# from the repo root — first time only
uv python install 3.12
uv venv venv --python 3.12
uv pip install --python venv/bin/python -r requirements.lock
# pip route instead: python3.12 -m venv venv && venv/bin/pip install -r requirements.txt
# every time
source venv/bin/activate
python backend/scripts/serve.py --reload
# = uvicorn backend.api.app:app --reload --reload-dir backend --port 8000 (127.0.0.1)
The API is then on http://localhost:8000. Quick check: GET /health. The SQLite
database and the data/ tree are created/read under backend/data/ (and are
gitignored — this folder is the only copy; back it up — including
backend/data/dab_workspaces/, where each workspace’s own default books live).
The API answers only to this Mac’s own names (localhost, 127.0.0.1) — a request
for any other Host is refused (400), however the server was started — and accepts
changes only from the configured dev frontend pages: http://localhost:5173 and
http://127.0.0.1:5173 unless PTX_DEV_ORIGINS says otherwise
(environment variables).
Changing a dependency: edit the pin in requirements.txt, regenerate the lock (every
transitive package pinned, with hashes, for every platform), install it, and run the full
suite:
uv pip compile requirements.txt -o requirements.lock --universal --python-version 3.12 --generate-hashes
uv pip sync --python venv/bin/python requirements.lock
python -m pytest backend/tests -q
The solver stack (pypsa, linopy, highspy, numpy, pandas) is also checked with
the identical-solve gate on a database copy (backend/scripts/verify_db_copy.py --lp),
because the rule-engine figures never touch PyPSA and a solver change is invisible
without the LP re-solve.
First run, and adding colleagues
- The first time the app opens it asks you to set up your account (name, e-mail, password). You become the admin and the owner of the workspace, and the app’s super admin (see Managing workspaces below); every project already on this computer stays yours.
- A colleague — account menu → Workspace settings → Add a member (e-mail, name, role: viewer, editor or admin). Someone who already has an account here joins at once. Anyone else gets a one-time link, shown once with a Copy button: send it to them privately. It works once, for 7 days, and lets whoever opens it choose the password — they land in the app with the role you chose. Pending links are listed there and can be withdrawn.
- Several workspaces — the account menu lists every workspace you belong to, with your role in each; choosing one moves you there. An admin can create a new one (New workspace…); its creator owns it. The owner renames a workspace, hands it on (Transfer ownership) or deletes it — and the super admin can do all three for any workspace (Managing workspaces, below).
- Your password — account menu → Change password… (this signs out your other
sessions). Forgotten:
backend/scripts/set_password.py <e-mail>on the machine. - A lost or wrong link — in Links not used yet, New link makes a new one-time link for that person (shown once, valid 7 days from now); the previous link stops working at once. Use it for a lost link, an expired one, or a link made for the wrong address.
Managing workspaces
-
The super admin is the account that set the app up. It sees every workspace — account menu → All workspaces: each one’s name, owner, how many members and projects it has, when it was made and its last activity. Not what it holds: to open a workspace’s projects, choose Join… and a role. Its members see that you joined (in their members list, and in “Since your last visit” on their projects home); Leave… is shown to them too. From the same list the super admin renames any workspace, transfers its ownership to one of its admins, or deletes it.
-
Another super admin is named — or removed — only on this Mac, from the repository root:
venv312/bin/python backend/scripts/super_admin.py --list venv312/bin/python backend/scripts/super_admin.py --add ana@example.com venv312/bin/python backend/scripts/super_admin.py --remove ana@example.comThe account must already be able to sign in (someone still holding an invitation link uses it first). The change counts from the next page they open.
-
Deleting a workspace — its owner: Workspace settings → Delete this workspace…; the super admin: All workspaces → ⋯ → Delete…. The dialog first offers Download every project (one zip, a bundle per project — import one back with Projects → Import a project), says where the backup goes, lists the members who would be left with no workspace (they could no longer sign in until someone adds them to another), and asks you to type the workspace’s name. Before removing anything the app saves a copy of the whole database in
~/Desktop/PtX_backups/(ptx_projects-<date>-<time>-before-delete-workspace-<id>.db, with the workspace’s own default books beside it in…-default-books/). Everything in the workspace then goes: its projects and their results, its members’ access, its links, its default books. It cannot be undone from the app — only by restoring that copy: stop the app, copy the.dbfile overbackend/data/ptx_projects.db(and the…-default-books/folder back tobackend/data/dab_workspaces/<id>/), start the app again.
Share with colleagues on your Wi-Fi
By default only this Mac can open the app. To let colleagues on the office Wi-Fi open it from their own computers, start the server like this — from the repository root, on the Mac that holds the data:
cd frontend && npm run build && cd .. # once, and after each update
venv312/bin/python backend/scripts/serve.py --share
- It serves the API on
http://127.0.0.1:8000exactly as before (sonpm run devkeeps working), and the built app over HTTPS on this Mac’s Wi-Fi address only, port 8443: colleagues openhttps://<your-mac-name>.local:8443(the exact address is printed, and shown in Workspace settings → Sharing on this network). Stop it with Ctrl+C; without--sharenothing is shared (serve.pyalone = the API on this Mac). - Before it listens, it refuses — with the reason — when no account exists yet,
when
PTX_DEV_PRINCIPALis set, when the Wi-Fi has no password, or when the Mac has no private office address on its Wi-Fi (never every network at once, never a VPN). The first time, it makes this Mac’s certificate: each colleague installs it once (below). - If the Mac joins another network (or its Wi-Fi address changes), sharing stops by
itself within seconds and the settings page says why: start it again on the office
network.
--reloadis refused with--share. - The macOS firewall is off on many Macs: turn it on (System Settings → Network → Firewall) and choose Allow when macOS asks whether Python may accept incoming connections.
- Inviting — Workspace settings → Add a member → Who will open this link? →
A colleague on your network: send them that link (and the one beneath it, by the
Mac’s address, for a computer that cannot find
.localnames) together with the certificate file. While nothing is shared, that choice shows the command instead of a link that would not open. - Never share the certificate authority’s key (
backend/data/private/tls/ca.key): whoever has it can pass for this Mac on every computer that installed the certificate. Only the certificate itself (PtX-Model-local-CA.crt, downloaded from the settings page) is meant for colleagues. The key, like the database, never leaves this Mac.
Install this Mac’s certificate
Each colleague does this once per computer or phone, so their browser trusts this Mac’s shared address. Compare the fingerprint first: the admin reads it from Workspace settings → Sharing on this network (by phone or in person, not in the same message as the file); the colleague’s system shows it while installing. If it differs, do not install the file.
- macOS — double-click the file: Keychain Access adds it to the login keychain. Double-click PtX Model local CA (…) → Trust → When using this certificate: Always Trust → close the window and confirm with your password. The fingerprint is under Details (SHA-256).
- Windows — double-click the file → check the Thumbprint on the Details tab (the settings page shows it too) → Install Certificate… → Current User → Place all certificates in the following store → Browse → Trusted Root Certification Authorities → Finish → Yes.
- iPhone, iPad — send the file by AirDrop or e-mail and open it → Settings → Profile Downloaded → Install. Then Settings → General → About → Certificate Trust Settings → switch on PtX Model local CA.
- Android — Settings → Security & privacy → More security settings → Encryption & credentials → Install a certificate → CA certificate → Install anyway → choose the file (menu names vary by maker; search Settings for “CA certificate”).
- Firefox keeps its own list on every system: Settings → Privacy & Security → Certificates → View Certificates → Authorities → Import… → tick Trust this CA to identify websites.
Then open the link. The certificate can vouch only for .local names and private
network addresses — never for a public website. To remove it, delete PtX Model local
CA (…) from the same place.
When a colleague cannot connect
- Test the network from their device:
https://<your-mac-name>.local:8443/api/healthshould show{"status":"ok"}. If the name is not found, try the address form (https://<wifi-address>:8443/api/health). - It cannot work on mobile data or from home (the Mac’s address exists only inside the office network), on guest or public Wi-Fi (they keep devices apart on purpose), through the colleague’s VPN, or while this Mac sleeps. A browser warning about the certificate means it is not installed yet on that device (above).
Frontend
export PATH="$HOME/.nvm/versions/node/v20.20.2/bin:$PATH" # Node 20 on PATH
cd frontend
npm install # first time only
npm run dev # Vite dev server, http://localhost:5173
Open http://localhost:5173. The frontend calls the backend at VITE_API_BASE
(default http://localhost:8000) — start the backend first, or the rooms show their
“start the backend” error state. The dev page server listens on this Mac only
(server.host: 'localhost'), on port 5173 exactly (strictPort: when the port is
taken it stops and says so, rather than moving to a port the API would refuse), and
may read only the frontend/ folder, its node_modules and docs/
(server.fs.allow) — never backend/ or the data. The built app (npm run build,
what serve.py --share serves) calls /api on its own address instead. The data font
(JetBrains Mono) ships in frontend/public/fonts/ with its licence: no font is fetched
from an outside service.
A second copy on other ports (a worktree’s verification servers, say an API on
8037 and a dev page on 5200): start the API with PTX_DEV_ORIGINS=http://localhost:5200
(and its own PTX_DB_PATH / data folders), and the page with
VITE_API_BASE=http://localhost:8037 npx vite --port 5200 — the API accepts that
page and nothing else, and the user’s own servers are not touched.
The quality gates (run before you commit)
The frontend’s unit tests run on Node’s own test runner (npm test: the files in
frontend/tests/ load a pure module — a sentence or a verdict — through Vite; no browser,
no extra dependency). The gates are:
# frontend (from frontend/)
npm run build # tsc -b && vite build — must be clean
npm run lint # eslint — 0 errors
npm test # node --test tests/ — must pass
# backend (from repo root, venv active)
python -m pytest backend/tests -q # must stay green — read the exit code
npm run build runs the TypeScript project build and the Vite production build,
so it catches type errors the dev server tolerates. Treat a red build/lint/pytest as
a blocker.
Handy scripts
| Command | What |
|---|---|
npm run dev |
Vite dev server (HMR). |
npm run build |
tsc -b && vite build (the type + prod gate). |
npm run lint |
ESLint. |
npm run preview |
Serve the production build locally. |
npm run docs:check |
The docs gate: generated numbers current + front-matter and links valid (uses ../venv, or PTX_PYTHON). |
python -m pytest backend/tests -q |
Backend test suite. |
python -m pytest backend/tests/test_api.py -k solve |
A focused subset. |
Gotchas
- French OS locale: the dev machine formats numbers/dates in French. Numeric
inputs use
parseDecimaland dates usefmtWhen(en-GB) so both.and,work — keep it that way (seefrontend/src/format.ts). - New docs
.mdfile? The in-app/docsexplorer resolves its Markdown glob at dev-server start-up — restartnpm run devfor a new file to appear (editing an existing one hot-reloads). The productionbuildalways picks up new files. - Adding a new
.mdand a Markdown glob in a JS comment: never put a**/pattern inside a/* … */block comment — the*/closes it early. The docs loader uses//line comments for that reason.
How to modify this safely
- Backend behaviour →
core/+ apytest. Orchestration →controllers.py. New HTTP surface → a thin route inapp.py. - A response-shape change is a three-place change:
core/producer →api.tstype →client.ts/room. Runtscto catch every break.
Related topics
From the app’s documentation, docs/05-development/getting-started.md · Hyprisma 1.0.5