Skip to content
YaromyrSPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EventHub

A user event collection and viewing system built with .NET 8, Angular, Azure Service Bus, and Azure Functions — following event-driven architecture and the BMAD methodology.

Architecture Overview

┌─────────────┐       ┌─────────────────┐       ┌──────────────┐       ┌──────────────┐
│  Angular 21  │──────▶│  ASP.NET Core   │──────▶│ Azure Service│──────▶│Azure Function│
│     SPA      │ HTTP  │   Web API       │publish│    Bus       │trigger│  (Isolated)  │
│ (port 4200)  │◀──────│  (port 5001)    │       │  Queue:      │       │              │
└─────────────┘       └─────────────────┘       │  "events"    │       └──────┬───────┘
                             │ query             └──────────────┘              │ persist
                             ▼                                                ▼
                      ┌──────────────┐                               ┌──────────────┐
                      │  Azure SQL   │◀──────────────────────────────│  EF Core 8   │
                      │  Database    │                               │  DbContext   │
                      └──────────────┘                               └──────────────┘

Flow:

  1. User submits an event via the Angular SPA form
  2. API validates the request and publishes a message to the Azure Service Bus queue
  3. API returns 202 Accepted immediately (asynchronous processing)
  4. Azure Function triggers on the queue message and persists the event to Azure SQL
  5. User browses events via the Angular SPA table with filtering, sorting, and pagination

Technology Stack

Component Technology Version
Frontend Angular (standalone components, signals) 21.x
Styling SCSS —
Backend API ASP.NET Core Web API .NET 8.0 (LTS)
Event Processor Azure Functions (isolated worker) v4, .NET 8.0
Message Broker Azure Service Bus Queue mode
Database Azure SQL via Entity Framework Core EF Core 8.x
Infrastructure Bicep (IaC) —
Methodology BMAD Method v6.x

Prerequisites

  • .NET 8.0 SDK (or later — the projects target net8.0)
  • Node.js 18.x or later (for Angular CLI)
  • Azure Functions Core Tools v4
  • SQL Server LocalDB (included with Visual Studio or installable separately)
  • An Azure Service Bus namespace + queue (required for end-to-end event flow; there is no official local Service Bus emulator)

Project Structure

EventHub/
├── EventHub.slnx                     # .NET solution file
├── src/
│   ├── api/EventHub.Api/             # ASP.NET Core Web API
│   │   ├── Controllers/              #   EventsController (POST, GET)
│   │   ├── Services/                 #   EventService, ServiceBusPublisher
│   │   ├── Data/                     #   EF Core DbContext + Migrations
│   │   ├── Middleware/               #   ExceptionHandlingMiddleware
│   │   └── appsettings.json
│   ├── functions/EventHub.Functions/ # Azure Function (isolated worker)
│   │   ├── Functions/                #   EventProcessorFunction (ServiceBusTrigger)
│   │   ├── Services/                 #   EventPersistenceService
│   │   ├── Data/                     #   DbContext
│   │   └── local.settings.json
│   ├── shared/EventHub.Shared/       # Shared library
│   │   ├── Models/                   #   Event entity, EventType enum
│   │   └── DTOs/                     #   Request/Response DTOs, PagedResult<T>
│   └── web/EventHub.Web/            # Angular 21 SPA
│       └── src/app/
│           ├── components/           #   event-list, event-form, layout
│           ├── services/             #   EventService (HttpClient)
│           ├── interceptors/         #   errorInterceptor
│           ├── models/               #   TypeScript interfaces & enums
│           └── environments/         #   API URL configuration
├── infra/                            # Bicep IaC templates
│   ├── main.bicep
│   └── parameters.dev.bicepparam
├── _bmad-output/                     # BMAD methodology artifacts
│   └── planning-artifacts/           #   PRD, Architecture, Epics
└── README.md

Local Development Setup

1. Clone the repository

git clone <repository-url>
cd EventHub

2. Configure the database

The API and Functions use SQL Server LocalDB by default. No additional setup is needed if LocalDB is installed.

Connection string in src/api/EventHub.Api/appsettings.json:

Server=localhost;Database=EventHubDb;Trusted_Connection=True;TrustServerCertificate=True;

3. Apply EF Core migrations

cd src/api/EventHub.Api
dotnet ef database update

4. Configure Azure Service Bus

Update the connection string in both:

  • src/api/EventHub.Api/appsettings.json → ServiceBus:ConnectionString
  • src/functions/EventHub.Functions/local.settings.json → ServiceBusConnection

Replace with your Azure Service Bus namespace connection string. The queue name is events.

5. Run the API

cd src/api/EventHub.Api
dotnet run

The API starts at https://localhost:7090 (and http://localhost:5197). Swagger UI is available at https://localhost:7090/swagger.

6. Run the Azure Function

cd src/functions/EventHub.Functions
func start

The function listens on the events queue and processes messages into the database.

7. Run the Angular SPA

cd src/web/EventHub.Web
npm install
npx ng serve

The SPA is available at http://localhost:4200. It proxies API calls to https://localhost:5001/api.

Running Tests

