mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 16:11:08 -05:00
Implement historical tracking using django-pghistory; add middleware for context capture and update model architecture
This commit is contained in:
45
memory-bank/decisions/pghistory-integration.md
Normal file
45
memory-bank/decisions/pghistory-integration.md
Normal 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
|
||||
57
memory-bank/features/history-visualization.md
Normal file
57
memory-bank/features/history-visualization.md
Normal 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)
|
||||
34
memory-bank/projects/history-tracking/implementation-plan.md
Normal file
34
memory-bank/projects/history-tracking/implementation-plan.md
Normal 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
|
||||
@@ -36,7 +36,23 @@
|
||||
- Use Redis for session storage
|
||||
- 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
|
||||
```html
|
||||
|
||||
39
memory-bank/workflows/model-migrations.md
Normal file
39
memory-bank/workflows/model-migrations.md
Normal 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
|
||||
31
memory-bank/workflows/moderation.md
Normal file
31
memory-bank/workflows/moderation.md
Normal 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')
|
||||
Reference in New Issue
Block a user