# Contributing to YourPHR __You don't have to be a developer to make YourPHR better.__ Patients, clinicians, designers, writers, translators, FHIR/standards folks, and engineers all have a place here. This page is both an invitation and a map. > __Mission: Your medical records, immediately and in your hands — for free.__ YourPHR is a self-hosted personal/family health record viewer — a [community-maintained, standalone continuation](README.md) of Fasten OnPrem (GPL v3, attribution retained). ## Why contribute - __It matters.__ People can't act on records they can't read. YourPHR exists to put your health *in your hands* in plain language — see the [patient-legible display north star](docs/your-phr-dashboard/patient-legible-display.md). Your work goes straight to that. - __It stays yours.__ YourPHR is __community-owned and stays free__ — GPL v3, self-hosted, your data never leaves your control and is never sold. This is a continuation that exists to keep a fully open-source build alive after upstream's sync moved into a commercial product; the whole point is that effort here compounds and won't be locked away. - __The problems are genuinely interesting__ (see below). ## The interesting problems (if you want something meaty) This is real-world health-data engineering, not CRUD. A few of the juicy ones: - __Turn messy, vendor-specific FHIR into something a human can read.__ Patient portals export non-conformant FHIR R4 (FollowMyHealth/Veradigm collapse social/lifestyle items into clinical `Condition`s, omit `Condition.category`, use proprietary code systems). We normalize it at read time and route it to legible patient sections — the __two-layer source-adapter / display-mapper__ design in [classification-and-display-architecture.md](docs/your-phr-dashboard/classification-and-display-architecture.md). - __Reconcile "Current Medications" across resource types__ — one drug scattered across `MedicationRequest` / `MedicationStatement` / `MedicationDispense`, no clean "is current" flag. A derived, de-duplicated, provenance-aware view ([#264](https://github.com/jwilleke/yourphr/issues/264)). - __Self-hosted SMART-on-FHIR without a commercial relay__ — a tiny public store-and-poll OAuth `code` bouncer that never sees tokens, so a LAN instance can still sync ([relay README](relay/README.md), [EPIC #20](https://github.com/jwilleke/yourphr/issues/20)). - __US Core 9.0.0 Must-Support display conformance__ — a CI gate checks our display against the IG's own example resources ([docs/us-core/](docs/us-core/README.md)). - __Importing the formats portals actually give patients__ — C-CDA/CCD XML ([#254](https://github.com/jwilleke/yourphr/issues/254)), PDFs ([#255](https://github.com/jwilleke/yourphr/issues/255)). Start with the [architecture overview](./docs/architecture/architecture.md) for the whole map, then the [roadmap](docs/Roadmap.md) for where it's headed. ## Ways to contribute — by what you're good at | If you are a… | You can help with… | Start here | |---|---|---| | __Developer__ (Go / Angular) | Backend FHIR handling, display models, the API, frontend cards & dashboards | [`good first issue`](https://github.com/jwilleke/yourphr/labels/good%20first%20issue) · [`help wanted`](https://github.com/jwilleke/yourphr/labels/help%20wanted) · the [dev setup](#development-environment) below | | __FHIR / health-IT / standards__ person | US Core conformance, vendor-quirk mappings, value-set translation, SMART-on-FHIR | [docs/us-core/](docs/us-core/README.md), [docs/EHR-vendors/](./docs/EHR-vendors/README.md), [#136](https://github.com/jwilleke/yourphr/issues/136) | | __Clinician / health professional__ | Sanity-check that displays are *correct* and *legible*, validate medication/condition reconciliation | open a [feature/bug issue](https://github.com/jwilleke/yourphr/issues/new/choose) describing what's wrong or misleading | | __Designer / UX__ | Make the dashboard and cards genuinely legible — the [patient-legible](docs/your-phr-dashboard/patient-legible-display.md) bar | [#262](https://github.com/jwilleke/yourphr/issues/262), [#244](https://github.com/jwilleke/yourphr/issues/244), the BS5 migration [#209](https://github.com/jwilleke/yourphr/issues/209) | | __Writer / plain-language__ | Docs, the glossary that translates codes to words, READMEs, onboarding | the `documentation` label; the `glossary-lookup` component | | __Translator__ | Make YourPHR usable in more languages | open an issue — i18n is welcome | | __Tester with real exports__ | Run *your own* FHIR/CCD/PDF export through it and report what renders poorly (__never paste real PHI__ — see below) | the display-gap path / a [bug report](https://github.com/jwilleke/yourphr/issues/new/choose) | | __Security / privacy__ | Review auth, the SSRF guard, CSP, the relay; threat-model the self-hosted deployment | [SECURITY.md](SECURITY.md), [security review](docs/planning/architecture-security-review.md) | | __Ops / packaging__ | Docker, k8s/Flux, the Nix flake, CI | the `dependencies` / build issues | New here and not sure? Open a [blank issue](https://github.com/jwilleke/yourphr/issues/new/choose) or say hello — "I'd like to help, where do I start?" is a perfectly good first message. ## Find something to work on - __Newcomers:__ [`good first issue`](https://github.com/jwilleke/yourphr/labels/good%20first%20issue) — small, well-scoped, low-context. - __Want impact:__ [`help wanted`](https://github.com/jwilleke/yourphr/labels/help%20wanted) — meatier work where an extra pair of hands moves the mission. - Comment on an issue to claim it (so two people don't duplicate effort), then open a PR that references it (`Fixes #123`). - Be kind: we follow the [Code of Conduct](CODE_OF_CONDUCT.md) (Contributor Covenant). ### A note on health data (important) YourPHR handles __Personal Health Information__. __Never__ attach real patient data, real exports, secrets, or keys to an issue or PR — use *synthetic* (Synthea-generated) fixtures only. If you found a display bug in your own records, describe the *shape* of the problem and paste a small __synthetic__ example, never the real thing. See the data rules in [AGENTS.md](AGENTS.md). --- ## Development environment > The authoritative pinned versions live in `frontend/.nvmrc`, `frontend/package.json`, `go.mod`, and `Dockerfile` — keep this section in sync with those. In the meantime, the [Fasten Docs Repository](https://github.com/fastenhealth/docs/tree/main/technical) has extensive background. ## Tech stack ### Frontend - Node.js `v24` — pinned in `frontend/.nvmrc` (run `nvm use` in `frontend/`) - Yarn `1.22.22` (classic) — pinned via `package.json` `packageManager`; enable with `corepack enable` - Angular `v20` — use the project-local CLI via `npx ng …` (don't install a global CLI) ### Backend - Go `v1.24` — built with `golang:1.24`; `go.mod` requires `go 1.23+` ### Misc - Docker `v24+` > Stack modernization (Node 24, Angular 20, Go 1.24, Docker distroless) is tracked in [#12](https://github.com/jwilleke/yourphr/issues/12); the Angular 14 → 20 climb and the Node → 24 flip are complete. ## Versioning YourPHR follows [SemVer](https://semver.org/). Releases are cut by a maintainer pushing an annotated `vX.Y.Z` tag — no release bot, no release PR ([#241](https://github.com/jwilleke/yourphr/issues/241) removed release-please, whose bot PR could not pass `main`'s required checks without a privileged token). Write commits as [Conventional Commits](https://www.conventionalcommits.org/); `CHANGELOG.md` is written by hand at release time in that format. The steps are in [`docs/development/releasing.md`](./docs/development/releasing.md). The version lives in `package.json` and nowhere else — a v3 instance reads it there and serves it on `/api/version`. ## Setup ### Nix (recommended) If you use Nix, the included flake provisions everything: 1. Install [Nix](https://nixos.org/download/) with flakes enabled, and optionally [direnv](https://direnv.net/). 2. `direnv allow` in this directory — the environment activates automatically on entry. ### macOS ```bash brew install node # then: cd frontend && nvm use (or use the .nvmrc version) corepack enable # provides the pinned Yarn 1.22.22 brew install go brew install docker # Frontend tests run with the ChromeHeadless browser. brew install --cask google-chrome # Go tooling (TypeScript type generation from Go structs) go install github.com/gzuidhof/tygo@latest ``` ## Running tests Before changing anything, confirm your environment is set up: ```bash make test # both suites make test-frontend # Angular only (ChromeHeadless) npm test # the server's unit tests (vitest) ``` The server also has integration harnesses under `scripts/`, run one at a time — `npm run app`, `npm run auth`, `npm run records`, and so on. CI runs each as its own job; the authoritative list is `.github/workflows/server-ci.yaml`. Before pushing, run that whole list rather than a subset: `npm run typecheck` and `npm run build` read *different* TypeScript configs and can disagree. ## Start the dev environment Running from source needs two processes: the Angular frontend and the TypeScript server. ```bash cp .env.dev.example .env ``` ```bash # .env — bootstrap and secrets only; every other setting is Admin -> Configuration YOURPHR_WEB_LISTEN_PORT=9090 # frontend/proxy.conf.json proxies /api here YOURPHR_FAST_STORAGE=./data # the databases, the config store, the signing key ``` Leave the encryption key unset for dev and the databases are written in the clear — the server says so on every start. (The `.env.*.example` templates still describe the Go stack's keys and are being rewritten, [#676](https://github.com/jwilleke/yourphr/issues/676).) Then, in two terminals: ```bash # Terminal 1 make serve-frontend # Terminal 2 make serve-server ``` Open `http://localhost:4200`. The frontend dev server proxies API requests to the backend. *Modes:* YourPHR runs in __sandbox__ (talks only to synthetic-data test servers — the default for dev) or __prod__ (real servers). ## Credentials All user data is stored locally, including your account. On first start, register a new account, then visit the Sources tab. See [Connecting a new Source](https://docs.fastenhealth.com/getting-started/sandbox.html#connecting-a-new-source) for sandbox credentials. ## Source code layout See the [architecture overview](./docs/architecture/architecture.md) for the high-level map and diagrams. In short: __Frontend__ (`frontend/src/app/`) ``` ├── components # shared/partial components reused across pages ├── models # API models + view models (patient-access-brands/ is tygo-generated — don't edit) ├── pages # auth, dashboard, medical-sources, resource-detail, source-detail … ├── services # fasten-api.service.ts (backend client), auth, event-bus (SSE) └── widgets # dashboard widget components ``` __Backend__ (`backend/`) ``` ├── cmd │ ├── fasten # entry point: start / migrate / version │ └── relay # SMART-on-FHIR store-and-poll OAuth relay └── pkg ├── auth # HS256 JWT + bcrypt ├── database # DatabaseRepository interface + GORM (encrypted SQLite); migrations/ ├── models │ └── database # generated fhir_*.go (FHIRPath → indexed columns) — DO NOT hand-edit └── web ├── handler # API endpoints ├── middleware └── server.go ``` > __Generated code:__ `fhir_*.go` and `frontend/.../models/patient-access-brands/*.ts` are generated. Re-run `make generate-backend` when their inputs (`search-parameters.json`, tygo-exported Go structs) change, and commit the result. Details in [AGENTS.md](AGENTS.md). ## FAQ ### How do I run individual frontend tests? From `frontend/`, use `ng test --include`: ```bash npx ng test --include='**/badge.component.spec.ts' npx ng test --include='lib/**/*.spec.ts' ``` ### How do I work with Storybook? [Storybook](https://storybook.js.org) develops/tests frontend components in isolation: ```bash make serve-storybook # interactive make build-storybook # verify all stories build (a CI check) ``` ### Generate a JWT for local use ```bash curl -X POST http://localhost:9090/api/auth/signup -H 'Content-Type: application/json' -d '{"username":"user1","password":"user1"}' curl -X POST http://localhost:9090/api/auth/signin -H 'Content-Type: application/json' -d '{"username":"user1","password":"user1"}' ``` The default encryption key and admin credentials can be overridden via `YOURPHR_JWT_ISSUER_KEY`. ### Access the encrypted SQLite DB with IntelliJ - Download the latest `sqlite-jdbc-crypt` jar from . - IntelliJ → Data Source Properties → Driver tab → duplicate `Sqlite`, rename to `Sqlite (Encrypted)`, set Driver Files to the downloaded jar, remove the `Xerial Sqlite JDBC` jar, Apply/OK. - New Data Source → `Sqlite (Encrypted)` → Connection Type `Url only`: `jdbc:sqlite:fasten.db?cipher=sqlcipher&legacy=3&hmac_use=0&kdf_iter=4000&legacy_page_size=1024&key=` - Test Connection → Apply/OK. ### Flush the SQLite Write-Ahead-Log to the DB ```sql PRAGMA wal_checkpoint(TRUNCATE); ``` See . --- Work your magic and open a pull request — we love pull requests. Found something but short on time? [Open an issue](https://github.com/jwilleke/yourphr/issues/new/choose) and tell us.