> ## Documentation Index
> Fetch the complete documentation index at: https://alliancebioversityciat-alliance-risk-analysis-tool.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompt Versioning

> Version history, retrieval, and change tracking for AI prompts

The CGIAR Risk Intelligence Tool implements comprehensive version control for AI prompts, allowing full audit trails, rollback capabilities, and change tracking.

## Version Strategy

### Current Version Pattern

Prompts follow a **snapshot-on-update** versioning strategy:

* The `prompts` table stores the **latest version** only (no JOINs needed for reads)
* On every update, the current state is snapshotted to `prompt_versions` table
* Version number is auto-incremented on each update
* Version 1 is created automatically when the prompt is first created

### Database Schema

```prisma theme={null}
model Prompt {
  id      String @id @default(uuid())
  name    String
  version Int    @default(1)  // Current version
  // ... other fields
  
  versions PromptVersion[]  // Historical snapshots
  changes  PromptChange[]   // Audit trail
}

model PromptVersion {
  id       String @id @default(uuid())
  promptId String
  version  Int
  
  // Snapshot of all prompt fields at this version
  name               String
  section            AgentSection
  systemPrompt       String
  userPromptTemplate String
  // ... all other prompt fields
  
  createdAt DateTime @default(now())
  
  @@unique([promptId, version])
}

model PromptChange {
  id         String           @id @default(uuid())
  promptId   String
  version    Int
  changeType PromptChangeType // CREATE, UPDATE, DELETE, ACTIVATE, DEACTIVATE
  changes    Json             // { field: { old: value, new: value } }
  comment    String?
  authorId   String
  createdAt  DateTime         @default(now())
}
```

## Endpoints

### Get Prompt (Current or Historical Version)

**`GET /api/admin/prompts/:id`**

Retrieve the current version or a specific historical version.

#### Query Parameters

**version** `number`

Historical version number to retrieve (omit for current version)

**Example:** `2`

#### Example: Get Current Version

```bash theme={null}
curl -X GET https://api.example.com/api/admin/prompts/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

#### Example: Get Historical Version

```bash theme={null}
curl -X GET "https://api.example.com/api/admin/prompts/550e8400-e29b-41d4-a716-446655440000?version=2" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

#### Response

```json theme={null}
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Gap Detection — Market Risk v2",
    "version": 2,
    "systemPrompt": "You are an expert agricultural risk analyst...",
    // ... all prompt fields
    "createdAt": "2026-02-20T10:00:00.000Z",
    "updatedAt": "2026-03-01T14:30:00.000Z"
  }
}
```

### Get Change History

**`GET /api/admin/prompts/:id/history`**

Returns the full version history of a prompt, including diffs between versions, who made each change, and when.

#### Response Fields

**data** `array`

Array of change records

**data\[].id** `string`

Change record UUID

**data\[].version** `number`

Version number this change created

**data\[].changeType** `string`

Type of change

**Values:** `CREATE`, `UPDATE`, `DELETE`, `ACTIVATE`, `DEACTIVATE`

**data\[].changes** `object`

Field-level diff object

Format: `{ field: { old: value, new: value } }`

**Example:**

```json theme={null}
{
  "systemPrompt": {
    "old": "You are an expert risk analyst.",
    "new": "You are an expert agricultural risk analyst with 15+ years of experience."
  },
  "tags": {
    "old": ["v2", "production"],
    "new": ["v3", "production", "reviewed"]
  }
}
```

**data\[].comment** `string`

Optional comment explaining the change

**data\[].author** `object`

User who made the change

* `id` (string): User UUID
* `email` (string): User email

**data\[].createdAt** `string`

ISO 8601 timestamp of the change

#### Example Request

