Backend Architecture
Architecture of the .NET Core backend API.
Technology Stack
- .NET 6.0: Runtime and framework
- ASP.NET Core: Web framework
- Entity Framework Core: ORM
- SignalR: WebSocket support
- MediatR: Mediator pattern
- AutoMapper: Object mapping
- Kafka: Event streaming
Project Structure
The backend lives under Src/backend/. The main API and workers are sibling projects (separate .csproj):
Src/backend/
├── API/ # Web API (REST + SignalR)
│ ├── Controllers/ # API controllers (Authentication, Post, Comment, Chat, etc.)
│ ├── Middlewares/ # Error handling, license, rate limit, host validation
│ ├── Dtos/, Helpers/ # DTOs and Swagger helpers
│ └── Program.cs # Startup
├── Application/ # Business logic (CQRS, MediatR)
│ └── Modules/ # Feature modules (Authentication, Post, Comment, Story, etc.)
├── Domain/ # Domain models and entities
│ └── Modules/ # Aggregates and value objects
├── Infrastructure/ # EF Core, repositories, Kafka, external services
├── Shared/ # Shared contracts and utilities
├── DatabaseApplication/ # Migrations and seeders
├── SharedWorker/ # Base worker, Kafka consumer, JWT, SignalR client
├── GraphWorker/ # Social graph (Neo4j)
├── ScoringWorker/ # Content scoring, recommendation
├── TrendingWorker/ # Trending decay
├── HashtagWorker/ # Hashtag extraction/indexing
├── ElasticsearchSyncWorker/ # Sync content to Elasticsearch
├── BlogAutoGenerationWorker/ # AI blog generation
├── InteractionWorker/ # Engagement processing
├── MediaProcessingWorker/ # Media processing
├── WebSocketWorker/ # Real-time notifications
├── WebPushNotificationWorker/ # Push notifications
└── ChatWorker/ # Real-time chat (SignalR hub)
Architecture Pattern
Clean Architecture
┌─────────── ──────────────────────────┐
│ API Layer │
│ (Controllers, Middlewares) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Application Layer │
│ (Services, Use Cases, DTOs) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Domain Layer │
│ (Entities, Value Objects) │
└───────── ─────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Infrastructure Layer │
│ (Database, External APIs) │
└─────────────────────────────────────┘
API Controllers
Controller Structure
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class PostsController : ControllerBase
{
private readonly IPostService _postService;
[HttpGet]
public async Task<ActionResult<PagedResult<PostDto>>> GetPosts([FromQuery] int page = 1)
{
var posts = await _postService.GetPostsAsync(page);
return Ok(posts);
}
[HttpPost]
public async Task<ActionResult<PostDto>> CreatePost([FromBody] CreatePostDto dto)
{
var post = await _postService.CreatePostAsync(dto);
return CreatedAtAction(nameof(GetPost), new { id = post.Id }, post);
}
}
Service Layer
Service Implementation
public class PostService : IPostService
{
private readonly IPostRepository _repository;
private readonly IEventPublisher _eventPublisher;
public async Task<PostDto> CreatePostAsync(CreatePostDto dto)
{
var post = new Post
{
Content = dto.Content,
AuthorId = dto.AuthorId,
CreatedAt = DateTime.UtcNow
};
await _repository.AddAsync(post);
await _eventPublisher.PublishAsync(new PostCreatedEvent(post));
return _mapper.Map<PostDto>(post);
}
}
Database Context
Entity Framework Setup
public class ApplicationDbContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
Event-Driven Architecture
Event Publishing
public class PostCreatedEvent
{
public string PostId { get; set; }
public string AuthorId { get; set; }
public DateTime CreatedAt { get; set; }
}
// Publish event
await _eventPublisher.PublishAsync(new PostCreatedEvent
{
PostId = post.Id,
AuthorId = post.AuthorId,
CreatedAt = post.CreatedAt
});
Event Consumers (Workers)
Workers consume events from Kafka and process them asynchronously.
Authentication & Authorization
JWT Authentication
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = configuration["Jwt:Issuer"],
ValidAudience = configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"]))
};
});