This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Atomic is a FHIR-native web framework for JavaScript/Bun that treats FHIR resources as first-class citizens. Instead of adapting traditional MVC patterns, it uses FHIR's own concepts: StructureDefinitions for models, OperationDefinitions for business logic, and CapabilityStatements for API contracts.
fhir-framework/
├── packages/
│ └── core/ # @atomic-fhir/core package
│ ├── src/
│ │ ├── index.js # Main exports
│ │ ├── index.d.ts # TypeScript definitions
│ │ ├── core/ # Core framework components
│ │ │ ├── atomic.js # Main framework class
│ │ │ ├── router.js # HTTP routing
│ │ │ ├── resource-registry.js
│ │ │ ├── operation-registry.js
│ │ │ ├── hooks-manager.js # Hooks system
│ │ │ ├── filesystem-loader.js # Auto-discovery
│ │ │ ├── package-manager.js # FHIR IG packages
│ │ │ ├── capability-statement.js # Metadata endpoint
│ │ │ ├── validator.js
│ │ │ ├── resource.js # Resource definition helper
│ │ │ ├── operation.js # Operation definition helper
│ │ │ ├── define-hook.js # Hook definition helper
│ │ │ └── middleware.js # Middleware definition helper
│ │ └── storage/ # Storage adapters
│ │ ├── storage-manager.js
│ │ ├── adapter.js # Base adapter class
│ │ └── sqlite-adapter.js
│ ├── package.json # Package configuration
│ ├── tsconfig.json # TypeScript configuration
│ └── README.md
├── examples/ # Example servers
│ ├── minimal-server/ # Simplest server (3 lines)
│ ├── basic-server/ # Basic CRUD operations
│ ├── custom-handlers-server/ # Custom business logic
│ ├── r4-core-server/ # Full R4 Core with packages
│ ├── us-core-server/ # US Core IG implementation
│ ├── us-core-server-v8/ # US Core v8 with direct URL
│ ├── typescript-test/ # TypeScript example
│ ├── package-aware-server/ # Package management demo
│ └── manual-server/ # Without autoload
├── docs/ # Documentation
├── tests/ # Test suite
├── cli.js # CLI tool
├── package.json # Root package with workspaces
├── lerna.json # Monorepo management
├── README.md # Main documentation
└── CLAUDE.md # This file
When creating a new Atomic FHIR server, use this structure:
my-fhir-server/
├── src/ # All source code goes in src/
│ ├── server.js # Server configuration
│ ├── resources/ # FHIR resource definitions
│ │ ├── Patient.js
│ │ └── Observation.js
│ ├── operations/ # Custom FHIR operations
│ │ ├── match.js # $match operation
│ │ └── everything.js # $everything operation
│ ├── middleware/ # Express-style middleware
│ │ ├── auth.js
│ │ └── audit.js
│ └── hooks/ # Lifecycle hooks
│ ├── timestamps.js # Add timestamps to all resources
│ └── validation.js # Custom validation
├── packages/ # FHIR IG packages (.tgz files)
│ ├── hl7.fhir.r4.core.tgz
│ └── hl7.fhir.us.core.tgz
├── package.json
└── README.md
Key Points:
- All application code MUST go in the
src/directory - Autoload automatically discovers components from
src/subfolders - Packages go in root-level
packages/directory as .tgz files
# Install dependencies
bun install
# Run tests
bun test
# Run linter
bun run lint
# Run prettier
bun run format
# Run examples
cd examples/minimal-server
bun run dev
# Create new project with CLI
bun run cli.js new <project-name>
# Generate components
bun run cli.js generate resource <ResourceType>
bun run cli.js generate operation <operation-name>Modern Configuration Format:
const app = new Atomic({
packages: [
// NPM registry style
{
package: 'hl7.fhir.r4.core',
version: '4.0.1',
npmRegistry: 'https://get-ig.org'
},
// Direct URL download
{
package: 'hl7.fhir.us.core',
version: '7.0.0',
remoteUrl: 'https://packages2.fhir.org/packages/hl7.fhir.us.core/7.0.0'
}
]
});Auto-Registration: When loading R4 Core, all base resources are automatically registered with full CRUD capabilities.
All FHIR interaction types are supported:
defineResource({
resourceType: 'Patient',
capabilities: {
// Instance level
read: true, // GET [base]/[type]/[id]
vread: true, // GET [base]/[type]/[id]/_history/[vid]
update: true, // PUT [base]/[type]/[id]
'update-conditional': false, // PUT [base]/[type]?[search]
patch: false, // PATCH [base]/[type]/[id]
'patch-conditional': false, // PATCH [base]/[type]?[search]
delete: true, // DELETE [base]/[type]/[id]
'delete-conditional-single': false,
'delete-conditional-multiple': false,
'delete-history': false,
'delete-history-version': false,
'history-instance': true,
// Type level
'history-type': true, // GET [base]/[type]/_history
create: true, // POST [base]/[type]
'create-conditional': false, // POST with If-None-Exist
'search-type': true // GET [base]/[type]
}
});Full TypeScript definitions are available in packages/core/src/index.d.ts:
AtomicConfig- Server configurationResourceDefinition- Resource definition with capabilitiesOperationDefinition- Operation with parametersHookDefinition- Hook with type and resourcesHandlerContext- Context passed to handlersHandlerResponse- Response from custom handlers
The /metadata endpoint reports:
- All registered resources with their capabilities
- Supported profiles (base + constraint profiles)
- Available operations
- Server information
Example:
{
"type": "Patient",
"supportedProfile": [
"http://hl7.org/fhir/StructureDefinition/Patient",
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
],
"interaction": [
{ "code": "read" },
{ "code": "vread" },
{ "code": "update" },
{ "code": "create" },
{ "code": "search-type" }
]
}Hooks are separated from resources for reusability:
defineHook({
name: 'hook-name',
type: 'beforeCreate', // Hook type
resources: '*', // '*' for all, 'Patient', or ['Patient', 'Practitioner']
priority: 10, // Execution order (higher = first)
async handler(resource, context) {
return resource; // Return modified resource for 'before' hooks
}
});Available hook types:
beforeCreate/afterCreatebeforeUpdate/afterUpdatebeforeDelete/afterDeletebeforeRead/afterReadbeforeSearch/afterSearchbeforeValidate/afterValidate
Override any CRUD operation:
defineResource({
resourceType: 'Patient',
handlers: {
async create(req, context) {
const { storage, hooks, validator, config, packageManager } = context;
// Custom business logic
return {
status: 201,
headers: { 'Content-Type': 'application/fhir+json' },
body: resource // Auto-converted to JSON
};
}
}
});Default Configuration:
autoload: {
enabled: true, // Enabled by default
paths: {
resources: 'src/resources',
operations: 'src/operations',
middleware: 'src/middleware',
hooks: 'src/hooks',
implementationGuides: 'src/implementation-guides'
}
}The framework automatically discovers and loads components from these directories.
Request → Router → Handler → Storage → Response
↓ ↓ ↓
Route Match Resource SQLite
Operation
↓
Hooks Pipeline
(before/after)
-
Atomic (
atomic.js) - Main framework class- Manages configuration
- Coordinates all components
- Handles server startup
-
PackageManager (
package-manager.js)- Downloads packages from registries or URLs
- Loads and indexes FHIR resources
- Provides profile lookup for metadata
-
CapabilityStatement (
capability-statement.js)- Generates metadata endpoint
- Reports resource capabilities
- Lists supported profiles
-
Router (
router.js)- Handles HTTP routing
- Maps FHIR REST endpoints
- Executes operations
-
HooksManager (
hooks-manager.js)- Manages lifecycle hooks
- Priority-based execution
- Resource-specific filtering
-
FilesystemLoader (
filesystem-loader.js)- Auto-discovers components
- Loads from configured paths
- Handles dynamic imports
-
StorageManager (
storage-manager.js)- Abstracts storage operations
- Uses adapter pattern
- Default SQLite implementation
The middleware system is defined but NOT fully implemented:
defineMiddleware()function existsregisterMiddleware()method is optional/not implemented- Middleware auto-discovery may not work
The framework automatically adjusts paths for servers in src/:
- If server is in
src/server.js, basePath is adjusted up one level - This ensures autoload paths work correctly
Packages are loaded in this order:
- Check if .tgz file exists in
packages/directory - Download from registry or URL if not present
- Extract and index all FHIR resources
- Register base resources automatically
Resources from packages are registered with:
- Full CRUD capabilities by default
- Search parameters from the package
- No custom handlers (use local resources for custom logic)
The metadata endpoint reports profiles in order:
- Base resource definition (e.g.,
http://hl7.org/fhir/StructureDefinition/Patient) - Constraint profiles from all loaded packages
# Unit tests for core components
bun test packages/core/src/**/*.test.js
# Integration tests for examples
bun test examples/*/tests/*.test.js
# Type checking
cd examples/typescript-test
bun run typecheck- Bun Runtime: Native SQLite, fast startup, built-in TypeScript
- Package Caching: Downloaded packages are cached locally
- Lazy Loading: Resources loaded on demand
- Direct JSON Storage: SQLite with JSON columns
- Input Validation: Use StructureDefinition-based validation
- Authentication: Implement via middleware (not built-in)
- Audit Logging: Use hooks for audit trail
- Rate Limiting: Implement via middleware
- Create file in
src/resources/ResourceName.js - Export default
defineResource({ resourceType: 'ResourceName' }) - Resource is auto-discovered and registered
- Create file in
src/hooks/hook-name.js - Export default
defineHook({ name, type, resources, handler }) - Hook is auto-discovered and registered
- Create file in
src/operations/operation-name.js - Export default
defineOperation({ name, resource, handler }) - Operation is auto-discovered and registered
Package download fails:
- Check network connectivity
- Verify package name and version exist
- Try direct URL instead of registry
Auto-discovery not working:
- Ensure files are in correct
src/subdirectories - Check file exports default function
- Verify autoload is enabled in config
TypeScript errors:
- Run
bun installto get latest types - Check imports from
@atomic-fhir/core - Verify TypeScript version >= 5.0
Planned features (not yet implemented):
- Full middleware system
- PostgreSQL and MongoDB adapters
- Subscription support
- Bulk data operations
- GraphQL interface
- Full StructureDefinition validation
- SMART on FHIR authentication
- Code Style: Use Prettier for formatting
- Testing: Add tests for new features
- Documentation: Update docs for API changes
- TypeScript: Keep type definitions updated
- Examples: Add examples for new features
- DO NOT create files unless necessary
- ALWAYS prefer editing existing files
- NEVER create documentation unless requested
- Keep responses concise and focused
- Test changes before committing