Implement historical tracking using django-pghistory; add middleware for context capture and update model architecture

This commit is contained in:
pacnpal
2025-02-08 21:18:44 -05:00
parent 71b73522ae
commit a148d34cf9
6 changed files with 223 additions and 1 deletions

View File

@@ -0,0 +1,45 @@
## Decision: Universal Model History via django-pghistory
### Pattern Implementation
- **Tracking Method**: `pghistory.Snapshot()` applied to all concrete models
- **Inheritance Strategy**: Base model class with history tracking
- **Context Capture**:
```python
# core/models.py
import pghistory
class HistoricalModel(models.Model):
class Meta:
abstract = True
@pghistory.track(pghistory.Snapshot())
def save(self, *args, **kwargs):
return super().save(*args, **kwargs)
```
### Integration Scope
1. **Model Layer**:
- All concrete models inherit from `HistoricalModel`
- Automatic event labeling:
```python
@pghistory.track(
pghistory.Snapshot('model.create'),
pghistory.AfterInsert('model.update'),
pghistory.BeforeDelete('model.delete')
)
```
2. **Context Middleware**:
```python
# core/middleware.py
pghistory.context(lambda request: {
'user': str(request.user) if request.user.is_authenticated else None,
'ip': request.META.get('REMOTE_ADDR'),
'user_agent': request.META.get('HTTP_USER_AGENT'),
'session_key': request.session.session_key
})
```
3. **Admin Integration**:
- Custom history view for Django Admin
- Version comparison interface

View File

@@ -0,0 +1,57 @@
## Feature: Unified History Timeline (HTMX Integrated)
### HTMX Template Pattern
```django
{# history/partials/history_timeline.html #}
<div id="history-timeline"
hx-get="{% url 'history:timeline' content_type_id=content_type.id object_id=object.id %}"
hx-trigger="every 30s, historyUpdate from:body">
<div class="space-y-4">
{% for event in events %}
<div class="component-wrapper bg-white p-4 shadow-sm">
<div class="component-header flex items-center gap-2 mb-2">
<span class="text-sm font-medium">{{ event.pgh_label|title }}</span>
<time class="text-xs text-gray-500">{{ event.pgh_created_at|date:"M j, Y H:i" }}</time>
</div>
<div class="component-content text-sm">
{% if event.pgh_context.metadata.user %}
<div class="flex items-center gap-1">
<svg class="w-4 h-4">...</svg>
<span>{{ event.pgh_context.metadata.user }}</span>
</div>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
```
### View Integration (Class-Based with HTMX)
```python
# history/views.py
class HistoryTimelineView(View):
def get(self, request, content_type_id, object_id):
events = ModelHistory.objects.filter(
pgh_obj_model=content_type_id,
pgh_obj_id=object_id
).order_by('-pgh_created_at')[:25]
if request.htmx:
return render(request, "history/partials/history_timeline.html", {
"events": events
})
return JsonResponse({
'history': [serialize_event(e) for e in events]
})
```
### Event Trigger Pattern
```python
# parks/signals.py
from django.dispatch import Signal
history_updated = Signal()
# In model save/delete handlers:
history_updated.send(sender=Model, instance=instance)

View File

@@ -0,0 +1,34 @@
# History Tracking Implementation Plan
## Phase Order & Document Links
1. **Architecture Design**
- [Integration Strategy](/decisions/pghistory-integration.md)
- [System Patterns Update](/systemPatterns.md#historical-tracking)
2. **Model Layer Implementation**
- [Migration Protocol](/workflows/model-migrations.md)
- [Base Model Configuration](/decisions/pghistory-integration.md#model-layer-integration)
3. **Moderation System Update**
- [Approval Workflow](/workflows/moderation.md#updated-moderation-workflow-with-django-pghistory)
- [Admin Integration](/workflows/moderation.md#moderation-admin-integration)
4. **Frontend Visualization**
- [Timeline Component](/features/history-visualization.md#template-components)
- [API Endpoints](/features/history-visualization.md#ajax-endpoints)
5. **Deployment Checklist**
- [Context Middleware](/systemPatterns.md#request-context-tracking)
- [QA Procedures](/workflows/model-migrations.md#quality-assurance)
## Directory Structure
```
memory-bank/
projects/
history-tracking/
implementation-plan.md
decisions.md -> ../../decisions/pghistory-integration.md
frontend.md -> ../../features/history-visualization.md
migrations.md -> ../../workflows/model-migrations.md
moderation.md -> ../../workflows/moderation.md

View File

@@ -36,7 +36,23 @@
- Use Redis for session storage - Use Redis for session storage
- Cache invalidation rules - Cache invalidation rules
### Frontend Patterns ### Historical Tracking
- All model changes create immutable pghistory events
- Events contain:
- Full object state snapshot
- Contextual metadata (user, request fingerprint)
- Semantic event label (created, updated, deleted)
- Middleware integration:
```python
# core/middleware.py
pghistory.context(lambda request: {
'user': str(request.user) if request.user.is_authenticated else None,
'ip': request.META.get('REMOTE_ADDR'),
'user_agent': request.META.get('HTTP_USER_AGENT')
})
```
## Frontend Patterns
1. HTMX Integration 1. HTMX Integration
```html ```html

View File

@@ -0,0 +1,39 @@
## Model Migration Protocol for History Tracking
### Implementation Steps
1. **Base Model Setup**
```python
# core/models.py
import pghistory
class HistoricalModel(models.Model):
class Meta:
abstract = True
@pghistory.track(pghistory.Snapshot())
def save(self, *args, **kwargs):
return super().save(*args, **kwargs)
```
2. **Concrete Model Implementation**
```python
# parks/models.py
class Park(HistoricalModel):
@pghistory.track(
pghistory.Snapshot('park.create'),
pghistory.AfterUpdate('park.update'),
pghistory.BeforeDelete('park.delete')
)
class Meta:
# Existing model fields and configuration
```
3. **Migration Generation**
```bash
./manage.py makemigrations --name add_pghistory_tracking
```
### Quality Assurance
1. Verify historical events table creation
2. Test event triggering for CRUD operations
3. Validate context metadata capture

View File

@@ -0,0 +1,31 @@
## Updated Moderation Workflow with django-pghistory
### Submission Lifecycle
1. **Change Proposal**
- Creates `pending` pghistory event with metadata:
```python
pghistory.track(
pghistory.Snapshot('submission.pending'),
status='pending'
)
```
2. **Approval Process**
- Merges event into main history:
```python
event.pgh_label = 'approved_change'
event.pgh_context['approver'] = request.user
```
3. **Rejection Handling**
- Preserves event with rejection context:
```python
event.pgh_label = 'rejected_change'
event.pgh_context['reason'] = rejection_reason
```
### Moderation Admin Integration
```python
# moderation/admin.py
@admin.register(pghistory.models.Event)
class HistoryAdmin(admin.ModelAdmin):
list_display = ('pgh_label', 'pgh_created_at', 'content_object')
readonly_fields = ('pgh_data', 'pgh_context')