dotnet test src/tests/EventHub.Backend.Tests/EventHub.Backend.Tests.csproj

The backend test suite covers:

  • EventServiceTests — API service layer (publishing, retrieval, filtering)
  • ExceptionHandlingMiddlewareTests — global error middleware
  • EventProcessorFunctionTests — Azure Function trigger logic
  • EventPersistenceServiceTests — database persistence service
  • CreateEventRequestValidationTests — DTO validation rules (including whitespace rejection)
  • DbContextModelConfigurationTests — EF Core model configuration

API Documentation

POST /api/events

Creates a new event and publishes it for asynchronous processing.

Request body:

{
  "userId": "user123",
  "type": "Click",
  "description": "User clicked the buy button"
}
Field Type Required Constraints
userId string Yes Max 200 characters
type string (enum) Yes PageView, Click, or Purchase
description string Yes Max 2000 characters

Response 202 Accepted:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "message": "Event accepted for processing"
}

Response 400 Bad Request (validation error):

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "UserId": ["The UserId field is required."]
  }
}

GET /api/events

Retrieves a paginated list of events with optional filtering and sorting.

Query parameters:

Parameter Type Default Description
type string — Filter by event type (PageView, Click, Purchase)
userId string — Filter by user ID
fromDate datetime — Filter events created after this date
toDate datetime — Filter events created before this date
sortBy string createdAt Sort field: createdAt, type, userId
sortDescending bool true Sort direction
page int 1 Page number (1-based)
pageSize int 20 Items per page (max 100)

Response 200 OK:

{
  "items": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "userId": "user123",
      "type": "Click",
      "description": "User clicked the buy button",
      "createdAt": "2026-03-02T10:30:00Z"
    }
  ],
  "totalCount": 42,
  "page": 1,
  "pageSize": 20
}

Design Decisions & Trade-offs

1. Azure SQL over Cosmos DB

Decision: Azure SQL with EF Core (Code-First).

Rationale: The Event model is a single flat entity with relational query needs (filtering, sorting, pagination). SQL provides strong LINQ-based querying via EF Core, code-first migrations for reproducible schemas, and lower cost for this use case. Cosmos DB would be overkill — it excels at document-oriented or globally distributed data, neither of which applies here.

2. Service Bus Queue over Topic

Decision: Queue (point-to-point) instead of Topic (pub/sub).

Rationale: Only one consumer (the Azure Function) processes events. A queue provides simpler configuration with the same reliability guarantees (dead-letter, retry). Topics add unnecessary complexity when there are no multiple subscribers.

3. Asynchronous event processing (202 Accepted)

Decision: The API publishes to Service Bus and returns immediately with 202 Accepted, rather than writing to the database synchronously.

Rationale: This decouples the API from the database, improves response times, and provides natural buffering under load. The trade-off is eventual consistency — an event may take a moment to appear in the list after creation. For this application, the delay is acceptable.

4. Azure Functions Isolated Worker over In-Process

Decision: .NET isolated worker model.

Rationale: The in-process model is deprecated. Isolated worker provides process-level isolation, full .NET 8 API surface, and better long-term support. The small overhead of out-of-process communication is negligible for this workload.

5. Angular Standalone Components (no NgModules)

Decision: All components are standalone with lazy-loaded routes.

Rationale: Angular's modern approach — standalone components are the recommended default. They simplify the dependency tree, enable per-route code splitting, and reduce boilerplate. The project has no legacy module dependencies.

6. ServiceBusMessage.MessageId for Idempotency

Decision: Set MessageId to the event's GUID.

Rationale: MessageId improves traceability and provides the key required for broker-level duplicate detection when that capability is enabled on the queue.

7. Error Handling Strategy

Decision: Centralized error middleware (API) + HTTP interceptor (Angular) + dead-letter queue (Service Bus).

Rationale:

  • API: ExceptionHandlingMiddleware catches all unhandled exceptions and returns RFC 7807 ProblemDetails. Exception details are included only in Development.
  • Angular: A functional HttpInterceptorFn logs errors and re-throws for component-level handling.
  • Service Bus: Messages that fail processing are retried up to 10 times, then moved to the dead-letter queue for investigation.

Infrastructure

Bicep templates in infra/ provision all Azure resources:

  • App Service Plan + App Service (API hosting)
  • Azure Service Bus namespace + events queue (dead-letter enabled)
  • Function App + Consumption plan + Storage Account
  • Azure SQL Server + Database
  • Application Insights

Deploy with:

az deployment group create \
  --resource-group rg-eventhub-dev \
  --template-file infra/main.bicep \
  --parameters @infra/parameters.dev.bicepparam sqlAdminPassword='<your-strong-password>'

BMAD Methodology

This project follows the BMAD (Business, Marketing, Architecture, Development) methodology. Planning artifacts are in _bmad-output/planning-artifacts/:

  • PRD (prd.md) — Product Requirements Document
  • Architecture (architecture.md) — Architecture Decision Document
  • Epics (epics.md) — Epic breakdown with 4 epics, 15 user stories

License

This project is a test task submission. All rights reserved.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages