mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 11:31:07 -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
|
- 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
|
||||||
|
|||||||
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