```bash theme={null}
curl -X GET https://api.example.com/api/admin/prompts/550e8400-e29b-41d4-a716-446655440000/history \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

#### Example Response

```json theme={null}
{
  "data": [
    {
      "id": "change-uuid-3",
      "version": 3,
      "changeType": "UPDATE",
      "changes": {
        "systemPrompt": {
          "old": "You are an expert risk analyst.",
          "new": "You are an expert agricultural risk analyst with 15+ years of experience."
        },
        "tags": {
          "old": ["v2", "production"],
          "new": ["v3", "production", "reviewed"]
        }
      },
      "comment": "Enhanced system prompt with experience level",
      "author": {
        "id": "user-uuid-456",
        "email": "admin@example.com"
      },
      "createdAt": "2026-03-04T14:30:00.000Z"
    },
    {
      "id": "change-uuid-2",
      "version": 2,
      "changeType": "UPDATE",
      "changes": {
        "name": {
          "old": "Gap Detection — Market Risk v1",
          "new": "Gap Detection — Market Risk v2"
        },
        "userPromptTemplate": {
          "old": "Identify gaps for: {{categories}}",
          "new": "Given the following business plan section:\n\n{{document_excerpt}}\n\nIdentify gaps in risk coverage for the following categories: {{categories}}"
        }
      },
      "comment": null,
      "author": {
        "id": "user-uuid-123",
        "email": "editor@example.com"
      },
      "createdAt": "2026-03-01T10:00:00.000Z"
    },
    {
      "id": "change-uuid-1",
      "version": 1,
      "changeType": "CREATE",
      "changes": {},
      "comment": "Initial creation",
      "author": {
        "id": "user-uuid-123",
        "email": "editor@example.com"
      },
      "createdAt": "2026-02-20T10:00:00.000Z"
    }
  ]
}
```

## Version Lifecycle

### 1. Creation (v1)

When a prompt is created via `POST /api/admin/prompts/create`:

```typescript theme={null}
// Prisma transaction:
1. Create prompt record with version: 1
2. Create initial version snapshot in prompt_versions
3. Create change record with changeType: CREATE
```

### 2. Update (v2, v3, ...)

When a prompt is updated via `PUT /api/admin/prompts/:id/update`:

```typescript theme={null}
// Prisma transaction:
1. Read current prompt state
2. Snapshot current state to prompt_versions (preserves previous version)
3. Compute field-level diffs (old vs new)
4. Increment version number
5. Update prompt record with new values
6. Create change record with changeType: UPDATE and diffs
```

### 3. Toggle Active State

When toggling via `POST /api/admin/prompts/:id/toggle-active`:

```typescript theme={null}
// Prisma transaction:
1. Snapshot current state to prompt_versions
2. Increment version
3. Flip isActive flag
4. Create change record with changeType: ACTIVATE or DEACTIVATE
```

### 4. Deletion

When deleting via `DELETE /api/admin/prompts/:id`:

```typescript theme={null}
// Option A: Delete entire prompt
1. Create change record with changeType: DELETE
2. Delete prompt (cascades to versions, comments, changes)

// Option B: Delete specific version
1. Delete version snapshot from prompt_versions
2. Create change record documenting version deletion
```

## Diff Computation

The `changes` field in `PromptChange` records contains field-level diffs:

```typescript theme={null}
type ChangesDiff = {
  [field: string]: {
    old: any;
    new: any;
  }
};

// Example:
{
  "systemPrompt": {
    "old": "Original text...",
    "new": "Updated text..."
  },
  "tags": {
    "old": ["v1"],
    "new": ["v2", "reviewed"]
  },
  "isActive": {
    "old": false,
    "new": true
  }
}
```

Only changed fields are included in the diff.

## Rollback Pattern

To rollback to a previous version:

1. Fetch the historical version: `GET /api/admin/prompts/:id?version=2`
2. Extract all fields from the response
3. Update the prompt with those values: `PUT /api/admin/prompts/:id/update`

```typescript theme={null}
// Fetch version 2
const { data: v2 } = await fetch('/api/admin/prompts/550e8400-e29b-41d4-a716-446655440000?version=2');

// Rollback by updating with v2 values
await fetch('/api/admin/prompts/550e8400-e29b-41d4-a716-446655440000/update', {
  method: 'PUT',
  body: JSON.stringify({
    name: v2.name,
    systemPrompt: v2.systemPrompt,
    userPromptTemplate: v2.userPromptTemplate,
    // ... all other fields
  })
});

// This creates version 4 (a copy of version 2)
```

## Version Retention

All versions are retained indefinitely unless:

* The entire prompt is deleted (CASCADE deletes all versions)
* A specific version is explicitly deleted: `DELETE /api/admin/prompts/:id?version=2`

**Recommendation:** Implement a cleanup policy for old versions (e.g., keep last 10 versions per prompt).

## Conflict Detection

The update endpoint implements optimistic locking to detect concurrent modifications:

```typescript theme={null}
// Pseudo-code in PromptsService.update():
const currentPrompt = await prisma.prompt.findUnique({ where: { id } });

if (currentPrompt.updatedAt > clientLastReadTimestamp) {
  throw new ConflictException('Prompt was modified by another user');
}

// Proceed with update...
```

This prevents lost updates in multi-user scenarios.

## Best Practices

### 1. Version Naming

Include version numbers in the prompt name for easy identification:

```
✅ "Gap Detection — Market Risk v3"
❌ "Gap Detection — Market Risk (updated)"
```

### 2. Change Comments

Use the comment field in change records to explain significant updates:

```typescript theme={null}
await promptsService.update(id, dto, userId, {
  comment: 'Refined output format based on user feedback'
});
```

### 3. Version Review

Before activating a new version, review the change history:

```bash theme={null}
# Get change history
curl /api/admin/prompts/:id/history

# Compare current vs previous version
curl /api/admin/prompts/:id?version=2  # Old
curl /api/admin/prompts/:id             # New

# If satisfied, activate
curl -X POST /api/admin/prompts/:id/toggle-active
```

### 4. Version Cleanup

Periodically delete old version snapshots to reduce database size:

```bash theme={null}
# Delete version 1 (keep versions 2-5)
curl -X DELETE "/api/admin/prompts/:id?version=1"
```

## Source Code

* Versioning logic: `packages/api/src/prompts/prompts.service.ts`
* Change history service: `packages/api/src/prompts/change-history.service.ts`
* Get prompt endpoint: `packages/api/src/prompts/prompts.controller.ts:141`
* Get history endpoint: `packages/api/src/prompts/prompts.controller.ts:244`


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.