$npx -y skills add softspark/ai-toolkit --skill medplum-rulesMedplum (FHIR healthcare) coding rules: style, patterns, security, testing. Triggers: medplum.config.mts, medplum.config.ts, FHIR, Medplum, Bot, Subscription, Questionnaire.
| 1 | # Medplum (FHIR healthcare) Rules |
| 2 | |
| 3 | These rules come from `app/rules/medplum/` in ai-toolkit. They cover |
| 4 | the project's standards for coding style, frameworks, patterns, |
| 5 | security, and testing in Medplum (FHIR healthcare). Apply them when writing or |
| 6 | reviewing Medplum (FHIR healthcare) code. |
| 7 | |
| 8 | # Medplum / FHIR Coding Style |
| 9 | |
| 10 | ## Resource Structure |
| 11 | - Every FHIR object must include `resourceType` as first field. |
| 12 | - Use PascalCase for resource types (`Patient`, `ServiceRequest`), camelCase for fields (`birthDate`, `valueQuantity`). |
| 13 | - Never hardcode resource IDs. Let the server assign them on create. |
| 14 | - Include `meta.profile` when creating resources that must conform to a StructureDefinition. |
| 15 | |
| 16 | ## References |
| 17 | - Use `createReference(resource)` from `@medplum/core` to build Reference objects. |
| 18 | - Always include `display` on references for human readability. |
| 19 | - Use `getReferenceString(resource)` for comparisons and logging — returns `ResourceType/id`. |
| 20 | - Use `parseReference(ref)` to extract resourceType and id from a reference string. |
| 21 | - Never concatenate strings to build references manually. |
| 22 | |
| 23 | ## CodeableConcepts & Coding |
| 24 | - Always include `system`, `code`, and `display` in every Coding element. |
| 25 | - Use standard terminology URIs: `http://loinc.org`, `http://snomed.info/sct`, `http://hl7.org/fhir/sid/icd-10-cm`. |
| 26 | - Use `getCodeBySystem(cc, system)` to find codes; `setCodeBySystem(cc, system, code)` to set them. |
| 27 | - Prefer `CodeableConcept` over plain `Coding` when the FHIR spec allows both — it supports multiple codings and free text. |
| 28 | |
| 29 | ## Identifiers |
| 30 | - Use `identifier` arrays with `system` + `value` for external IDs (MRN, NPI, SSN). |
| 31 | - Use `getIdentifier(resource, system)` and `setIdentifier(resource, system, value)` helpers. |
| 32 | - Identifier systems must be absolute URIs (e.g., `http://hl7.org/fhir/sid/us-npi`). |
| 33 | - Use `createResourceIfNoneExist(resource, 'identifier=system|value')` for idempotent creates. |
| 34 | |
| 35 | ## Extensions |
| 36 | - Use the `extension` array with `url` and typed `value[x]` fields. |
| 37 | - Prefer official HL7/US Core extensions over custom ones where they exist. |
| 38 | - Use `getExtension(resource, url)` and `getExtensionValue(resource, url)` helpers. |
| 39 | |
| 40 | ## Bundles |
| 41 | - Use `urn:uuid:<uuid>` for internal references between entries in a transaction Bundle. |
| 42 | - Every Bundle entry must have `request.method` (`POST`, `PUT`, `DELETE`) and `request.url`. |
| 43 | - Include `fullUrl` on entries that are referenced by other entries. |
| 44 | - Use conditional references (`Practitioner?identifier=npi|123`) for existing resources. |
| 45 | |
| 46 | ## HIPAA-Aware Coding |
| 47 | - Identifiers like SSN, MRN, and insurance IDs are PHI — never log raw values to console or external services. |
| 48 | - Use a safe logging utility (e.g., `safeLog()`) for any output that might contain patient data. Never `console.log` raw FHIR resources. |
| 49 | - Reference `display` strings may contain patient names — treat as PHI in logs and error messages. |
| 50 | - Every new data access path or admin operation must include corresponding `AuditEvent` creation. No exceptions. |
| 51 | - When audit logging fails (Medplum unreachable), write to a fallback store — audit events must never be silently dropped. |
| 52 | - See `security.md` rules for full HIPAA, access policy, and PHI handling requirements. |
| 53 | |
| 54 | ## Formatting |
| 55 | - Use `formatHumanName()`, `formatAddress()`, `formatDate()`, `formatQuantity()` for display strings. |
| 56 | - Use `getDisplayString(resource)` as a universal fallback for any resource's display name. |
| 57 | - Never manually concatenate name parts — FHIR names have `given[]`, `family`, `prefix[]`, `suffix[]`. |
| 58 | |
| 59 | # Medplum Frameworks |
| 60 | |
| 61 | ## @medplum/core — SDK Client |
| 62 | - Use `MedplumClient` for all FHIR operations. Never use raw `fetch` against Medplum endpoints. |
| 63 | - Use `medplum.createResource()`, `readResource()`, `updateResource()`, `deleteResource()` for CRUD. |
| 64 | - Use `medplum.searchResources()` for typed arrays. Use `medplum.searchOne()` when expecting a single result. |
| 65 | - Use `medplum.executeBatch()` for transaction Bundles — groups multiple operations atomically. |
| 66 | - Use `medplum.upsertResource(resource, query)` for atomic create-or-update. |
| 67 | - Use `medplum.createResourceIfNoneExist(resource, query)` for idempotent creation. |
| 68 | - Configure `autoBatchTime` on MedplumClient to auto-batch concurrent GET requests. Use `Promise.all()` instead of sequential `await` to benefit from batching. |
| 69 | |
| 70 | ## @medplum/fhirtypes — Type Safety |
| 71 | - Import FHIR types directly: `import { Patient, Observation } from '@medplum/fhirtypes'`. |
| 72 | - Use TypeScript types for all FHIR resources — never use `any` for resource data. |
| 73 | - Cast `event.input` in bot handlers: `const patient = event.input as Patient`. |
| 74 | - Use optional chaining for nested FHIR fields: `patient.name?.[0]?.given?.[0]`. |
| 75 | |
| 76 | ## @medplum/react — UI Components |
| 77 | - Wrap app with `<MedplumProvider c |