> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ferrum.thalamiq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Versioning & History

> How Ferrum handles resource versioning, history tracking, and version-aware operations.

## Implementation Features

**Spec**: [FHIR Versioning](https://hl7.org/fhir/R4/http.html#history),
[Version-aware Updates](https://hl7.org/fhir/R4/http.html#versionaware)

| Feature                    | Support      | Notes                                       |
| -------------------------- | ------------ | ------------------------------------------- |
| **Sequential Versioning**  | Full         | Integer versionIds starting from 1          |
| **Instance History**       | Full         | All versions of a single resource           |
| **Type History**           | Full         | All versions of a resource type             |
| **System History**         | Full         | All versions across all resource types      |
| **Versioned Read (vread)** | Full         | Read specific version by versionId          |
| **Version-aware Updates**  | Full         | If-Match header support                     |
| **History Bundles**        | Full         | History replication via Bundle.type=history |
| **Soft Delete History**    | Full         | Deleted versions preserved in history       |
| **Hard Delete History**    | Configurable | Complete removal including history          |
| **History Parameters**     | Full         | `_count`, `_since`, `_sort` support         |

## Version Management

### Sequential Integer Versions

Ferrum uses **sequential integer versions** starting at 1 for each resource:

```jsonc theme={null}
// First version (create)
{
  "resourceType": "Patient",
  "id": "123",
  "meta": {
    "versionId": "1",
    "lastUpdated": "2026-01-12T10:00:00Z"
  },
  "name": [{ "family": "Doe", "given": ["John"] }]
}

// Second version (update)
{
  "resourceType": "Patient",
  "id": "123",
  "meta": {
    "versionId": "2",
    "lastUpdated": "2026-01-12T11:00:00Z"
  },
  "name": [{ "family": "Doe", "given": ["Jane"] }]
}
```

### Version Lifecycle

Each CRUD operation affects versioning differently:

| Operation         | Version Behavior         | Example                                            |
| ----------------- | ------------------------ | -------------------------------------------------- |
| **CREATE**        | Creates version 1        | `POST /Patient` → version 1                        |
| **UPDATE**        | Increments version       | `PUT /Patient/123` → version 2, 3, etc.            |
| **PATCH**         | Increments version       | `PATCH /Patient/123` → version 2, 3, etc.          |
| **DELETE** (soft) | Creates deletion version | `DELETE /Patient/123` → version 3 (marked deleted) |
| **DELETE** (hard) | Removes all versions     | `DELETE /Patient/123` → all history gone           |

### Database Storage

Ferrum stores versions in two tables:

* **`resources`**: All resource versions with metadata
* **`resource_versions`**: Version counter per resource

```sql theme={null}
-- Current version lookup (fast)
SELECT * FROM resources
WHERE resource_type = 'Patient' AND id = '123' AND is_current = true;

-- Specific version lookup
SELECT * FROM resources
WHERE resource_type = 'Patient' AND id = '123' AND version_id = 2;
```

## Versioned Read (vread)

**Spec**: [vread](https://hl7.org/fhir/R4/http.html#vread)

Read a specific version of a resource:

```bash theme={null}
# Read version 2 of Patient/123
curl http://localhost:8080/fhir/Patient/123/_history/2
```

### Response Behavior

**Successful vread** (`200 OK`):

```json theme={null}
{
  "resourceType": "Patient",
  "id": "123",
  "meta": {
    "versionId": "2",
    "lastUpdated": "2026-01-12T11:00:00Z"
  },
  "name": [{ "family": "Doe", "given": ["Jane"] }]
}
```

**Version not found** (`404 Not Found`):

```json theme={null}
{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "not-found",
      "diagnostics": "Version 5 of Patient/123 not found"
    }
  ]
}
```

**Deleted version** (`410 Gone`):

```json theme={null}
{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "deleted",
      "diagnostics": "Version 3 of Patient/123 was deleted"
    }
  ]
}
```

### HEAD Support

Check version existence without fetching body:

```bash theme={null}
curl -I http://localhost:8080/fhir/Patient/123/_history/2

# 200 OK = version exists
# 404 Not Found = version doesn't exist
# 410 Gone = version was a deletion
```

### Caching Headers

vread responses include immutable caching headers since versions never change:

```http theme={null}
HTTP/1.1 200 OK
ETag: W/"2"
Last-Modified: Mon, 12 Jan 2026 11:00:00 GMT
Cache-Control: public, max-age=31536000, immutable
```

## History Operations

### Instance History

**Spec**: [Instance History](https://hl7.org/fhir/R4/http.html#history)

Get all versions of a specific resource:

```bash theme={null}
curl http://localhost:8080/fhir/Patient/123/_history
```

**Response** (Bundle with type="history"):

```json theme={null}
{
  "resourceType": "Bundle",
  "type": "history",
  "total": 3,
  "entry": [
    {
      "resource": {
        "resourceType": "Patient",
        "id": "123",
        "meta": { "versionId": "2", "lastUpdated": "2026-01-12T11:00:00Z" },
        "name": [{ "family": "Doe", "given": ["Jane"] }]
      },
      "request": { "method": "PUT", "url": "Patient/123" }
    },
    {
      "resource": {
        "resourceType": "Patient",
        "id": "123",
        "meta": { "versionId": "1", "lastUpdated": "2026-01-12T10:00:00Z" },
        "name": [{ "family": "Doe", "given": ["John"] }]
      },
      "request": { "method": "POST", "url": "Patient" }
    }
  ]
}
```

### Type History

Get history for all resources of a specific type:

```bash theme={null}
curl http://localhost:8080/fhir/Patient/_history
```

### System History

Get history across all resource types:

```bash theme={null}
curl http://localhost:8080/fhir/_history
```

### History Parameters

All history endpoints support standard parameters:

| Parameter | Description                   | Example                                                    |
| --------- | ----------------------------- | ---------------------------------------------------------- |
| `_count`  | Limit results                 | `?_count=10`                                               |
| `_since`  | Only versions after timestamp | `?_since=2026-01-12T10:00:00Z`                             |
| `_sort`   | Sort direction                | `?_sort=_lastUpdated` (asc), `?_sort=-_lastUpdated` (desc) |

```bash theme={null}
# Get last 5 versions since yesterday
curl "http://localhost:8080/fhir/Patient/123/_history?_count=5&_since=2026-01-11T00:00:00Z"
```

### History Entry Methods

Ferrum automatically determines the HTTP method for each history entry:

| Version | Condition     | Method   | Notes             |
| ------- | ------------- | -------- | ----------------- |
| 1       | First version | `POST`   | Resource creation |
| 2+      | Not deleted   | `PUT`    | Resource update   |
| Any     | Deleted flag  | `DELETE` | Resource deletion |

## Version-Aware Operations

### Optimistic Locking with If-Match

**Spec**: [Version-aware Updates](https://hl7.org/fhir/R4/http.html#versionaware)

Always use `If-Match` for safe updates:

```bash theme={null}
# 1. Read current version
curl -i http://localhost:8080/fhir/Patient/123
# ETag: W/"2"

# 2. Update with version check
curl -X PUT http://localhost:8080/fhir/Patient/123 \
  -H "Content-Type: application/fhir+json" \
  -H 'If-Match: W/"2"' \
  -d '{
    "resourceType": "Patient",
    "id": "123",
    "name": [{ "family": "Doe", "given": ["Jane"] }]
  }'
```

### Version Conflict Handling

**Successful update** (`200 OK`):

```json theme={null}
{
  "resourceType": "Patient",
  "id": "123",
  "meta": {
    "versionId": "3",
    "lastUpdated": "2026-01-12T12:00:00Z"
  }
}
```

**Version conflict** (`412 Precondition Failed`):

```json theme={null}
{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "conflict",
      "diagnostics": "Version conflict: expected 2, actual 3"
    }
  ]
}
```

### Recovery from Conflicts

When version conflicts occur:

1. **Refetch** the current version
2. **Merge** your changes with current state
3. **Retry** with new version

```bash theme={null}
# Conflict occurred, refetch current state
curl -i http://localhost:8080/fhir/Patient/123
# ETag: W/"3"

# Retry with correct version
curl -X PUT http://localhost:8080/fhir/Patient/123 \
  -H 'If-Match: W/"3"' \
  -d '{ /* merged changes */ }'
```

## Delete and History

### Soft Delete (Default)

With soft delete (`hard_delete: false`):

```bash theme={null}
curl -X DELETE http://localhost:8080/fhir/Patient/123
```

**Behavior**:

* Creates new version marked as deleted
* History remains accessible
* `GET /Patient/123` → `410 Gone`
* `GET /Patient/123/_history` → `200 OK` (full history)
* `GET /Patient/123/_history/3` → `410 Gone` (deletion version)

### Hard Delete

With hard delete (`hard_delete: true`):

```bash theme={null}
curl -X DELETE http://localhost:8080/fhir/Patient/123
```

**Behavior**:

* Physically removes all versions from database
* History becomes inaccessible
* `GET /Patient/123` → `404 Not Found`
* `GET /Patient/123/_history` → `404 Not Found`
* Enables history deletion endpoints

### History Deletion (Hard Delete Only)

When hard delete is enabled, you can delete specific versions or entire history:

```bash theme={null}
# Delete specific version
curl -X DELETE http://localhost:8080/fhir/Patient/123/_history/2

# Delete entire history
curl -X DELETE http://localhost:8080/fhir/Patient/123/_history
```

<Warning>
  **Irreversible Operation**: Hard delete permanently removes all data and
  history. This cannot be undone. Use with extreme caution in production.
</Warning>

## History Bundles (Replication)

**Spec**: [Bundle.type=history](https://hl7.org/fhir/R4/bundle.html)

Ferrum supports history bundle replication for data synchronization:

```bash theme={null}
curl -X POST http://localhost:8080/fhir \
  -H "Content-Type: application/fhir+json" \
  -d '{
    "resourceType": "Bundle",
    "type": "history",
    "entry": [
      {
        "resource": {
          "resourceType": "Patient",
          "id": "123",
          "meta": { "versionId": "1" },
          "name": [{ "family": "Doe", "given": ["John"] }]
        }
      },
      {
        "resource": {
          "resourceType": "Patient",
          "id": "123",
          "meta": { "versionId": "2" },
          "name": [{ "family": "Doe", "given": ["Jane"] }]
        }
      }
    ]
  }'
```

### History Bundle Processing

Ferrum processes history bundles with these rules:

1. **Sequential Processing**: Entries processed in order (not atomic)
2. **ID Preservation**: Resource IDs preserved from bundle
3. **Version Checking**: Older/duplicate versions ignored
4. **Create or Update**: Creates if resource doesn't exist, updates if newer
5. **Delete Handling**: Entries with `response.status="410 Gone"` trigger deletion

### Version Conflict Resolution

```json theme={null}
{
  "resourceType": "Bundle",
  "type": "batch-response",
  "entry": [
    {
      "response": {
        "status": "200 OK",
        "location": "Patient/123/_history/2"
      }
    },
    {
      "response": {
        "status": "200 OK",
        "outcome": {
          "resourceType": "OperationOutcome",
          "issue": [
            {
              "severity": "information",
              "code": "informational",
              "diagnostics": "Ignored older or duplicate history entry"
            }
          ]
        }
      }
    }
  ]
}
```

## Performance Considerations

### Indexing Strategy

Ferrum indexes key version-related columns:

```sql theme={null}
-- Primary lookup indexes
CREATE INDEX idx_resources_current ON resources (resource_type, id, is_current);
CREATE INDEX idx_resources_version ON resources (resource_type, id, version_id);
CREATE INDEX idx_resources_updated ON resources (last_updated DESC);

-- History query optimization
CREATE INDEX idx_resources_history ON resources (resource_type, id, last_updated DESC, version_id DESC);
```

### History Query Optimization

For large history sets, use pagination:

```bash theme={null}
# Get first page
curl "http://localhost:8080/fhir/Patient/_history?_count=50"

# Get next page using _cursor from previous response
curl "http://localhost:8080/fhir/Patient/_history?_count=50&_cursor=eyJ..."
```

### Version Cleanup

Configure version limits to manage storage:

```yaml theme={null}
fhir:
  max_history_versions: 100 # Keep last 100 versions per resource
  history_cleanup_enabled: true
  history_cleanup_interval: "24h"
```

<Note>
  **Version Cleanup**: When enabled, Ferrum automatically removes old versions
  beyond the configured limit, keeping the most recent versions.
</Note>

## Configuration

Key configuration options for versioning and history:

```yaml theme={null}
fhir:
  # Delete behavior
  hard_delete: false # Use soft delete (preserves history)

  # History limits
  max_history_versions: 0 # 0 = unlimited, >0 = keep N versions
  history_cleanup_enabled: false
  history_cleanup_interval: "24h"

  # History bundle processing
  allow_history_bundles: true

  # Performance
  history_page_size: 100 # Default page size for history queries

  # Interactions (can be disabled per type)
  interactions:
    instance:
      history: true # GET /Patient/123/_history
      vread: true # GET /Patient/123/_history/2
    type:
      history: true # GET /Patient/_history
    system:
      history: true # GET /_history
      history_bundle: true # POST / with Bundle.type=history
```

## Error Handling

Common versioning-related errors:

| HTTP Status               | Meaning               | Example                 |
| ------------------------- | --------------------- | ----------------------- |
| `404 Not Found`           | Version doesn't exist | Wrong versionId         |
| `410 Gone`                | Version was deleted   | Reading deleted version |
| `412 Precondition Failed` | Version conflict      | If-Match mismatch       |

### Error Response Examples

**Version not found**:

```json theme={null}
{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "not-found",
      "diagnostics": "Version 5 of Patient/123 not found"
    }
  ]
}
```

**Version conflict**:

```json theme={null}
{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "conflict",
      "diagnostics": "Version conflict: expected 2, actual 3. Resource was modified by another client."
    }
  ]
}
```

## Testing Your Implementation

Use the interactive API playground to test versioning operations:

<CardGroup cols={2}>
  <Card title="Versioned Read" href="/api-reference/history/versioned-read">
    Test vread operations
  </Card>

  <Card title="Instance History" href="/api-reference/history/resource">
    Browse resource history
  </Card>

  <Card title="Type History" href="/api-reference/history/type">
    Query type-level history
  </Card>

  <Card title="System History" href="/api-reference/history/system">
    Access system-wide history
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="CRUD Operations" href="/server/crud-operations">
    Learn about create, read, update, delete
  </Card>

  <Card title="Search Operations" href="/server/search">
    Query resources efficiently
  </Card>

  <Card title="Batch & Transaction" href="/server/batch-and-transactions">
    Perform multiple operations atomically
  </Card>

  <Card title="Configuration" href="/getting-started/configuration">
    Configure versioning behavior
  </Card>
</CardGroup>
