System Overview
High-level overview of the Bellamy Book system architecture. For a full walkthrough that teaches how all pieces fit together, see Understanding the Architecture. For a detailed deep dive into media processing, recommendations, push, search, chat/calls, and scaling, see System Architecture Deep Dive.
Architecture Pattern
Bellamy Book uses a modular architecture with:
- Single API: ASP.NET Core (.NET 8) backend serving social frontend and admin panel (REST + SignalR for notifications/presence).
- Polyglot persistence: PostgreSQL, MongoDB, Redis, Neo4j, Elasticsearch/OpenSearch; MinIO (or S3-compatible) for media storage.
- Event-driven workers: Kafka for most async processing (scores, trends, graph, search sync, interactions, real-time notification delivery); RabbitMQ for AI blog generation and for push notifications (Web Push, Expo Push).
- Media processing: MediaProcessingWorker polls PostgreSQL for pending
MediaFilerecords and processes files (no Kafka for media trigger); writes processed assets to MinIO and DB. - Real-time: ChatWorker and WebSocketWorker are separate processes hosting SignalR hubs; frontend connects to their URLs (not the main API) for chat and in-app notifications.
Component Diagram
Top-to-bottom layout so all text is visible. Edges show protocol where relevant.
graph TB
subgraph Presentation["Presentation Layer"]
FE["Frontend<br/>React + Vite"]
ADMIN["Admin Panel<br/>React"]
end
subgraph Application["Application Layer"]
API["Backend API<br/>ASP.NET Core"]
CHAT["ChatWorker<br/>SignalR"]
end
subgraph DataStorage["Data Storage"]
PG[("PostgreSQL")]
MONGO[("MongoDB")]
REDIS[("Redis")]
NEO4J[("Neo4j")]
ES[("Elasticsearch")]
end
subgraph KafkaWorkers["Kafka Workers"]
KAFKA["Kafka"]
INT["InteractionWorker"]
SCORE["ScoringWorker"]
TREND["TrendingWorker"]
GRAPH["GraphWorker"]
HASHTAG["HashtagWorker"]
ELASTIC["ElasticsearchSyncWorker"]
WS["WebSocketWorker"]
end
subgraph RabbitMQWorkers["RabbitMQ"]
RABBIT["RabbitMQ"]
BLOG["BlogAutoGenerationWorker"]
WEBPUSH["WebPushNotificationWorker"]
EXPOPUSH["ExpoPushNotificationWorker"]
end
MEDIA["MediaProcessingWorker<br/>polls DB"]
FE -->|"HTTP/REST + SignalR"| API
ADMIN -->|"HTTP/REST"| API
API --> PG
API --> MONGO
API --> REDIS
API --> ES
CHAT --> REDIS
CHAT --> MONGO
API -->|"Events"| KAFKA
API -->|"Chat/Call push"| RABBIT
KAFKA --> INT
KAFKA --> SCORE
KAFKA --> TREND
KAFKA --> GRAPH
KAFKA --> HASHTAG
KAFKA --> ELASTIC
KAFKA --> WS
RABBIT --> BLOG
RABBIT --> WEBPUSH
RABBIT --> EXPOPUSH
INT --> PG
INT --> REDIS
SCORE --> PG
SCORE --> NEO4J
TREND --> PG
GRAPH --> NEO4J
HASHTAG --> PG
ELASTIC --> ES
BLOG --> PG
WS --> REDIS
MEDIA --> PG
MEDIA --> MONGO
Note: BlogAutoGenerationWorker and push workers (WebPush, Expo) consume RabbitMQ. MediaProcessingWorker reads pending MediaFiles from PostgreSQL and MinIO (no Kafka). Real-time chat and call signaling use ChatWorker (SignalR).
Data Flow
Request Flow
- Client Request → Frontend or Admin sends HTTP request (with optional SignalR for real-time).
- Backend API → ASP.NET Core receives request (middleware: license, rate limit, auth).
- Authentication → JWT validation and role-based authorization (User, Moderator, Admin).
- Business Logic → MediatR handlers, domain logic, repositories.
- Data Access → PostgreSQL/MongoDB/Redis/Neo4j/Elasticsearch as needed; optional Kafka publish for async side effects.
- Response → JSON response (or 201/204) sent to client.
Event Flow
- Event triggered → User action (e.g. post, comment, reaction) causes API to publish to Kafka (or to RabbitMQ for chat/call push or blog generation).
- Worker consumes → Corresponding worker (separate process) processes the message.
- Data updated → Worker writes to PostgreSQL, MongoDB, Redis, Neo4j, or Elasticsearch as needed.
- Real-time → WebSocketWorker pushes in-app notifications via SignalR; push workers send Web/Expo push when applicable.
Database Strategy
PostgreSQL
- User accounts, posts, comments, reactions, friendships, follows
- Hashtags, blogs, tickets, license, AI agent settings, email campaigns
MongoDB
- Stories, notifications, chat messages
- Document-shaped data with flexible schema
Redis
- Session storage
- Cache (user, post, feed, story, media URLs)
- Rate limiting
- Real-time state (presence, connection mapping for SignalR)
MinIO / S3-compatible
- Media files (avatars, covers, posts, stories, chat, blogs)
- Temp bucket for uploads; public bucket for processed assets
Neo4j
- Social graph (friends, suggestions, relationship weights)
- Updated by GraphWorker and ScoringWorker from Kafka events
Elasticsearch / OpenSearch
- Full-text search (posts, blogs, users, hashtags)
- Synced by ElasticsearchSyncWorker from Kafka events
Scalability
Horizontal Scaling
- Stateless API servers
- Load balancer distribution
- Database replication
- Worker scaling
Caching Strategy
- Redis for hot data
- CDN for static assets
- Application-level caching
Security
Authentication
- JWT tokens
- Refresh token rotation
- OAuth support (optional)
Authorization
- Role-based access control
- Resource-level permissions
- API rate limiting
Data Protection
- HTTPS/TLS encryption
- Database encryption at rest
- Input validation and sanitization
Next Steps
- System Architecture Deep Dive — Media, recommendations, push, search, chat/calls, scaling.
- Microservices
- Data Flow