Files
Peter.Morton 9286ee8927 feat: Add X-Verint-KAB-Original-URL header to document exports
Adds HTTP response header containing original Google Drive URL
for exported documents to enable content traceability and auditing.

- Adds X-Verint-KAB-Original-URL header to successful export responses
- Header format: https://drive.google.com/file/d/{fileId}
- Present for all export formats (PDF, DOCX, plain text)
- Header omitted on error responses (4xx/5xx)
- 18 new tests (9 contract + 9 integration)
- Zero new dependencies
- Performance: 0.000019ms overhead per request

Implements:
- FR-001: Header present on successful exports (200 OK)
- FR-002: Header absent on error responses
- FR-003: Standard header name X-Verint-KAB-Original-URL
- FR-004: Standard URL format with file ID
- FR-005: Uses validated document.id from Google Drive API
- FR-006: Header present regardless of file accessibility
- FR-007: Consistent across all export formats
- FR-008: Minimal performance impact (< 5ms requirement)

Testing:
- Contract tests validate header presence, format, and error handling
- Integration tests verify behavior across formats and permissions
- All 18 tests passing
- 100% requirements coverage

Documentation:
- Feature specification (specs/001-gdrive-url-header/spec.md)
- Implementation plan (plan.md)
- Technical research (research.md)
- Data model (data-model.md)
- API contract (contracts/response-headers.md)
- User guide (quickstart.md)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-27 16:04:54 -05:00

481 lines
13 KiB
Markdown

