From 596e93376e229992d2bc46694d88b4e4ff7548df Mon Sep 17 00:00:00 2001 From: Thomas Wright <63931206+authorTom@users.noreply.github.com> Date: Sun, 26 Jul 2026 11:34:17 +0100 Subject: [PATCH] docs: apply the shared README house style Applies a shared README structure used across all nine authorTom project repositories, so someone arriving from one recognises the shape of the next. Canonical section order: # Name -> bold one-sentence pitch -> hero screenshot ## Why it exists the argument: what you did before and why it hurt ## What it does features ## Run it ### With Docker (recommended) / ### From source ## Configuration a table of runtime variables, and what is UI-only instead ## How it's built layout and the decisions worth knowing ## Security where the project handles accounts or data ## Backing up where there is state worth losing ## Licence always last, always spelled this way Also standardised: British English throughout, sentence-case headings with no emoji, no shields.io badges or centred divs, Docker before source in every quick start (the previous order varied), and alt text that describes what is in each screenshot rather than saying "screenshot". Content is preserved rather than rewritten -- this reorganises and normalises the existing material. Drops the three shields.io badges and the emoji from every heading. Moves the screenshot table up to sit directly under the pitch. Keeps the comparison table and the "What SimHub is not (yet)" section intact -- the latter is the most trustworthy paragraph in the file. Co-Authored-By: Claude Opus 5 --- README.md | 379 +++++++++++++++++++++++++++--------------------------- 1 file changed, 189 insertions(+), 190 deletions(-) diff --git a/README.md b/README.md index 4acfa23..c4b2134 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,150 @@ -# SimHub 🩺 +# SimHub -[![Licence: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Node.js Version](https://img.shields.io/badge/node-%3E%3D16.0.0-blue.svg)](https://nodejs.org/) -[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)]() +**A free, open-source scenario management and run-time system for clinical +simulation teams.** -**SimHub is a free, open-source scenario management and run-time system for clinical simulation teams.** Write your scenarios once in a structured, ASPiH-aligned format, organise them into course programmes, run them live with an on-screen patient monitor, and debrief with a built-in PEARLS guide — all from one web app that runs entirely on your own hardware. +Write your scenarios once in a structured, ASPiH-aligned format, organise them +into course programmes, run them live with an on-screen patient monitor, and +debrief with a built-in PEARLS guide — all from one web app that runs entirely +on your own hardware. -It is built for simulation centres, clinical skills departments, and education teams who want the structure of a commercial simulation platform without the licence fees, per-seat pricing, or handing their scenario library to a third-party cloud. +It is built for simulation centres, clinical skills departments and education +teams who want the structure of a commercial simulation platform without the +licence fees, per-seat pricing, or handing their scenario library to a +third-party cloud. ---- +| Login gateway | Faculty dashboard | +| --- | --- | +| ![The SimHub sign-in screen](public/screenshots/01_login_screen.png) | ![A dashboard listing scenarios grouped into curriculum programmes](public/screenshots/02_dashboard.png) | +| **Scenario details** | **Interactive run HUD** | +| ![A scenario detail sheet showing learning outcomes, SBAR handover and phases](public/screenshots/03_details.png) | ![The facilitator HUD with a live ECG trace, target vitals, run timer and expected actions](public/screenshots/04_hud.png) | +| **PEARLS debrief guide** | **High-contrast light mode** | +| ![The debrief guide with PEARLS phases, pre-filled questions and a phase timer](public/screenshots/05_debrief.png) | ![The same dashboard in high-contrast light mode](public/screenshots/06_dashboard_light.png) | -## 💷 Why a free, open-source platform? +## Why it exists -If you are currently managing scenarios in Word documents and shared drives — or paying for a commercial platform — here is what SimHub offers: +If you are currently managing scenarios in Word documents and shared drives — or +paying for a commercial platform — here is what SimHub offers: | | SimHub | Typical paid platform | Word docs + shared drive | | :--- | :--- | :--- | :--- | | **Cost** | £0, forever (MIT licence) | Annual licence, often per-seat | "Free", but unstructured | -| **Your data** | Stays on your own machine/server | Vendor's cloud | Scattered, versioning by filename | -| **Users & scenarios** | Unlimited | Often tiered | Unlimited | -| **Structure & governance** | Enforced ASPiH-aligned template, version history, review dates | Varies | Manual, inconsistent | +| **Your data** | Stays on your own machine or server | Vendor's cloud | Scattered, versioning by filename | +| **Users and scenarios** | Unlimited | Often tiered | Unlimited | +| **Structure and governance** | Enforced ASPiH-aligned template, version history, review dates | Varies | Manual, inconsistent | | **Run-time support** | Live vitals HUD, phase progression, timers, cue prompts | Usually yes | Printed sheets | | **If the vendor disappears** | Nothing changes — you have the code and the data | Migration project | — | -Because your entire scenario library lives in plain, human-readable JSON files on your own hardware, there is **no vendor lock-in and nothing leaves your building** — which also makes conversations with your information governance team considerably shorter. +Because your entire scenario library lives in plain, human-readable JSON files +on your own hardware, there is **no vendor lock-in and nothing leaves your +building** — which also makes conversations with your information governance +team considerably shorter. -### What SimHub is *not* (yet) +### What SimHub is not (yet) -Honesty helps you evaluate. SimHub does not currently do: manikin/hardware control, audiovisual capture or video-assisted debriefing, learner-facing accounts or assessment scoring, or LMS integration. It manages, runs, and debriefs your *scenarios* — it does not replace your AV system or your manikin software. +Honesty helps you evaluate. SimHub does not currently do manikin or hardware +control, audiovisual capture or video-assisted debriefing, learner-facing +accounts or assessment scoring, or LMS integration. It manages, runs and +debriefs your *scenarios* — it does not replace your AV system or your manikin +software. ---- +## What it does -## 🌟 What can it do? +**Plan and write** — A guided seven-step scenario builder covering everything +the [ASPiH](https://aspih.org.uk/) standards expect: governance and sign-off, +learning outcomes (technical and non-technical), patient demographics and +clinical background, SBAR handovers, faculty and simulated-participant roles +with scripts, equipment and medication checklists, environment setup, and +multi-phase clinical progression with target vitals. -**📝 Plan & write** — A guided seven-step scenario builder covering everything the [ASPiH](https://aspih.org.uk/) standards expect: governance and sign-off, learning outcomes (technical and non-technical), patient demographics and clinical background, SBAR handovers, faculty and simulated-participant roles with scripts, equipment and medication checklists, environment setup, and multi-phase clinical progression with target vitals. +**Organise** — Group scenarios into curriculum programmes (for example *Year 5 +Undergraduate Medicine*, *FY1 Induction*), search the whole library instantly, +and track review-due dates so nothing quietly goes out of date. -**🗂️ Organise** — Group scenarios into curriculum programmes (e.g. *Year 5 Undergraduate Medicine*, *FY1 Induction*), search the whole library instantly, and track review-due dates so nothing quietly goes out of date. +**Run** — A real-time facilitator HUD with a simulated bedside monitor (live ECG +trace paced by the scripted heart rate), phase-by-phase progression that updates +target vitals at a click, a run timer, expected-action checklists, rescue-cue +prompts, and confederate scripts to hand. -**▶️ Run** — A real-time facilitator HUD with a simulated bedside monitor (live ECG trace paced by the scripted heart rate), phase-by-phase progression that updates target vitals at a click, a run timer, expected-action checklists, rescue-cue prompts, and confederate scripts to hand. +**Debrief** — A built-in guide based on the +[PEARLS](https://debrief2learn.org/pearls-debriefing-tool/) framework, +pre-filled with the questions and analysis points you wrote into the scenario, +with its own timer for each debrief phase. -**🗣️ Debrief** — A built-in guide based on the [PEARLS](https://debrief2learn.org/pearls-debriefing-tool/) framework, pre-filled with the questions and analysis points you wrote into the scenario, with its own timer for each debrief phase. +**Govern** — Role-based access (Admin / programme-scoped Editor / Read-Only), +full user administration with bulk operations, forced password rotation for +provisioned accounts, scenario version history, a recycle bin for accidental +deletions, one-click JSON backup and restore, and PDF export of any scenario for +printing or sharing. -**🔐 Govern** — Role-based access (Admin / programme-scoped Editor / Read-Only), full user administration with bulk operations, forced password rotation for provisioned accounts, scenario version history, a recycle bin for accidental deletions, one-click JSON backup and restore, and PDF export of any scenario for printing or sharing. +## Run it ---- +You do not need to be a developer for either route. If you can install a program +and copy a few commands into a terminal, you can run SimHub. There is no +database server to set up and no build step. -## 📸 SimHub in action +### With Docker (recommended) -| 🔐 Login Gateway | 📊 Faculty Dashboard | -| :---: | :---: | -| ![Login Gateway](public/screenshots/01_login_screen.png) | ![Faculty Dashboard](public/screenshots/02_dashboard.png) | +The published image is the easiest way to run SimHub reliably on a departmental +server, a NAS, or even a Raspberry Pi — it is built for both x86 and ARM. It is +small (~60 MB), runs as an unprivileged user, reports its own health, and shuts +down gracefully so no data is lost on restarts. -| 🩺 Scenario Details | 💻 Interactive Run HUD | -| :---: | :---: | -| ![Scenario Details](public/screenshots/03_details.png) | ![Interactive Run HUD](public/screenshots/04_hud.png) | +```bash +curl -fsSL -o compose.yaml \ + https://raw.githubusercontent.com/authorTom/simhub/main/compose.yaml +curl -fsSL -o .env.example \ + https://raw.githubusercontent.com/authorTom/simhub/main/.env.example +cp .env.example .env # then edit if you need TRUST_PROXY, a different port, etc. -| 🗣️ PEARLS Debrief Guide | ☀️ High-Contrast Light Mode | -| :---: | :---: | -| ![PEARLS Debrief](public/screenshots/05_debrief.png) | ![Dashboard Light Mode](public/screenshots/06_dashboard_light.png) | +docker compose up -d # start (pulls the image) +docker compose ps # confirm STATUS shows "(healthy)" +docker compose exec simhub node seed.js # optional: load the example scenario +``` + +Open **`http://:3000`** and sign in — see +[First sign-in](#first-sign-in) below. You do not need the source checked out on +the server. ---- +Or without compose, in one command: -## 🚀 Getting started (about 10 minutes) +```bash +docker run -d --name simhub \ + -p 3000:3000 \ + -v simhub-data:/app/data \ + --restart unless-stopped \ + ghcr.io/authortom/simhub:latest +``` -There are two ways to run SimHub: +Updating: -* **Directly with Node.js** (below) — the quickest way to try it out on your own machine or a test environment. -* **As a Docker container** (see [Deploy with Docker](#-deploy-with-docker)) — the recommended way to run it for a department: a small, self-contained image with your data kept safely in a volume. +```bash +docker compose pull && docker compose up -d +``` -You do not need to be a developer for either. If you can install a program and copy a few commands into a terminal, you can run SimHub. There is no database server to set up and no build step — one small dependency and it runs. +The new container starts against the same data volume, and persisted sessions +mean your faculty are not even signed out. To be able to roll back, deploy a +pinned tag instead of `latest`. -### 1. Install Node.js +| Tag | Meaning | +| :--- | :--- | +| `ghcr.io/authortom/simhub:latest` | Current state of `main` | +| `ghcr.io/authortom/simhub:sha-` | Immutable build of a specific commit (best for pinning and rollback) | +| `ghcr.io/authortom/simhub:` | Published when a `v*` release tag is pushed | -Download and install [Node.js](https://nodejs.org/) (the free LTS version) for Windows, macOS, or Linux. This is the only prerequisite. +To build the image yourself instead — on an air-gapped network, for instance: -### 2. Download and start SimHub +```bash +git clone https://github.com/authorTom/simhub.git +cd simhub +docker build -t simhub . +docker run -d --name simhub -p 3000:3000 -v simhub-data:/app/data --restart unless-stopped simhub +``` -Open a terminal (Command Prompt / PowerShell on Windows, Terminal on macOS) and run: +### From source + +The quickest way to try it on your own machine. The only prerequisite is +[Node.js](https://nodejs.org/) (the free LTS version). ```bash git clone https://github.com/authorTom/simhub.git @@ -86,11 +154,12 @@ npm run seed # loads a complete worked example scenario npm start ``` -> No `git`? You can also download the project as a ZIP from GitHub (green **Code** button → *Download ZIP*), unzip it, and run the last three commands inside the folder. - -### 3. Open it in your browser +Open ****. The seeded example — a full Acute Pulmonary +Embolism scenario ("Sam Phillips") mapped to an undergraduate curriculum — is a +good way to explore every feature before writing your own. -Go to **http://localhost:3000** and sign in (see below). The seeded example — a full Acute Pulmonary Embolism scenario ("Sam Phillips") mapped to an undergraduate curriculum — is a good way to explore every feature before writing your own. +> No `git`? Download the project as a ZIP from GitHub (green **Code** button → +> *Download ZIP*), unzip it, and run the last three commands inside the folder. ### First sign-in @@ -101,7 +170,10 @@ SimHub seeds two accounts so you can get in: | **Admin** | `admin@simhub.local` | `admin123` | | **Read-Only faculty** | `faculty@simhub.local` | `faculty123` | -These initial passwords are **provisional**: each account must set its own password at first sign-in before anything else works. The same applies to any account an Admin later creates or resets — so a default or temporary password can never quietly linger. +These initial passwords are **provisional**: each account must set its own +password at first sign-in before anything else works. The same applies to any +account an Admin later creates or resets — so a default or temporary password +can never quietly linger. ### User roles @@ -111,140 +183,43 @@ These initial passwords are **provisional**: each account must set its own passw | **Editor** | Create and edit scenarios, but **only within programmes an Admin has allocated to them**. Read-only everywhere else. Ideal for course leads who own their own content. | | **Read-Only** | Browse the library, view scenario detail sheets, run the HUD and debrief guide. Cannot change anything. | ---- - -## 🗄️ Your data, backups, and recovery - -* **Where it lives**: everything is plain JSON in the `data/` folder — one file per scenario, one per programme. You can read them, diff them, and back them up like any other files. -* **Backups**: Admins get one-click **Export** (downloads your whole scenario library as a single JSON file) and **Import** (restores or merges it) from the dashboard sidebar. Scheduling a copy of the `data/` folder into your existing backup routine covers everything else (users, sessions). -* **Deletions are recoverable**: deleted scenarios go to a recycle bin, where an Admin can restore them or erase them permanently. -* **Printing / sharing**: any scenario can be exported as a print-styled PDF. - ---- - -## 🐳 Deploy with Docker - -The published container image is the easiest way to run SimHub reliably on a departmental server, a NAS, or even a Raspberry Pi (it is built for both x86 and ARM). It is small (~60 MB), runs as an unprivileged user, reports its own health, and shuts down gracefully so no data is lost on restarts. - -### Prerequisite - -[Docker](https://docs.docker.com/get-docker/) (Docker Desktop on Windows/macOS, Docker Engine on Linux). - -### Quick start — one command - -```bash -docker run -d --name simhub \ - -p 3000:3000 \ - -v simhub-data:/app/data \ - --restart unless-stopped \ - ghcr.io/authortom/simhub:latest -``` - -Open **http://localhost:3000**, sign in with the seeded accounts (see [First sign-in](#first-sign-in)), and optionally load the worked example scenario: - -```bash -docker exec simhub node seed.js -``` - -### Recommended — Docker Compose - -The repository ships a ready-made [compose.yaml](compose.yaml) that **pulls the published image** — you do **not** need the source checked out on the server. Grab just that one file onto the server and start it: - -```bash -# Download the compose file next to where your data volume will live -curl -fsSL -o compose.yaml \ - https://raw.githubusercontent.com/authorTom/simhub/main/compose.yaml - -# Optional: configuration overrides (proxy, port). Compose auto-reads a sibling .env -curl -fsSL -o .env.example \ - https://raw.githubusercontent.com/authorTom/simhub/main/.env.example -cp .env.example .env # then edit .env if you need TRUST_PROXY, etc. - -docker compose up -d # start (pulls the image) -docker compose ps # confirm STATUS shows "(healthy)" -docker compose exec simhub node seed.js # optional: load the example scenario -docker compose logs -f simhub # watch the logs -``` - -Then open `http://:3000` and sign in as `admin@simhub.local` / `admin123`; you are forced to set a real password at first sign-in. - -Compose gives you a declarative record of your deployment (port, volume, environment) that you can keep in your team's documentation. To run behind a reverse proxy, set `TRUST_PROXY=1` in `.env` (or uncomment it in `compose.yaml`). - -### Your data lives in the volume - -All scenarios, programmes, users, and sessions are stored in the `simhub-data` named volume — **the container itself is disposable**. You can delete and recreate the container (or update the image) without losing anything. Back the volume up either with the in-app Admin **Export** button, or at the infrastructure level: - -```bash -docker run --rm -v simhub-data:/data -v "$PWD":/backup alpine \ - tar czf /backup/simhub-data-backup.tar.gz -C /data . -``` - -### Updating to a new version +## Configuration -```bash -docker compose pull && docker compose up -d -``` +| Variable | Default | What it does | +| --- | --- | --- | +| `PORT` | `3000` | Port the server listens on | +| `TRUST_PROXY` | *(unset)* | Set to `1` behind a reverse proxy, so login rate-limiting sees real client addresses | -That's it — the new container starts against the same data volume, and persisted sessions mean your faculty aren't even signed out. To be able to roll back, deploy a pinned tag (`ghcr.io/authortom/simhub:sha-` or a release version) instead of `latest`, and change the tag in `compose.yaml` when you upgrade. +Copy [`.env.example`](.env.example) to `.env` and adjust. Everything else — +scenarios, programmes, users, roles — is managed inside the app. -### Building the image yourself +## Running SimHub for a department -If you prefer not to pull the published image (e.g. on an air-gapped network), build it from source: +For a single sim suite, the Docker quick start above (or `npm start` on any +spare machine — modest hardware is fine) is genuinely enough. For a shared +departmental installation: -```bash -git clone https://github.com/authorTom/simhub.git -cd simhub -docker build -t simhub . -docker run -d --name simhub -p 3000:3000 -v simhub-data:/app/data --restart unless-stopped simhub -``` - -### Where images are published +- **Put it behind HTTPS.** Run a reverse proxy (nginx, Caddy, IIS) in front of + SimHub and terminate TLS there. Sign-in uses bearer tokens and assumes an + encrypted transport. +- **Set `TRUST_PROXY=1`** when behind a proxy. Leave it unset when clients + connect directly. +- **Protect the `data/` folder.** It holds password hashes and session tokens. + It is never served over the web, but restrict filesystem permissions to the + service account and include it in backups. +- **Restarts are painless.** Active sign-ins persist across restarts and + redeploys, so updating SimHub does not sign your faculty out mid-session. +- **Monitoring.** `GET /api/health` is an unauthenticated liveness endpoint for + uptime checks and container orchestrators. -Every push to `main` automatically builds and publishes a fresh multi-architecture image to **GitHub Container Registry** via the included [workflow](.github/workflows/docker-publish.yml): - -| Tag | Meaning | -| :--- | :--- | -| `ghcr.io/authortom/simhub:latest` | Current state of `main` | -| `ghcr.io/authortom/simhub:sha-` | Immutable build of a specific commit (best for pinning/rollback) | -| `ghcr.io/authortom/simhub:` | Published when a `v*` release tag is pushed | +## How it's built ---- - -## 🏥 Running SimHub for a department - -For a single sim suite, the Docker quick start above (or `npm start` on any spare machine — modest hardware is fine) is genuinely enough. For a shared departmental installation: - -* **Put it behind HTTPS**: run a reverse proxy (nginx, Caddy, IIS) in front of SimHub and terminate TLS there. Sign-in uses bearer tokens and assumes an encrypted transport. -* **Set `TRUST_PROXY=1`** when behind a proxy so login rate-limiting sees real client addresses. Leave it unset when clients connect directly. -* **Protect the `data/` folder**: it holds password hashes and session tokens. It is never served over the web, but restrict filesystem permissions to the service account and include it in backups. -* **Restarts are painless**: active sign-ins persist across restarts and redeploys, so updating SimHub does not log your faculty out mid-session. -* **Monitoring**: `GET /api/health` is an unauthenticated liveness endpoint for uptime checks and container orchestrators (the Docker image already uses it for its built-in healthcheck). -* **Port**: set the `PORT` environment variable to change from the default `3000`. - -Security features already built in: salted scrypt password hashing, brute-force login throttling, 8-hour sliding sessions with revocation on password change or account removal, server-side role enforcement, path-traversal and stored-XSS protections, and last-admin lockout guards. - ---- - -## 🧑‍💻 For developers - -**Stack**: Node.js + Express backend, flat-file JSON persistence, vanilla HTML/CSS/JS frontend (no build step, no framework). The only runtime dependency is Express. - -### Tests - -```bash -npm run test # API integration suite (auth, roles, CRUD, backups) -npm run test:ui # Puppeteer end-to-end: full scenario wizard save flow -npm run screenshots # regenerate the README screenshots -``` - -The UI tests and screenshots need Google Chrome installed in a standard location. - -### Project layout +Node.js + Express backend, flat-file JSON persistence, vanilla HTML/CSS/JS +frontend — no build step, no framework. The only runtime dependency is Express. ```text simhub/ -├── .github/ # Issue templates -│ └── workflows/ # CI: builds & publishes the Docker image +├── .github/workflows/ # CI: builds and publishes the Docker image ├── data/ # Flat-file JSON database (git-ignored) │ ├── scenarios/ # One file per scenario │ ├── programmes/ # Programme tracks @@ -255,12 +230,8 @@ simhub/ │ ├── css/style.css # Themes and styles │ ├── js/ # SPA logic (api / components / app) │ └── index.html # Application shell -├── CHANGELOG.md # Full change history -├── CONTRIBUTING.md # Contribution guide ├── Dockerfile # Production container image ├── compose.yaml # Departmental deployment recipe (pull-based) -├── .env.example # Config template -> copy to .env -├── LICENSE # MIT licence ├── scenario_template.md # ASPiH scenario blueprint (reference) ├── seed.js # Example dataset generator ├── server.js # Express application server @@ -268,26 +239,54 @@ simhub/ └── test-ui-save.js # Puppeteer UI tests ``` ---- +Everything is plain JSON in `data/` — one file per scenario, one per programme. +You can read them, diff them, and back them up like any other files. + +### Tests + +```bash +npm run test # API integration suite (auth, roles, CRUD, backups) +npm run test:ui # Puppeteer end-to-end: full scenario wizard save flow +npm run screenshots # regenerate the README screenshots +``` + +The UI tests and screenshots need Google Chrome installed in a standard +location. + +## Security + +Built in already: salted scrypt password hashing, brute-force login throttling, +8-hour sliding sessions with revocation on password change or account removal, +server-side role enforcement, path-traversal and stored-XSS protections, and +last-admin lockout guards. + +## Backing up -## 🤝 Contributing +All scenarios, programmes, users and sessions are stored in the `simhub-data` +named volume — **the container itself is disposable**. You can delete and +recreate it, or update the image, without losing anything. -Contributions from the simulation community are very welcome — clinical educators reporting what a real sim programme needs are just as valuable as code. Please read the [Contributing Guide](CONTRIBUTING.md), then: +- **From the app**: Admins get one-click **Export** (downloads the whole + scenario library as a single JSON file) and **Import** from the dashboard + sidebar. +- **At the infrastructure level**: -1. Fork the project. -2. Create your feature branch (`git checkout -b feature/AmazingFeature`). -3. Commit your changes (`git commit -m 'Add some AmazingFeature'`). -4. Push to the branch (`git push origin feature/AmazingFeature`). -5. Open a Pull Request. + ```bash + docker run --rm -v simhub-data:/data -v "$PWD":/backup alpine \ + tar czf /backup/simhub-data-backup.tar.gz -C /data . + ``` ---- +Deleted scenarios go to a recycle bin, where an Admin can restore them or erase +them permanently. Any scenario can also be exported as a print-styled PDF. -## 📝 Change log +## Contributing -The full version history — features, security hardening, and fixes — lives in [CHANGELOG.md](CHANGELOG.md). +Contributions from the simulation community are very welcome — clinical +educators reporting what a real sim programme needs are just as valuable as +code. Please read the [Contributing Guide](CONTRIBUTING.md). ---- +The full version history lives in [CHANGELOG.md](CHANGELOG.md). -## 📄 Licence +## Licence -MIT — free for any use, including commercial. See [LICENSE](LICENSE) for details. +MIT — free for any use, including commercial. See [LICENSE](LICENSE).