- Added BaseEntitySubmissionService as an abstract base for entity submissions. - Created specific submission services for entities: Park, Ride, Company, RideModel. - Implemented create, update, and delete functionalities with moderation workflow. - Enhanced logging and validation for required fields. - Addressed foreign key handling and special field processing for each entity type. - Noted existing issues with JSONField usage in Company submissions.
16 KiB
History API Endpoints Documentation
Overview
The History API provides complete access to historical changes for all major entities in the ThrillTrack system. Built on top of the django-pghistory library, this API enables:
- Historical Tracking: View complete history of changes to entities
- Event Comparison: Compare different versions of entities over time
- Field History: Track changes to specific fields
- Activity Summaries: Get statistics about entity modifications
- Rollback Capabilities: Restore entities to previous states (admin only)
Supported Entities
The History API is available for the following entities:
- Parks (
/api/v1/parks/{park_id}/history/) - Rides (
/api/v1/rides/{ride_id}/history/) - Companies (
/api/v1/companies/{company_id}/history/) - Ride Models (
/api/v1/ride-models/{model_id}/history/) - Reviews (
/api/v1/reviews/{review_id}/history/)
Additionally, generic history endpoints are available:
- Generic Event Access (
/api/v1/history/events/{event_id}) - Generic Event Comparison (
/api/v1/history/compare)
Authentication & Authorization
Access Levels
The History API implements a tiered access control system:
1. Public (Unauthenticated)
- Access Window: Last 30 days
- Permissions: Read-only access to recent history
- Use Cases: Public transparency, recent changes visibility
2. Authenticated Users
- Access Window: Last 1 year
- Permissions: Read-only access to extended history
- Use Cases: User research, tracking their contributions
3. Moderators/Admins/Superusers
- Access Window: Unlimited (entire history)
- Permissions: Full read access + rollback capabilities
- Use Cases: Moderation, auditing, data recovery
Rollback Permissions
Only users with moderator, admin, or superuser privileges can perform rollbacks:
- Check via
can_rollbackfield in responses - Requires explicit permission check
- Creates audit trail of rollback actions
Endpoint Reference
1. List Entity History
Get paginated history of changes to an entity.
Endpoint Pattern: GET /{entity-type}/{entity-id}/history/
Query Parameters:
page(integer, default: 1): Page numberpage_size(integer, default: 50, max: 100): Items per pagedate_from(string, format: YYYY-MM-DD): Filter from datedate_to(string, format: YYYY-MM-DD): Filter to date
Response: 200 OK
{
"entity_id": "uuid-string",
"entity_type": "park|ride|company|ridemodel|review",
"entity_name": "Entity Display Name",
"total_events": 150,
"accessible_events": 150,
"access_limited": false,
"access_reason": "Full access (moderator)",
"events": [
{
"id": 12345,
"timestamp": "2024-01-15T10:30:00Z",
"operation": "insert|update|delete",
"snapshot": {
"id": "uuid",
"name": "Example Park",
"status": "operating",
...
},
"changed_fields": ["name", "status"],
"change_summary": "Updated name and status",
"can_rollback": true
}
],
"pagination": {
"page": 1,
"page_size": 50,
"total_pages": 3,
"total_items": 150
}
}
Examples:
# Get park history
GET /api/v1/parks/123e4567-e89b-12d3-a456-426614174000/history/
# Get ride history with date filter
GET /api/v1/rides/987fcdeb-51a2-43f1-9876-543210fedcba/history/?date_from=2024-01-01&date_to=2024-12-31
# Get company history, page 2
GET /api/v1/companies/456e789a-b12c-34d5-e678-901234567890/history/?page=2&page_size=100
2. Get Specific History Event
Retrieve detailed information about a single historical event.
Endpoint Pattern: GET /{entity-type}/{entity-id}/history/{event-id}/
Response: 200 OK
{
"id": 12345,
"timestamp": "2024-01-15T10:30:00Z",
"operation": "update",
"entity_id": "uuid-string",
"entity_type": "park",
"entity_name": "Example Park",
"snapshot": {
"id": "uuid",
"name": "Example Park",
"status": "operating",
...
},
"changed_fields": ["name", "status"],
"metadata": {},
"can_rollback": true,
"rollback_preview": null
}
Examples:
# Get specific park event
GET /api/v1/parks/123e4567-e89b-12d3-a456-426614174000/history/12345/
# Get specific review event
GET /api/v1/reviews/67890/history/54321/
3. Compare Two History Events
Compare two historical snapshots to see what changed between them.
Endpoint Pattern: GET /{entity-type}/{entity-id}/history/compare/
Query Parameters:
event1(integer, required): First event IDevent2(integer, required): Second event ID
Response: 200 OK
{
"entity_id": "uuid-string",
"entity_type": "park",
"entity_name": "Example Park",
"event1": {
"id": 12345,
"timestamp": "2024-01-15T10:30:00Z",
"snapshot": {...}
},
"event2": {
"id": 12346,
"timestamp": "2024-01-16T14:20:00Z",
"snapshot": {...}
},
"differences": {
"name": {
"old_value": "Old Park Name",
"new_value": "New Park Name",
"changed": true
},
"status": {
"old_value": "closed",
"new_value": "operating",
"changed": true
}
},
"changed_field_count": 2,
"unchanged_field_count": 15,
"time_between": "1 day, 3:50:00"
}
Examples:
# Compare two park events
GET /api/v1/parks/123e4567-e89b-12d3-a456-426614174000/history/compare/?event1=12345&event2=12346
# Compare ride events
GET /api/v1/rides/987fcdeb-51a2-43f1-9876-543210fedcba/history/compare/?event1=100&event2=105
4. Compare Event with Current State
Compare a historical event with the entity's current state.
Endpoint Pattern: GET /{entity-type}/{entity-id}/history/{event-id}/diff-current/
Response: 200 OK
{
"entity_id": "uuid-string",
"entity_type": "park",
"entity_name": "Example Park",
"event": {
"id": 12345,
"timestamp": "2024-01-15T10:30:00Z",
"snapshot": {...}
},
"current_state": {
"name": "Current Park Name",
"status": "operating",
...
},
"differences": {
"name": {
"old_value": "Historical Name",
"new_value": "Current Park Name",
"changed": true
}
},
"changed_field_count": 3,
"time_since": "45 days, 2:15:30"
}
Examples:
# Compare historical park state with current
GET /api/v1/parks/123e4567-e89b-12d3-a456-426614174000/history/12345/diff-current/
# Compare historical company state with current
GET /api/v1/companies/456e789a-b12c-34d5-e678-901234567890/history/98765/diff-current/
5. Rollback to Historical State
Restore an entity to a previous state. Requires moderator/admin/superuser permissions.
Endpoint Pattern: POST /{entity-type}/{entity-id}/history/{event-id}/rollback/
Authentication: Required (JWT)
Request Body:
{
"fields": ["name", "status"], // Optional: specific fields to rollback
"comment": "Reverting vandalism", // Optional: reason for rollback
"create_backup": true // Optional: create backup event before rollback
}
Response: 200 OK
{
"success": true,
"message": "Successfully rolled back to event 12345",
"rolled_back_fields": ["name", "status"],
"backup_event_id": 12350,
"new_event_id": 12351
}
Error Responses:
401 Unauthorized: Authentication required403 Forbidden: Insufficient permissions404 Not Found: Event or entity not found400 Bad Request: Invalid rollback request
Examples:
# Full rollback of park
POST /api/v1/parks/123e4567-e89b-12d3-a456-426614174000/history/12345/rollback/
{
"comment": "Reverting accidental changes",
"create_backup": true
}
# Partial rollback (specific fields only)
POST /api/v1/rides/987fcdeb-51a2-43f1-9876-543210fedcba/history/54321/rollback/
{
"fields": ["name", "description"],
"comment": "Restoring original name and description",
"create_backup": true
}
6. Get Field History
Track all changes to a specific field over time.
Endpoint Pattern: GET /{entity-type}/{entity-id}/history/field/{field-name}/
Response: 200 OK
{
"entity_id": "uuid-string",
"entity_type": "park",
"entity_name": "Example Park",
"field": "status",
"field_type": "CharField",
"changes": [
{
"event_id": 12346,
"timestamp": "2024-01-16T14:20:00Z",
"old_value": "closed",
"new_value": "operating"
},
{
"event_id": 12345,
"timestamp": "2024-01-15T10:30:00Z",
"old_value": "operating",
"new_value": "closed"
}
],
"total_changes": 2,
"first_recorded": "2023-06-01T08:00:00Z",
"last_changed": "2024-01-16T14:20:00Z"
}
Examples:
# Track park status changes
GET /api/v1/parks/123e4567-e89b-12d3-a456-426614174000/history/field/status/
# Track ride height changes
GET /api/v1/rides/987fcdeb-51a2-43f1-9876-543210fedcba/history/field/height/
# Track company name changes
GET /api/v1/companies/456e789a-b12c-34d5-e678-901234567890/history/field/name/
7. Get Activity Summary
Get statistics about modifications to an entity.
Endpoint Pattern: GET /{entity-type}/{entity-id}/history/summary/
Response: 200 OK
{
"entity_id": "uuid-string",
"entity_type": "park",
"entity_name": "Example Park",
"total_events": 150,
"total_updates": 145,
"total_creates": 1,
"total_deletes": 0,
"first_event": "2023-01-01T00:00:00Z",
"last_event": "2024-03-15T16:45:00Z",
"most_active_period": "2024-01",
"average_updates_per_month": 12.5,
"most_changed_fields": [
{"field": "status", "changes": 25},
{"field": "description", "changes": 18},
{"field": "ride_count", "changes": 15}
]
}
Examples:
# Get park activity summary
GET /api/v1/parks/123e4567-e89b-12d3-a456-426614174000/history/summary/
# Get review activity summary
GET /api/v1/reviews/67890/history/summary/
Generic History Endpoints
Get Any Event by ID
Retrieve any historical event by its ID, regardless of entity type.
Endpoint: GET /api/v1/history/events/{event-id}
Response: 200 OK
{
"id": 12345,
"timestamp": "2024-01-15T10:30:00Z",
"operation": "update",
"entity_type": "park",
"entity_id": "uuid-string",
"snapshot": {...},
"changed_fields": ["name", "status"],
"can_rollback": true
}
Compare Any Two Events
Compare any two events, even across different entities.
Endpoint: GET /api/v1/history/compare
Query Parameters:
event1(integer, required): First event IDevent2(integer, required): Second event ID
Response: Similar to entity-specific comparison endpoint
Access Control Details
Time-Based Access Windows
Access windows are enforced based on user authentication level:
# Access limits
PUBLIC_WINDOW = 30 days
AUTHENTICATED_WINDOW = 1 year
PRIVILEGED_WINDOW = Unlimited
Access Reason Messages
The API provides clear feedback about access limitations:
- "Full access (moderator)": Unlimited access
- "Full access (admin)": Unlimited access
- "Full access (superuser)": Unlimited access
- "Access limited to last 365 days (authenticated user)": 1-year limit
- "Access limited to last 30 days (public)": 30-day limit
Rollback Safety Guidelines
Before Performing a Rollback
- Review the Target State: Use
diff-currentto see what will change - Check Dependencies: Consider impact on related entities
- Create Backup: Always set
create_backup: truefor safety - Add Comment: Document why the rollback is being performed
- Use Partial Rollback: When possible, rollback only specific fields
Rollback Best Practices
{
"fields": ["name", "description"], // Limit scope
"comment": "Reverting vandalism on 2024-03-15", // Document reason
"create_backup": true // Always true in production
}
Audit Trail
All rollbacks create:
- Backup Event: Snapshot before rollback (if
create_backup: true) - Rollback Event: New event with restored state
- Audit Log: Metadata tracking who performed rollback and why
Error Handling
Common Error Responses
404 Not Found
{
"error": "Entity not found"
}
400 Bad Request
{
"error": "Invalid date format. Use YYYY-MM-DD"
}
403 Forbidden
{
"error": "Only moderators and administrators can perform rollbacks"
}
401 Unauthorized
{
"error": "Authentication required"
}
Error Codes
| Status Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request (invalid parameters) |
| 401 | Unauthorized (authentication required) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not Found (entity or event not found) |
| 500 | Internal Server Error |
Rate Limiting
The History API implements standard rate limiting:
- Authenticated Users: 100 requests per minute
- Unauthenticated Users: 20 requests per minute
- Rollback Operations: 10 per minute (additional limit)
Rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1617181723
Performance Considerations
Pagination
- Default page size: 50 events
- Maximum page size: 100 events
- Use pagination for large result sets
Caching
- Event data is cached for 5 minutes
- Comparison results are cached for 2 minutes
- Current state comparisons are not cached
Query Optimization
- Use date filters to reduce result sets
- Prefer field-specific history for focused queries
- Use summary endpoints for overview data
Integration Examples
Python (requests)
import requests
# Get park history
response = requests.get(
'https://api.thrilltrack.com/v1/parks/123/history/',
params={'page': 1, 'page_size': 50},
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
history = response.json()
# Compare two events
response = requests.get(
'https://api.thrilltrack.com/v1/parks/123/history/compare/',
params={'event1': 100, 'event2': 105}
)
comparison = response.json()
# Perform rollback
response = requests.post(
'https://api.thrilltrack.com/v1/parks/123/history/100/rollback/',
json={
'comment': 'Reverting vandalism',
'create_backup': True
},
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
JavaScript (fetch)
// Get ride history
const response = await fetch(
'https://api.thrilltrack.com/v1/rides/456/history/',
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
const history = await response.json();
// Compare with current state
const diffResponse = await fetch(
'https://api.thrilltrack.com/v1/rides/456/history/200/diff-current/'
);
const diff = await diffResponse.json();
cURL
# Get company history
curl -H "Authorization: Bearer TOKEN" \
"https://api.thrilltrack.com/v1/companies/789/history/"
# Rollback to previous state
curl -X POST \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"comment": "Reverting changes", "create_backup": true}' \
"https://api.thrilltrack.com/v1/companies/789/history/150/rollback/"
Troubleshooting
Common Issues
Issue: "Access limited to last 30 days"
- Solution: Authenticate with valid credentials to extend access window
Issue: "Event not found or not accessible"
- Solution: Event may be outside your access window or doesn't exist
Issue: "Cannot rollback: Event not found"
- Solution: Verify event ID and ensure you have rollback permissions
Issue: Rate limit exceeded
- Solution: Implement exponential backoff or reduce request frequency
Support
For additional support:
- Documentation: https://docs.thrilltrack.com/history-api
- GitHub Issues: https://github.com/thrilltrack/api/issues
- Email: api-support@thrilltrack.com
Changelog
Version 1.0 (Current)
- Initial release of History API
- Support for Parks, Rides, Companies, Ride Models, and Reviews
- Complete CRUD history tracking
- Comparison and rollback capabilities
- Tiered access control system