# HTTP Response Headers Contract
**Feature**: 001-gdrive-url-header
**Date**: 2026-03-27
**Version**: 1.0.0
**Status**: Draft
## Overview
This document defines the contract for the `X-Verint-KAB-Original-URL` HTTP response header added to document export responses. This header provides clients with the original Google Drive URL for traceability and auditing purposes.
---
## Header Specification
### Header Name
```
X-Verint-KAB-Original-URL
```
**Properties**:
- **Name**: `X-Verint-KAB-Original-URL` (case-insensitive per HTTP spec)
- **Type**: Custom HTTP header (uses `X-` prefix per client requirements)
- **Category**: Response header (never in requests)
**Note**: The `X-` prefix is deprecated in RFC 6648 but required by client naming conventions as documented in the feature specification.
---
### Header Value
**Format**:
```
https://drive.google.com/file/d/{fileId}
```
**Components**:
- **Scheme**: `https://` (required, never `http://`)
- **Domain**: `drive.google.com` (fixed)
- **Path**: `/file/d/{fileId}` (fixed structure)
- **File ID**: Alphanumeric string (33-44 characters typical)
**Characteristics**:
- Single-line string (no line breaks)
- No query parameters
- No URL fragments (#)
- No authentication tokens in URL
- Publicly addressable (permissions enforced by Google Drive)
**Example Values**:
```
X-Verint-KAB-Original-URL: https://drive.google.com/file/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms
X-Verint-KAB-Original-URL: https://drive.google.com/file/d/2CyjMWt1YSB6oGNetLcEaCkhnVVsruqmct85PhzF3vqnt
```
---
## Presence Rules
### When Header is Present (200 OK Responses)
The `X-Verint-KAB-Original-URL` header **MUST** be present in the following scenarios:
1. **Successful Document Export** (200 OK)
- Any supported export format (PDF, DOCX, plain text, etc.)
- Document metadata successfully retrieved from Google Drive
- Document content successfully retrieved from Google Drive
- Response headers set before content streaming
**Example**:
```http
GET /documents/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms HTTP/1.1
Host: adapter.example.com
HTTP/1.1 200 OK
Content-Type: application/pdf
X-Request-Id: req_550e8400-e29b-41d4-a716-446655440000
Content-Disposition: inline; filename="Document.pdf"
Content-Length: 245760
X-Verint-KAB-Original-URL: https://drive.google.com/file/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms
[PDF content bytes...]
```
### When Header is Absent (Error Responses)
The `X-Verint-KAB-Original-URL` header **MUST NOT** be present in error scenarios:
1. **Document Not Found** (404)
- Invalid document ID
- Document does not exist in Google Drive
- Service account lacks access to document
2. **Unauthorized** (401)
- Service account authentication failed
- Invalid or expired credentials
3. **Forbidden** (403)
- Unsupported export format
- Document type cannot be exported
4. **Payload Too Large** (413)
- Document exceeds size limits
5. **Server Errors** (5xx)
- Internal server error
- Google Drive API unavailable
- Stream error during content transfer
**Example (Error Response)**:
```http
GET /documents/INVALID_ID HTTP/1.1
Host: adapter.example.com
HTTP/1.1 404 Not Found
X-Request-Id: req_660f9511-f3ac-52e5-b827-557766551111
Document not found
```
**Rationale**: Omitting the header on errors provides a clear signal to clients that the export failed and no valid Drive URL is available.
---
## Response Examples
### Example 1: PDF Export (Success)
**Request**:
```http
GET /documents/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms HTTP/1.1
Host: adapter.example.com
```
**Response**:
```http
HTTP/1.1 200 OK
Content-Type: application/pdf
X-Request-Id: req_550e8400-e29b-41d4-a716-446655440000
Content-Disposition: inline; filename="Q4-Financial-Report.pdf"
Content-Length: 245760
X-Verint-KAB-Original-URL: https://drive.google.com/file/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms
[245760 bytes of PDF content]
```
**Header Validation**:
- ✅ Header name is `X-Verint-KAB-Original-URL`
- ✅ Header value starts with `https://drive.google.com/file/d/`
- ✅ File ID matches request URL (`1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms`)
- ✅ URL is well-formed and accessible
---
### Example 2: DOCX Export (Success)
**Request**:
```http
GET /documents/2CyjMWt1YSB6oGNetLcEaCkhnVVsruqmct85PhzF3vqnt HTTP/1.1
Host: adapter.example.com
```
**Response**:
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
X-Request-Id: req_660f9511-f3ac-52e5-b827-557766551111
Content-Disposition: inline; filename="Meeting-Notes.docx"
Content-Length: 52480
X-Verint-KAB-Original-URL: https://drive.google.com/file/d/2CyjMWt1YSB6oGNetLcEaCkhnVVsruqmct85PhzF3vqnt
[52480 bytes of DOCX content]
```
**Header Validation**:
- ✅ Header present on DOCX export
- ✅ URL format matches specification
- ✅ File ID matches request
---
### Example 3: Plain Text Export (Success)
**Request**:
```http
GET /documents/3DzkNXu2ZTC7pHOfuMdFbDliowWtsvrndu96QiaG4wrO HTTP/1.1
Host: adapter.example.com
```
**Response**:
```http
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
X-Request-Id: req_770fa622-g4bd-63f6-c938-668877662222
Content-Disposition: inline; filename="README.txt"
Content-Length: 1024
X-Verint-KAB-Original-URL: https://drive.google.com/file/d/3DzkNXu2ZTC7pHOfuMdFbDliowWtsvrndu96QiaG4wrO
```
**Header Validation**:
- ✅ Header present on plain text export
- ✅ Consistent format across all export types
---
### Example 4: Document Not Found (Error)
**Request**:
```http
GET /documents/INVALID_ID_12345 HTTP/1.1
Host: adapter.example.com
```
**Response**:
```http
HTTP/1.1 404 Not Found
X-Request-Id: req_880gb733-h5ce-74g7-d049-779988773333
Document not found
```
**Header Validation**:
- ✅ No `X-Verint-KAB-Original-URL` header present
- ✅ Only `X-Request-Id` header for tracing
- ✅ Clear error response
---
### Example 5: Unsupported Export Format (Error)
**Request**:
```http
GET /documents/4EalOYv3aUD8qIPgvNeGcEmjpxXutwsoev07RjbH5xsP HTTP/1.1
Host: adapter.example.com
```
**Response**:
```http
HTTP/1.1 403 Forbidden
X-Request-Id: req_990hc844-i6df-85h8-e15a-88a099884444
No supported export format found for document type
```
**Header Validation**:
- ✅ No `X-Verint-KAB-Original-URL` header (even though file ID is valid)
- ✅ Error responses never include the URL header
---
## Client Integration Guide
### Extracting the Header
**JavaScript (Browser/Node.js)**:
```javascript
// Using fetch API
const response = await fetch('http://adapter.example.com/documents/123');
const driveUrl = response.headers.get('X-Verint-KAB-Original-URL');
if (driveUrl) {
console.log('Original document:', driveUrl);
} else {
console.log('Export failed or file URL unavailable');
}
```
**Python (requests library)**:
```python
import requests
response = requests.get('http://adapter.example.com/documents/123')
drive_url = response.headers.get('X-Verint-KAB-Original-URL')
if drive_url:
print(f'Original document: {drive_url}')
else:
print('Export failed or file URL unavailable')
```
**cURL**:
```bash
curl -I http://adapter.example.com/documents/123 | grep -i x-verint-kab-original-url
```
### Validation
Clients **SHOULD** validate the header value if present:
```javascript
function isValidDriveUrl(url) {
if (!url) return false;
// Check format: https://drive.google.com/file/d/{fileId}
const pattern = /^https:\/\/drive\.google\.com\/file\/d\/[a-zA-Z0-9_-]+$/;
return pattern.test(url);
}
const driveUrl = response.headers.get('X-Verint-KAB-Original-URL');
if (driveUrl && isValidDriveUrl(driveUrl)) {
// Use the URL
} else {
// Handle invalid or missing URL
}
```
### Use Cases
1. **Audit Trail**:
```javascript
const exportLog = {
timestamp: Date.now(),
documentId: '123',
exportFormat: 'PDF',
sourceUrl: response.headers.get('X-Verint-KAB-Original-URL'),
requestId: response.headers.get('X-Request-Id')
};
```
2. **User Navigation**:
```javascript
const driveUrl = response.headers.get('X-Verint-KAB-Original-URL');
if (driveUrl) {
// Show "View in Google Drive" link
const link = document.createElement('a');
link.href = driveUrl;
link.textContent = 'View Original Document';
link.target = '_blank';
}
```
3. **Content Tracking**:
```javascript
const metadata = {
exportedFile: 'report.pdf',
originalSource: response.headers.get('X-Verint-KAB-Original-URL'),
exportDate: new Date().toISOString()
};
```
---
## Compatibility
### Backward Compatibility
- ✅ **Non-breaking change**: Adding a response header is backward compatible
- ✅ **Clients can ignore**: Existing clients that don't expect the header will ignore it
- ✅ **Opt-in usage**: New clients can opt-in to using the header
### Forward Compatibility
- ⚠️ **Header name is fixed**: Future versions will not change the header name
- ⚠️ **URL format is stable**: Google Drive URL format is considered stable
- ✅ **Header will always be present on success**: Clients can rely on presence for successful exports
---
## Constraints
### Technical Constraints
- **HTTP Header Size Limit**: Total header size ~100-120 bytes (well within typical 8KB limit)
- **URL Length**: File IDs typically 33-44 characters (no practical limit concerns)
- **Character Set**: ASCII only (no international characters)
### Behavioral Constraints
- **No Query Parameters**: URL never includes `?` query parameters
- **No Fragments**: URL never includes `#` fragments
- **HTTPS Only**: URL always uses `https://` (never `http://`)
- **Single Value**: Header appears exactly once per response (never multiple times)
---
## Error Handling
### Missing Header
**Client Behavior**:
```javascript
const driveUrl = response.headers.get('X-Verint-KAB-Original-URL');
if (!driveUrl) {
// Header missing - check response status
if (response.status === 200) {
// Unexpected: successful export should have header
console.warn('Export succeeded but no source URL provided');
} else {
// Expected: error responses don't include header
console.log('Export failed:', response.status);
}
}
```
### Invalid Header Value
**Client Validation**:
```javascript
const driveUrl = response.headers.get('X-Verint-KAB-Original-URL');
if (driveUrl && !driveUrl.startsWith('https://drive.google.com/file/d/')) {
// Malformed header value (should not happen in production)
console.error('Invalid Drive URL format:', driveUrl);
// Treat as if header is missing
}
```
---
## Testing Contract
### Contract Tests
Tests **MUST** verify:
1. ✅ Header is present on all successful exports (200 OK)
2. ✅ Header value matches format: `https://drive.google.com/file/d/{fileId}`
3. ✅ File ID in header matches the requested document ID
4. ✅ Header is absent on all error responses (4xx, 5xx)
5. ✅ Header is consistent across all export formats (PDF, DOCX, text)
### Test Cases
```javascript
// Test 1: Header present on success
test('exports include X-Verint-KAB-Original-URL header', async () => {
const response = await fetch('/documents/valid-id');
assert.strictEqual(response.status, 200);
assert(response.headers.has('X-Verint-KAB-Original-URL'));
});
// Test 2: Header format
test('header value has correct format', async () => {
const response = await fetch('/documents/valid-id');
const url = response.headers.get('X-Verint-KAB-Original-URL');
assert(url.startsWith('https://drive.google.com/file/d/'));
});
// Test 3: Header absent on error
test('error responses do not include URL header', async () => {
const response = await fetch('/documents/invalid-id');
assert.strictEqual(response.status, 404);
assert(!response.headers.has('X-Verint-KAB-Original-URL'));
});
// Test 4: Consistency across formats
test('header present for all export formats', async () => {
const formats = ['PDF', 'DOCX', 'TXT'];
for (const format of formats) {
const response = await fetch(`/documents/valid-id-${format}`);
assert(response.headers.has('X-Verint-KAB-Original-URL'));
}
});
```
---
## Version History
### Version 1.0.0 (2026-03-27)
**Initial Release**:
- Defined `X-Verint-KAB-Original-URL` header contract
- Specified URL format: `https://drive.google.com/file/d/{fileId}`
- Defined presence rules (present on 200 OK, absent on errors)
- Provided client integration examples
- Established testing contract
---
## References
- **Feature Specification**: `/specs/001-gdrive-url-header/spec.md`
- **Data Model**: `/specs/001-gdrive-url-header/data-model.md`
- **RFC 6648**: Deprecation of X- Prefix (https://tools.ietf.org/html/rfc6648)
- **Google Drive URLs**: https://developers.google.com/drive/api/guides/manage-sharing