Blog System Design Sandbox

Project Overview
Built a full-stack blogging system to experiment with production backend patterns including JWT access/refresh tokens, request validation, structured logging, health checks, and Dockerized deployment.
Fullstack Blog: System Design Sandbox
- Problem Statement
Most tutorial projects demonstrate features but ignore the operational realities that make production systems difficult:
Authentication lifecycle management
Failure handling and observability
Infrastructure consistency
Deployment reproducibility
API evolution without breaking clients
Multi-device session control
As a result, many portfolio projects appear feature-complete but lack engineering maturity.
The goal of this project was to build a minimal domain (blog) but stress-test the infrastructure, reliability, and system design aspects of a real production system.
The blog domain exists purely as a stable surface area to exercise concerns such as authentication, API behavior, deployment pipelines, and state management.
- System Goals
The system was designed around five engineering goals.
2.1 Authentication Lifecycle Control
JWT systems often fail in real deployments because tokens cannot easily be revoked or invalidated.
This system implements:
Access / Refresh token separation
Token versioning
Forced invalidation on password change
Blacklist tracking via Redis
This prevents long-lived compromised tokens from remaining valid.
2.2 Multi-Device Session Awareness
Typical JWT implementations treat authentication as stateless, which prevents device-level session control.
This project introduces a session tracking layer allowing users to:
View active sessions
Logout from specific devices
Logout from all devices
Revoke refresh tokens safely
Each login creates a UserSession record which maps refresh tokens to devices.
2.3 Operational Traceability
In production debugging, the most expensive failure is one that cannot be traced.
The system introduces request-scoped tracing:
Every incoming request is assigned a request ID that flows through:
client → nginx → django middleware → logs
Structured logs attach:
request_id user_id endpoint status_code latency
This allows failed requests to be traced across services.
2.4 Deployment Reproducibility
A frequent source of production incidents is environment drift.
The project ensures environment parity through containerization.
Local Dev Docker Containers Production Infrastructure
The same Docker configuration runs in both environments.
This guarantees that:
“Works on my machine” means works in production.
2.5 Safe API Evolution
Production APIs cannot change destructively.
This system enforces additive API design:
Versioned endpoints
Backward compatible schema changes
Standard response envelopes
Example API response structure:
{ "data": {...}, "meta": {...}, "error": null }
Clients remain stable even when backend fields evolve.
- Architecture Overview
The application follows a decoupled full-stack architecture.
Client (React + Vite) │ ▼ Nginx Reverse Proxy │ ▼ Django REST API │ ├── PostgreSQL (persistent data) └── Redis (token blacklist + caching) Key Architectural Decisions
Frontend / Backend Separation
Benefits:
Independent deployment
API-first design
Better scaling options
Easier mobile integration
Reverse Proxy Layer (Nginx)
Responsibilities:
TLS termination
Static asset delivery
Routing requests to backend
Request buffering and protection
Redis Integration
Used for:
JWT blacklist
Future caching strategies
Rate-limiting storage
Redis was selected due to its low latency and atomic operations.
- Technology Stack Backend
Framework: Django 5 + Django REST Framework
Authentication: SimpleJWT
Database: PostgreSQL
Caching: Redis
API Documentation: drf-spectacular
Frontend
Framework: React 19
Build Tool: Vite
Styling: Tailwind CSS
Routing: React Router v7
HTTP Client: Axios
Infrastructure
Docker
Docker Compose
AWS EC2
AWS RDS
GitHub Actions CI
- Authentication System Design
JWT authentication is implemented with additional security layers.
Token Structure
Two tokens are issued during authentication.
Access Token Short lifespan Used for API requests
Refresh Token Longer lifespan Used to obtain new access tokens Token Versioning Strategy
Each user has a token_version field.
When a sensitive event occurs (e.g., password change):
token_version += 1
All previously issued tokens become invalid because their version no longer matches the user record.
This prevents token reuse after credential compromise.
Token Blacklisting
Refresh tokens are stored in Redis when revoked.
Flow:
Logout → token added to Redis blacklist Future refresh attempt → token rejected
This ensures refresh tokens cannot be reused.
- Session Management Model
Unlike traditional JWT systems, sessions are persisted.
Each login creates:
UserSession
user_id device ip_address created_at refresh_token is_active
This allows:
Device-specific logout
Session auditing
Security visibility
- Resilience & Failure Handling
Production systems must assume failure.
Several defensive mechanisms were implemented.
Soft Deletes
Instead of removing records:
deleted_at timestamp
This prevents accidental data loss and allows recovery.
API Timeouts
Axios interceptors enforce request timeouts to prevent UI lockups.
Centralized Error Handling
React error boundaries catch runtime UI failures.
ErrorBoundary
Prevents entire application crashes.
- CI/CD Pipeline
GitHub Actions enforce automated checks before deployment.
Pipeline stages:
Lint Tests Build Docker Image Deployment
This ensures broken code cannot be merged into the main branch.
- Observability Strategy
Observability was designed around three pillars.
Logging
Structured logs capture:
timestamp request_id endpoint user status latency Health Endpoints
Infrastructure monitoring uses:
/health/ /health/db/ /health/cache/
These endpoints allow load balancers and monitoring tools to verify system health.
Failure Visibility
Centralized error mapping ensures the frontend receives meaningful error states instead of silent failures.
- Security Considerations
Several security protections were implemented.
Rate Limiting
Authentication endpoints enforce request throttling.
POST /auth/token/
This reduces brute-force login attempts.
Environment Validation
Startup checks verify required environment variables.
If critical variables are missing:
Application refuses to start
Fail-fast prevents silent configuration bugs.
Secrets Management
Sensitive values such as:
SECRET_KEY DATABASE_URL JWT_SECRET
are stored in environment variables rather than source code.
- Project Structure
The repository is organized to enforce separation of concerns.
backend/ accounts/ blog/ config/
frontend/ components/ pages/ context/
infrastructure/ docker-compose.yml
This structure allows the system to evolve without tightly coupling frontend and backend logic.
- Performance Considerations
Several performance improvements were implemented.
Lazy Loading
React routes are dynamically loaded.
React.lazy()
This reduces initial bundle size.
Axios Interceptors
Token attachment and refresh logic are centralized to avoid duplicated network logic across components.
Docker Layer Caching
Build layers were optimized to reduce CI build times.
- Key Engineering Lessons
Building the system revealed several practical lessons.
- Authentication is Hard
Token invalidation and multi-device logout introduce complexity rarely covered in tutorials.
- Observability is Critical
Without request tracing, debugging distributed failures becomes extremely difficult.
- Environment Consistency Matters
Containerization removed entire classes of deployment bugs.
- API Stability Must Be Planned Early
Versioning and response envelopes prevent frontend breakage during backend evolution.
- Future Engineering Work
Future work will focus on deeper infrastructure complexity.
Planned Enhancements
Advanced Caching
Redis read-through caching Cache invalidation strategies
Background Jobs
Introduce Celery workers for:
email sending analytics aggregation image processing
Observability Stack
Prometheus metrics Grafana dashboards Distributed tracing 15. Conclusion
This project intentionally avoids feature complexity and instead focuses on system behavior under real operational constraints.
The blog domain acts as a stable testing ground to explore engineering problems such as:
authentication lifecycle
infrastructure reliability
API evolution
deployment reproducibility
system observability
The result is a full-stack system designed not as a tutorial project, but as a system design sandbox for production-grade engineering practices.
Ready to Build Your Scalable MVP?
Partner with Ashif E.K to transform your vision into a high-performance React & Django application. Let's engineer your success.
Limited availability for Q2 2026.