A server-rendered Rust web application for uploading, parsing, and displaying GE HealthCare MUSE ECG XML files with 12-lead SVG waveform rendering.
GE HealthCare MUSE is a cardiology information system that manages ECG (electrocardiogram) data. This web app lets users upload MUSE XML files and view parsed results including patient demographics, test metadata, ECG measurements, diagnosis statements, and interactive 12-lead waveform visualizations.
- File Upload — Drag-and-drop or browse to upload MUSE XML files via HTMX multipart POST
- Patient Demographics — Name, ID, age, gender
- Test Metadata — Acquisition date/time, device, site
- ECG Measurements — Heart rate, PR interval, QRS duration, QT/QTc, axis measurements
- Diagnosis Statements — Parsed diagnostic text from the MUSE file
- 12-Lead Waveform Display — Server-generated SVG with ECG grid layout (4x3 grid + rhythm strip)
- Input Validation — Empty file, size limit, UTF-8, and XML parse checks with user-friendly error messages
| Component | Version | Purpose |
|---|---|---|
| Rust | Edition 2024 | Systems programming language |
| Loco | 0.16 | Rails-like framework on axum |
| axum | 0.8 | Web application framework |
| Tera | 1.20 | Server-side template engine |
| ge-healthcare-muse | 0.1 | MUSE XML parser |
| HTMX | 2.0.8 | AJAX navigation and file upload |
| Alpine.js | 3.14.8 | Client-side interactivity |
| Assertables | 9.8 | Assertion testing macros |
# Build
cargo build
# Run tests
cargo test
# Start development server (port 5150)
cargo loco start
# Visit http://localhost:5150- Visit the homepage at
http://localhost:5150 - Read the introduction about GE HealthCare MUSE
- Click "Upload a file" and select a MUSE XML file
- View the parsed results: demographics, measurements, diagnosis, and 12-lead ECG waveforms
A sample MUSE XML fixture is included at fixtures/sample_muse.xml for testing.
├── assets/
│ ├── static/
│ │ └── style.css # Application styles
│ └── views/
│ ├── base.html # Base template (HTMX + Alpine.js CDN)
│ ├── home/
│ │ └── index.html # Homepage with upload form
│ └── upload/
│ ├── results.html # Parsed ECG results display
│ └── error.html # Error alert partial
├── config/
│ ├── development.yaml # Dev server config (port 5150)
│ └── test.yaml # Test environment config
├── fixtures/
│ └── sample_muse.xml # Sample MUSE XML for testing
├── src/
│ ├── app.rs # Loco App trait (routes, initializers)
│ ├── bin/main.rs # CLI entrypoint
│ ├── lib.rs # Module declarations
│ ├── controllers/
│ │ ├── home.rs # GET / — homepage
│ │ └── upload.rs # POST /upload — file upload + validation
│ ├── initializers/
│ │ └── view_engine.rs # Tera ViewEngine initializer
│ ├── muse/
│ │ ├── mod.rs # XML parse + template context builder
│ │ └── svg.rs # SVG waveform generation
│ └── views/
│ ├── home.rs # Homepage view renderer
│ └── upload.rs # Results + error view renderers
└── tests/
├── muse/
│ └── svg_test.rs # SVG generation unit tests (5 tests)
└── requests/
└── upload_test.rs # Upload endpoint integration tests (3 tests)
The application follows the Loco framework's MVC pattern:
- No database — Stateless file upload and parse workflow
- Server-side rendering — Tera templates with
hx-boost="true"for SPA-like navigation - HTMX — Multipart file upload via
hx-post="/upload"withhx-target="#results"for in-page result rendering - Alpine.js — Client-side filename preview and collapsible sections
- SVG generation — Server-side ECG waveform rendering with proper scaling (25mm/s, 10mm/mV standard)
Browser → POST /upload (multipart)
→ controllers::upload::handle_upload
→ Validate: non-empty, size limit, UTF-8, valid XML
→ muse::parse_and_build_context (parse XML, decode waveforms, generate SVGs)
→ views::upload::results (render Tera template)
→ HTML partial injected into #results div via HTMX
# Run all tests
cargo test
# Run SVG unit tests only
cargo test --test muse
# Run integration tests only
cargo test --test requests
# Lint
cargo clippy| Test Suite | Tests | Description |
|---|---|---|
muse/svg_test |
5 | SVG element structure, lead labels, polyline, grid lines, 12-lead grid |
requests/upload_test |
3 | Valid upload, empty file error, invalid XML error |
cargo loco start # Start development server (port 5150)
cargo build # Development build
cargo build --release # Production build
cargo test # Run all tests
cargo clippy # Lint checks- Server port: 5150
- Binding: localhost
- Static assets served from
assets/static/at/static - Debug logging enabled
PORT— Server portHOST— Server host URL
See repository for license information.