── Processing service publishes after bulk upsert ────────
redis.publish("asgi:group:posts_feed", signal_payload)
── Django Channels consumer receives ─────────────────────
class SignalConsumer(AsyncWebsocketConsumer):
async def signal_update(self, event):
await self.send(json.dumps(event["payload"]))
── Client dashboard updates ──────────────────────────────
score: 45 → 1200 velocity badge: 3.85/s trending: ★ RISING
AUTHJWT — required for all endpoints belowPOST /api/token/ → {access, refresh} · access expires 60min · POST /api/token/refresh/ to rotate
GET/api/v1/signals/cross-platform feed · paginated · 30s Redis cache
GET/api/v1/pulse/topic sentiment summary · VADER + NER entities
GET/api/v1/trending/velocity-ranked cross-platform trending
GET/api/v1/compare/divergence events · platform delta scores
WSws://localhost:8000/ws/signals/real-time push · no polling · Redis DB2 pub/sub
GET/health/health check · no auth required · no DB query
Daphne serves HTTP and WebSocket on the same ASGI process. REST responses cached in Redis DB1 at 30s TTL — expires automatically, not explicitly invalidated on flush. WebSocket bypasses the cache entirely — always live from Redis DB2 pub/sub channel layer. All REST endpoints require Authorization: Bearer <access_token> header.