Skip to main content

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 MediaFile records 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

  1. Client Request → Frontend or Admin sends HTTP request (with optional SignalR for real-time).
  2. Backend API → ASP.NET Core receives request (middleware: license, rate limit, auth).
  3. Authentication → JWT validation and role-based authorization (User, Moderator, Admin).
  4. Business Logic → MediatR handlers, domain logic, repositories.
  5. Data Access → PostgreSQL/MongoDB/Redis/Neo4j/Elasticsearch as needed; optional Kafka publish for async side effects.
  6. Response → JSON response (or 201/204) sent to client.

Event Flow

  1. 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).
  2. Worker consumes → Corresponding worker (separate process) processes the message.
  3. Data updated → Worker writes to PostgreSQL, MongoDB, Redis, Neo4j, or Elasticsearch as needed.
  4. 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