Today I closed Day 17 — Part 1 of my AI Phishing Defense Platform.
The system was “working”… but architecturally wrong.
The Problem
Audit logs were storing API keys as plain strings.
That breaks:
- relational integrity
- analytics joins
- usage aggregation
- long-term scalability
It looked like this:
api_key = models.CharField(max_length=64)
That’s not production-grade.
The Refactor
I replaced it with:
api_key = models.ForeignKey(
APIKey,
null=True,
blank=True,
on_delete=models.SET_NULL,
)
This allowed:
- proper usage aggregation
- accurate plan tracking
- clean JOIN queries
- future-ready analytics
What Broke
- As expected, migrations and existing logic exploded:
- ForeignKey assignment errors
- IntegrityError on status_code
- Rate limit filters pointing to wrong fields
- Audit logger passing strings instead of instances
- This is normal when upgrading architecture.
What Was Fixed
• Correct FK assignment
• Refactored log_audit_event
• Unified rate limit logic
• Clean APIUsage logging
• Plan-aware audit entries
Now the system tracks:
- Anonymous
- Free
- Pro
- Status codes
- Daily usage
- Endpoint analytics
Lesson
- Don’t build demos.
- Build systems that survive refactoring.
- Architecture debt always shows up later.
Day 17 is about backend maturity.
Tomorrow: analytics expansion layer.

Top comments (0)