HackDev is a platform for organizing, managing, and participating in hackathons. Users create events, form teams, submit projects, chat in real time, join video rooms, and go through a full hackathon lifecycle from enrollment to judging. The project is a monorepo with an Angular SPA and an ASP.NET Core API backed by MySQL, Azure Blob Storage, and Twilio for video.
hackdev/
├── frontend/hackdev/ # Angular SPA
│ └── src/app/
│ ├── auth/ # Login & registration
│ ├── domain/ # Feature modules by role
│ │ ├── hackathon/ # Hackathon lifecycle pages & components
│ │ ├── admin/ # User management
│ │ ├── moderator/ # Hackathon & promoting approval
│ │ ├── mentor/ # Mentor dashboard
│ │ ├── reviewer/ # Project review & scoring
│ │ ├── reviewer_applicant/ # Reviewer promotion flow
│ │ ├── chat/ # Real-time messaging UI
│ │ ├── team/ # Team services
│ │ ├── project/ # Project services
│ │ └── promoting/ # Role promotion requests
│ ├── profile/ # User profile
│ ├── public/ # Landing page
│ ├── shared/ # Headers, buttons, API constants, services
│ ├── video/ # Twilio video rooms & calling
│ └── root/ # App shell & routing
│
└── backend/Hackdev/ # .NET solution
├── HackDev.Host/ # HTTP API host, middleware pipeline, DI composition
├── HackDev.Presentation/ # REST controllers, SignalR hubs, Twilio integration
├── HackDev.Application/ # MediatR CQRS handlers, accessors, background workers
├── HackDev.Domain/ # Entities, interfaces, constants, error definitions
├── HackDev.Data/ # EF Core DbContext, MySQL configurations, migrations, seeders
├── HackDev.Shared/ # FluentValidation registration
└── *Tests/ # Unit tests (Application, Presentation)
The backend follows Clean Architecture and the CQRS pattern via MediatR. Dependencies always point inward: Host → Presentation / Data / Application → Domain. Infrastructure concerns (MySQL, Azure Blob, Twilio, VirusTotal) are wired in Application and Presentation layers behind domain interfaces.
Diagrams below use the C4 model — zooming from system context down to components and dynamic flows.
GitHub rendering note: Mermaid C4 diagrams ship with dark-gray arrows meant for a white canvas. GitHub renders the README with a dark background but does not pass
prefers-color-schemeinto Mermaid, so arrows andRel()labels end up nearly invisible. Every diagram below includes a%%{init}%%theme override (bright#58a6fflines, light label text) to fix this. If labels still look off, toggle GitHub to light theme (Settings → Appearance).
| # | Diagram | C4 level | What it shows |
|---|---|---|---|
| 1 | System Context | L1 | Users, HackDev, and external systems |
| 2 | Container | L2 | SPA, API, MySQL, Azure, Twilio, VirusTotal |
| 3 | Backend components | L3 | .NET projects and their dependencies |
| 4 | Frontend components | L3 | Angular modules and service boundaries |
| 5 | Clean Architecture layers | L4 | Inward dependency rule across projects |
| 6 | Authentication | Dynamic | Register, login, token refresh |
| 7 | Hackathon creation & moderation | Dynamic | Create → approve → enrollment |
| 8 | Project submission | Dynamic | VirusTotal scan → Azure Blob upload |
| 9 | Real-time chat | Dynamic | SignalR groups + message persistence |
| 10 | Hackathon phases | State | Phase transitions and triggers |
| 11 | Phase updater worker | Dynamic | Background polling and auto-transitions |
| 12 | Role promotion | Dynamic | Certificate upload → moderator review |
| 13 | Deployment topology | Deployment | Runtime nodes and network paths |
| 14 | Entity relationships | Data | Core database entities and cardinalities |
Shows HackDev as a single system and who interacts with it.
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
C4Context
title Level 1 — System Context
Person(participant, "Participant", "Registers, enrolls in hackathons, joins teams, submits projects, votes")
Person(organizer, "Organizer", "Creates hackathons, manages phases, coordinates the event")
Person(moderator, "Moderator", "Approves hackathons and reviewer promotion requests")
Person(reviewer, "Reviewer", "Scores submitted projects during the judging phase")
Person(mentor, "Mentor", "Guides teams during active hackathons")
Person(admin, "Admin", "Manages users and platform configuration")
System(hackdev, "HackDev Platform", "Organizes end-to-end hackathon lifecycle: enrollment, teams, projects, chat, video, judging")
System_Ext(mysql, "MySQL", "Relational database for users, hackathons, teams, projects, chats, tokens")
System_Ext(azure, "Azure Blob Storage", "Stores hackathon images, demo files, and certificates")
System_Ext(twilio, "Twilio Video", "WebRTC video rooms for live collaboration")
System_Ext(virustotal, "VirusTotal", "Malware scanning for uploaded files")
Rel(participant, hackdev, "Uses", "HTTPS")
Rel(organizer, hackdev, "Creates & manages hackathons", "HTTPS")
Rel(moderator, hackdev, "Moderates content", "HTTPS")
Rel(reviewer, hackdev, "Reviews projects", "HTTPS")
Rel(mentor, hackdev, "Mentors teams", "HTTPS")
Rel(admin, hackdev, "Administers platform", "HTTPS")
Rel(hackdev, mysql, "Reads/writes", "TCP/SQL")
Rel(hackdev, azure, "Uploads/downloads files", "HTTPS")
Rel(hackdev, twilio, "Issues video tokens, lists rooms", "HTTPS")
Rel(hackdev, virustotal, "Scans files before storage", "HTTPS")
Shows the major deployable units and how they communicate.
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
C4Container
title Level 2 — Container diagram
Person(user, "Platform User", "Any authenticated role")
System_Boundary(hackdev, "HackDev Platform") {
Container(spa, "Angular SPA", "TypeScript, Angular 19", "Role-based UI: hackathon pages, chat, video, dashboards")
Container(api, "ASP.NET Core API", "C#, .NET 8", "REST endpoints, JWT auth, SignalR hubs, background workers")
ContainerDb(db, "MySQL Database", "MySQL 8", "Users, hackathons, teams, projects, chats, refresh tokens")
}
System_Ext(blob, "Azure Blob Storage", "Object storage with purpose-specific containers")
System_Ext(twilio, "Twilio Video API", "Managed WebRTC infrastructure")
System_Ext(vt, "VirusTotal API", "File reputation scanning")
Rel(user, spa, "Uses", "HTTPS")
Rel(spa, api, "API calls, WebSocket", "JSON/HTTPS, WSS")
Rel(spa, twilio, "Joins video rooms", "WebRTC")
Rel(api, db, "Reads/writes via EF Core", "TCP/SQL")
Rel(api, blob, "Uploads/downloads blobs", "HTTPS")
Rel(api, twilio, "Generates JWT, lists rooms", "HTTPS")
Rel(api, vt, "Submits files for scan", "HTTPS")
Internal structure of the ASP.NET Core API container.
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
C4Component
title Level 3 — Backend API components
Container(spa, "Angular SPA", "Angular 19", "Browser client")
Container_Boundary(api, "ASP.NET Core API") {
Component(host, "HackDev.Host", "ASP.NET Core", "Kestrel, CORS, auth pipeline, Swagger, hub mapping, DI root")
Component(presentation, "HackDev.Presentation", "ASP.NET Core MVC", "REST controllers, FluentValidation, SignalR hubs, mappers")
Component(application, "HackDev.Application", "MediatR, ErrorOr", "CQRS handlers, accessors, FileService, phase worker")
Component(domain, "HackDev.Domain", "Plain C#", "Entities, interfaces, phase/role constants, error definitions")
Component(data, "HackDev.Data", "EF Core", "DbContext, migrations, entity configurations, seeders")
Component(shared, "HackDev.Shared", "FluentValidation", "Cross-cutting validator registration")
}
ContainerDb(db, "MySQL", "MySQL 8", "Persistent storage")
System_Ext(blob, "Azure Blob", "File storage")
System_Ext(twilio, "Twilio", "Video API")
System_Ext(vt, "VirusTotal", "Malware scan")
Rel(spa, presentation, "HTTP / WSS", "JSON")
Rel(host, presentation, "Composes")
Rel(host, application, "Composes")
Rel(host, data, "Composes")
Rel(host, shared, "Composes")
Rel(presentation, application, "Dispatches commands/queries", "MediatR")
Rel(application, domain, "Uses entities & contracts")
Rel(data, domain, "Maps entities")
Rel(application, data, "Via accessors / IApplicationDbContext")
Rel(application, blob, "Via IFileService")
Rel(application, vt, "Via FileService")
Rel(presentation, twilio, "Via VideoService")
Rel(data, db, "SQL")
| Component | Key types | Responsibility |
|---|---|---|
| HackDev.Host | Program.cs |
Startup: CORS, JWT middleware, 100 MB upload limit, auto-migrate, seed, map hubs |
| Controllers | HackathonController, ProjectsController, ChatController, AuthenticationController, … |
HTTP boundary — validate, dispatch MediatR, return DataResponse envelope |
| SignalR Hubs | ChatHub, NotificationHub |
Chat group membership; broadcast video room changes |
| MediatR Handlers | CreateHackathonCommandHandler, SubmitProjectCommandHandler, SendChatMessageCommandHandler, … |
Business use cases; return ErrorOr<T> |
| Accessors | HackathonAccessor, UserAccessor, ProjectAccessor, TeamAccessor, … |
Focused EF queries per aggregate |
| Background worker | HackathonPhaseUpdaterBackgroundWorker |
Polls every 5 s; auto-advances hackathon phases |
| FileService | IFileService |
VirusTotal scan → Azure Blob upload across 5 containers |
| ApplicationDbContext | IApplicationDbContext |
EF Core persistence with snake_case naming |
Internal structure of the Angular SPA container.
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
C4Component
title Level 3 — Frontend SPA components
Person(user, "Platform User", "Browser")
Container_Boundary(spa, "Angular SPA") {
Component(shell, "App Shell", "root/", "Routing, layout, module bootstrap")
Component(auth, "Auth Module", "auth/", "Login, register, JWT storage & refresh")
Component(hackathon, "Hackathon Module", "domain/hackathon/", "Lifecycle pages per phase: enrollment → concluded")
Component(chat, "Chat Module", "domain/chat/", "Chat UI, SignalR connection, message list")
Component(video, "Video Module", "video/", "Twilio room join, participant tiles, calling service")
Component(roleDash, "Role Dashboards", "admin/, moderator/, mentor/, reviewer/", "Role-specific management UIs")
Component(shared, "Shared Layer", "shared/", "Headers, API constants, routing service, Material UI")
Component(services, "Domain Services", "*/services/", "HTTP clients for hackathon, project, team, promoting APIs")
}
Container(api, "ASP.NET Core API", ".NET 8", "Backend")
System_Ext(twilio, "Twilio Video", "WebRTC")
Rel(user, shell, "Navigates")
Rel(shell, auth, "Routes")
Rel(shell, hackathon, "Routes")
Rel(shell, roleDash, "Routes")
Rel(hackathon, services, "Calls")
Rel(chat, services, "Calls")
Rel(chat, api, "REST + SignalR WSS")
Rel(services, api, "REST/JSON")
Rel(video, api, "Fetches Twilio JWT")
Rel(video, twilio, "WebRTC media")
Rel(auth, services, "Token management")
Rel(shared, shell, "Shared UI primitives")
Shows the inward-pointing dependency direction enforced across .NET projects.
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
flowchart TB
subgraph L1["Outer — Frameworks & Drivers"]
Host["HackDev.Host<br/><i>Kestrel, Swagger, CORS</i>"]
Presentation["HackDev.Presentation<br/><i>Controllers, SignalR, Twilio SDK</i>"]
Data["HackDev.Data<br/><i>EF Core, MySQL provider</i>"]
end
subgraph L2["Application — Use Cases"]
Application["HackDev.Application<br/><i>MediatR handlers, accessors,<br/>FileService, background worker</i>"]
end
subgraph L3["Domain — Enterprise Rules"]
Domain["HackDev.Domain<br/><i>Entities, interfaces, constants,<br/>ErrorOr error definitions</i>"]
end
Host --> Presentation
Host --> Application
Host --> Data
Presentation --> Application
Application --> Domain
Data --> Domain
style Domain fill:#e8f5e9,stroke:#2e7d32
style Application fill:#e3f2fd,stroke:#1565c0
style L1 fill:#fff3e0,stroke:#e65100
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
sequenceDiagram
actor User
participant SPA as Angular SPA
participant Auth as AuthenticationController
participant MediatR as MediatR Handler
participant DB as MySQL
User->>SPA: Register / Login
SPA->>Auth: POST /auth/register or /auth/login
Auth->>Auth: FluentValidation
Auth->>MediatR: RegisterCommand / LoginCommand
MediatR->>DB: Create user / verify password hash
MediatR->>DB: Store refresh token
MediatR-->>Auth: ErrorOr AuthenticationResult
Auth-->>SPA: DataResponse { accessToken, refreshToken, role }
SPA->>SPA: Store tokens
Note over SPA,Auth: Token refresh
SPA->>Auth: POST /auth/refresh
Auth->>MediatR: RefreshTokenCommand
MediatR->>DB: Validate & rotate refresh token
MediatR-->>SPA: New access + refresh tokens
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
sequenceDiagram
actor Organizer
actor Moderator
participant SPA as Angular SPA
participant HC as HackathonController
participant MC as ModerationController
participant App as Application Handlers
participant Blob as Azure Blob
participant DB as MySQL
Organizer->>SPA: Create hackathon (form + image)
SPA->>HC: POST /hackathons/create
HC->>App: CreateHackathonCommand
App->>Blob: UploadHackathonImageAsync
App->>DB: Save hackathon (status=pending, phase=moderation)
App-->>SPA: Hackathon created
Moderator->>SPA: Approve hackathon
SPA->>MC: POST /moderation/hackathon/approve
MC->>App: ApproveHackathonCommand
App->>DB: status=active
App->>App: UpdatePhaseCommand → enrollment
App-->>SPA: Hackathon active, enrollment open
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
sequenceDiagram
actor Member as Team Member
participant SPA as Angular SPA
participant PC as ProjectsController
participant App as SubmitProjectCommandHandler
participant VT as VirusTotal
participant Blob as Azure Blob
participant DB as MySQL
Member->>SPA: Update project metadata
SPA->>PC: PUT /projects/update
PC->>App: UpdateProjectCommand
App->>DB: Save name, description, GitHub URL
Member->>SPA: Submit demo video + presentation
SPA->>PC: POST /projects/submit (multipart)
PC->>App: SubmitProjectCommand
App->>VT: Scan demo files
alt File infected
VT-->>App: Detected
App-->>SPA: Error — upload rejected
else File clean
VT-->>App: Clean
App->>Blob: Upload to demo-videos / demo-presentations
App->>DB: IsSubmitted = true
App-->>SPA: Project submitted
end
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
sequenceDiagram
actor User
participant SPA as Angular SPA
participant Hub as ChatHub (SignalR)
participant CC as ChatController
participant App as SendChatMessageCommandHandler
participant DB as MySQL
User->>SPA: Open chat
SPA->>Hub: Connect WSS /chatHub?access_token=JWT
SPA->>Hub: JoinChat(chatId)
Hub->>Hub: Add connection to group
User->>SPA: Send message
SPA->>CC: POST /chats/{chatId}/messages
CC->>App: SendChatMessageCommand
App->>DB: Verify user access (hackathon or team member)
App->>DB: Persist ChatMessage
CC->>Hub: Broadcast to chat group
Hub-->>SPA: Push message to all members
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
stateDiagram-v2
[*] --> moderation : Organizer creates hackathon
moderation --> enrollment : Moderator approves
moderation --> [*] : Moderator rejects
enrollment --> team_formation : MaxParticipants reached
team_formation --> briefing : Timer expires OR all teams full
briefing --> hacking : Timer expires
hacking --> judging : Timer expires
judging --> review : All projects reviewed
review --> concluded : Timer expires
concluded --> [*]
note right of moderation
status = pending
end note
note right of enrollment
status = active
Background worker polls every 5s
end note
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
C4Deployment
title Deployment — External services topology
Deployment_Node(browser, "User Browser", "Chrome, Firefox, Safari") {
Container(spa, "Angular SPA", "Static assets or ng serve")
}
Deployment_Node(appServer, "Application Server", "Local / cloud host") {
Container(api, "ASP.NET Core API", ".NET 8, Kestrel :5500")
}
Deployment_Node(dataStore, "Data Tier") {
ContainerDb(mysql, "MySQL 8", "Port 3307 (Docker) or managed instance")
}
Deployment_Node(azureCloud, "Azure") {
Container(blob, "Blob Storage", "uploads, hackathon-images, demo-videos, demo-presentations, certificates")
}
Deployment_Node(twilioCloud, "Twilio Cloud") {
Container(video, "Video API", "Room management + WebRTC TURN/STUN")
}
Deployment_Node(vtCloud, "VirusTotal") {
Container(scan, "File Scan API", "Pre-upload malware check")
}
Rel(spa, api, "REST + SignalR", "HTTPS / WSS")
Rel(spa, video, "WebRTC", "UDP/TCP")
Rel(api, mysql, "EF Core", "TCP/3306")
Rel(api, blob, "Azure SDK", "HTTPS/443")
Rel(api, video, "REST", "HTTPS/443")
Rel(api, scan, "REST", "HTTPS/443")
| Concept | Where | Purpose |
|---|---|---|
| Clean Architecture | Backend solution structure | Separates business logic from frameworks, databases, and third-party APIs |
| CQRS + MediatR | HackDev.Application |
Commands and queries are dispatched to dedicated IRequestHandler implementations |
| Accessor pattern | HackDev.Application |
HackathonAccessor, UserAccessor, etc. encapsulate EF queries behind focused data-access helpers |
| ErrorOr | Application handlers | Typed success/error results flow from handlers to controllers without exceptions for business failures |
| FluentValidation | HackDev.Shared + Presentation |
Request DTOs are validated before reaching MediatR handlers |
| Unified API envelope | DataResponse |
All endpoints return { isError, data, error } for consistent client handling |
| JWT + refresh tokens | Auth flow | Short-lived access tokens with revocable refresh tokens stored in MySQL |
| SignalR WebSockets | ChatHub, NotificationHub |
Real-time chat group membership and video room update notifications |
| Background worker | HackathonPhaseUpdaterBackgroundWorker |
Polls active hackathons every 5 seconds and advances phases based on timers and completion rules |
| VirusTotal scanning | FileService |
Uploaded files are scanned for malware before being stored in Azure Blob |
| Role-based authorization | Controllers | [Authorize(Roles = "...")] gates endpoints by user role (user, admin, moderator, mentor, reviewer) |
| Feature modules | Angular domain/ |
Hackathon, admin, mentor, reviewer, and moderator areas are self-contained modules |
| Twilio Video | video/ module + VideoService |
JWT tokens and room listing for in-browser video calls during hackathons |
| Layer | Responsibility |
|---|---|
| Host | Kestrel setup (100 MB upload limit), CORS, authentication pipeline, Swagger, SignalR hub mapping, auto-migration and seeding on startup |
| Presentation | REST controllers, request/response mappers, FluentValidation rules, SignalR hubs, Twilio video token generation |
| Application | MediatR handlers for all use cases, entity accessors, FileService, HackathonPhaseUpdaterBackgroundWorker |
| Domain | Entities, role/phase/status constants, IFileService and auth interfaces — no framework dependencies |
| Data | EF Core ApplicationDbContext, snake_case naming convention, MySQL provider, migrations, ISeeder implementations |
| Shared | Cross-cutting FluentValidation assembly scanning |
The SPA uses Angular 19 with feature modules organized by role. Shared concerns (headers, API constants, routing) live in shared/; page-level UI lives in domain/, auth/, and profile/.
| Area | Purpose |
|---|---|
auth/ |
Login, registration, JWT token management |
domain/hackathon/ |
Hackathon list, details, and phase-specific pages (enrollment → concluded) |
domain/admin/ |
Admin dashboard and user management |
domain/moderator/ |
Hackathon approval and promoting request review |
domain/mentor/ |
Mentor dashboard and assigned hackathons |
domain/reviewer/ |
Project review, scoring, and reviewer dashboard |
domain/chat/ |
Real-time chat UI backed by SignalR |
video/ |
Twilio video rooms, calling service, participant components |
shared/ |
Headers, buttons, API constants, routing service |
User
├── Id, FirstName, LastName, Username, Email, PasswordHash, Rating, Role
├── Specializations[]
├── Teams[]
└── RefreshTokens[]
Hackathon
├── Id, Name, Description, OrganizerId, ImageFileName
├── Status (pending | active | finished | rejected)
├── Phase (moderation → enrollment → team_formation → briefing → hacking → judging → review → concluded)
├── PhaseEndDateTime, HackingTimeMinutes, MaxParticipants, CurrentParticipantsCount
├── TeamsQuantity, TeamSize, ReviewersCount, MentorsCount
├── Organizer, Users[], Teams[], Projects[], Specializations[], Rules[]
Team
├── Id, Name, Description, HackathonId, LeaderId
├── MaxParticipantsQuantity, ParticipationQuantity
├── Users[], Project?, Tasks[]
Project
├── Id, Name, Description, GithubLink, HackathonId
├── IsSubmitted, IsReviewed, UserVotes
└── Score (reviewer-assigned)
Chat
├── Id, Type (hackathon | team), Name, HackathonId?, TeamId?
└── Messages[] (Content, SenderId, SentAt)
PromotingRequest
├── Id, UserId, Status, Skills[], SocialUrls[], Certificates[]
Task
├── Id, Name, Description, Status, TeamId
A hackathon moves through phases automatically (background worker) and manually (organizer via POST /hackathons/update-phase). See the State view — Hackathon phases diagram above for the full transition graph.
| Transition | Trigger |
|---|---|
moderation → enrollment |
Moderator approves the hackathon (POST /moderation/hackathon/approve) |
enrollment → team_formation |
Participant count reaches MaxParticipants |
team_formation → briefing |
Phase timer expires or all teams are full |
briefing → hacking |
Phase timer expires |
hacking → judging |
Phase timer expires |
judging → review |
All projects have been reviewed by assigned reviewers |
review → concluded |
Phase timer expires |
HackathonPhaseUpdaterBackgroundWorker runs as a hosted service, polling every 5 seconds and dispatching phase-change commands through MediatR.
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
sequenceDiagram
participant Worker as HackathonPhaseUpdaterBackgroundWorker
participant MediatR as MediatR
participant DB as MySQL
loop Every 5 seconds
Worker->>DB: Load active hackathons
DB-->>Worker: Hackathon list
alt enrollment & CurrentParticipantsCount >= MaxParticipants
Worker->>MediatR: ChangePhaseToTeamFormationCommand
else team_formation & all teams full
Worker->>MediatR: ChangePhaseToBriefingCommand
else phase timer expired (team_formation / briefing / hacking / review)
Worker->>MediatR: Next phase command
else judging & all projects IsReviewed
Worker->>MediatR: ChangePhaseToReviewCommand
end
MediatR->>DB: Update phase + PhaseEndDateTime
end
See the Dynamic view — Project submission sequence diagram above. In summary:
- Team members update project metadata via
PUT /projects/update. - A team member submits via
POST /projects/submitwith a GitHub link, demo video, and optional presentation. - Demo files are scanned by VirusTotal and stored in Azure Blob (
demo-videos/demo-presentationscontainers). - During judging, assigned reviewers score projects via
POST /projects/review. - During review, participants vote via
POST /projects/vote/{projectId}(limited votes per user per hackathon).
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
sequenceDiagram
actor Applicant as User (applicant)
actor Mod as Moderator
participant SPA as Angular SPA
participant PC as PromotingController
participant App as Application Handlers
participant Blob as Azure Blob (certificates)
participant DB as MySQL
Applicant->>SPA: Submit promotion request + certificates
SPA->>PC: POST /promoting/promote
PC->>App: CreatePromotingCommand
App->>Blob: Upload certificate files
App->>DB: Save PromotingRequest (status=pending)
App-->>SPA: Request created
Mod->>SPA: Review pending requests
SPA->>PC: GET /promoting
PC-->>SPA: List of requests
Mod->>SPA: Approve or reject
SPA->>PC: POST /promoting/review
PC->>App: UpdatePromotingRequestCommand
App->>DB: Update status + user role (e.g. reviewer)
App-->>SPA: Role updated
- A
usersubmits a promoting request viaPOST /promoting/promotewith skills, social URLs, and certificate files. - Certificates are stored in the Azure
certificatescontainer. - A
moderatororadminreviews the request viaPOST /promoting/review. - On approval, the user's role is updated (e.g. to
reviewer).
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/auth/register |
— | Create account |
POST |
/auth/login |
— | Login |
POST |
/auth/refresh |
— | Refresh access token |
POST |
/hackathons/create |
JWT (user) | Create hackathon (enters moderation) |
POST |
/hackathons/update-phase |
— | Manually advance hackathon phase |
POST |
/hackathons/attend |
JWT (user) | Enroll in a hackathon |
POST |
/hackathons/leave |
JWT (user) | Leave a hackathon |
GET |
/hackathons |
— | List all hackathons |
GET |
/hackathons/{id} |
— | Get hackathon by ID |
GET |
/hackathons/user |
JWT (user) | List user's hackathons |
GET |
/hackathons/image/{fileName} |
— | Get hackathon cover image |
POST |
/moderation/hackathon/approve |
JWT (moderator, admin) | Approve pending hackathon |
POST |
/moderation/hackathon/reject |
JWT (moderator, admin) | Reject pending hackathon |
POST |
/teams/attend |
JWT | Join a team during team formation |
GET |
/projects |
— | List all projects |
GET |
/projects/{projectId} |
— | Get project by ID |
GET |
/projects/team/{teamId} |
— | Get project by team |
PUT |
/projects/update |
— | Update project metadata |
POST |
/projects/submit |
JWT (user) | Submit project with demo files |
GET |
/projects/demo/{fileName} |
— | Stream demo video or presentation |
POST |
/projects/vote/{projectId} |
JWT (user) | Vote for a project |
GET |
/projects/for-review |
JWT (reviewer) | List projects awaiting review |
GET |
/projects/remaining-votes |
JWT (user) | Get remaining vote count |
POST |
/projects/review |
JWT (reviewer) | Score a project |
GET |
/chats |
JWT | List user's chats |
GET |
/chats/hackathon/{id} |
JWT | Get hackathon chat |
GET |
/chats/team/{id} |
JWT | Get team chat |
GET |
/chats/{id} |
JWT | Get chat by ID |
GET |
/chats/{chatId}/messages |
JWT | Get chat messages |
POST |
/chats/{chatId}/messages |
JWT | Send a chat message |
POST |
/tasks/create |
— | Create a team task |
GET |
/tasks/get-for-team/{teamId} |
— | List tasks for a team |
PUT |
/tasks/update |
— | Update a team task |
GET |
/users/get/all |
JWT (admin) | List all users |
GET |
/users/get/one/{id} |
JWT (admin, moderator, user) | Get user by ID |
PUT |
/users/update |
— | Update user profile |
GET |
/users/role/{userId} |
— | Get user role |
POST |
/users/create |
— | Create user (admin) |
GET |
/users/reviewers |
— | List reviewers |
GET |
/users/mentors |
— | List mentors |
GET |
/promoting |
JWT (admin, moderator) | List promoting requests |
POST |
/promoting/promote |
JWT (user) | Submit reviewer promotion request |
POST |
/promoting/review |
JWT (moderator, admin) | Approve/reject promotion |
GET |
/promoting/certificates/{name} |
— | Download certificate file |
GET |
/mentor/hackathons-for-mentoring |
JWT (mentor) | List hackathons for mentor |
GET |
/specializations |
— | List specializations |
GET |
/video/token |
— | Get Twilio video JWT |
GET |
/video/rooms |
— | List active Twilio video rooms |
GET |
/certificates/get/{name} |
— | Get certificate content |
SignalR hubs:
| Hub | Path | Purpose |
|---|---|---|
ChatHub |
/chatHub |
Join/leave chat groups; JWT passed via access_token query param |
NotificationHub |
/notificationHub |
Broadcast video room updates to connected clients |
Production relies on managed services for persistence, file storage, malware scanning, and video. See the Deployment view — External services topology diagram in the architecture section for the full topology.
%%{init: {'theme':'base','themeVariables':{'lineColor':'#58a6ff','arrowheadColor':'#58a6ff','primaryBorderColor':'#58a6ff','secondaryBorderColor':'#58a6ff','tertiaryBorderColor':'#8b949e','relationLabelColor':'#e6edf3','relationLabelBackground':'#21262d','actorLineColor':'#58a6ff','signalColor':'#58a6ff','signalTextColor':'#e6edf3','labelTextColor':'#e6edf3','textColor':'#e6edf3','nodeBorder':'#58a6ff','clusterBkg':'#161b22','clusterBorder':'#58a6ff'}}}%%
erDiagram
USER ||--o{ TEAM : "joins"
USER ||--o{ HACKATHON : "attends"
USER ||--o{ REFRESH_TOKEN : "owns"
USER ||--o{ PROMOTING_REQUEST : "submits"
USER }o--o{ SPECIALIZATION : "has"
HACKATHON ||--|{ TEAM : "contains"
HACKATHON ||--|{ PROJECT : "has"
HACKATHON ||--|{ HACKATHON_RULE : "defines"
HACKATHON }o--o{ SPECIALIZATION : "requires"
HACKATHON ||--o| USER : "organized by"
TEAM ||--o| PROJECT : "submits"
TEAM ||--|{ TASK : "tracks"
TEAM ||--o| USER : "led by"
TEAM ||--o{ CHAT : "has"
HACKATHON ||--o{ CHAT : "has"
CHAT ||--|{ CHAT_MESSAGE : "contains"
CHAT_MESSAGE }o--|| USER : "sent by"
PROJECT ||--|| PROJECT_SCORE : "scored by"
PROJECT }o--o{ HACKATHON_USER_VOTES : "receives"
USER {
guid id PK
string role
string email
int rating
}
HACKATHON {
guid id PK
string status
string phase
datetime phase_end_date_time
int max_participants
}
TEAM {
guid id PK
int max_participants_quantity
int participation_quantity
}
PROJECT {
guid id PK
bool is_submitted
bool is_reviewed
int user_votes
}
| Decision | Rationale |
|---|---|
| MySQL with snake_case convention | Relational data with EF Core naming conventions (UseSnakeCaseNamingConvention) for consistent column naming |
| Azure Blob containers by purpose | Separate containers for uploads, hackathon images, demo files, and certificates — each with different access patterns |
| VirusTotal pre-upload scan | Files are checked for malware before being persisted; infected uploads are rejected |
| Twilio for video | Managed WebRTC infrastructure avoids operating a custom media server |
| SignalR for chat notifications | Server pushes new messages to chat group members without polling |
| Background phase worker | Hackathon phases advance on timers and completion rules without requiring organizer action |
| Accessor pattern over repositories | Focused query helpers per aggregate reduce boilerplate while keeping data access in the Application layer |
| Auto-migration on startup | Development and first-run environments apply pending EF migrations automatically |
| Container | Content |
|---|---|
uploads |
General user uploads (certificates during promotion, scanned by VirusTotal) |
hackathon-images |
Hackathon cover images (PNG/JPG) |
demo-videos |
Project demo video files |
demo-presentations |
Project demo presentation files (PPTX) |
certificates |
Stored reviewer-applicant certificate files |
- .NET 8 SDK
- Node.js 20+
- MySQL 8+ (or Docker via
docker-compose.yaml)
cd backend/Hackdev
docker compose up -dThis starts MySQL 8.2 on port 3307 with root password example.
- Apply EF Core migrations:
cd backend/Hackdev/HackDev.Data
dotnet ef database update --startup-project ../HackDev.Host-
Configure
appsettings.Development.jsoninHackDev.Host:Database:DevelopmentConnectionString— MySQL connection stringAzureBlobStorage:ConnectionString— Azure Storage or AzuriteAuthentication:Jwt:*andAuthentication:Refresh:*— token secrets and expiryTwilio:TWILIO_ACCOUNT_SID,TWILIO_API_KEY,TWILIO_API_SECRETVirusTotal:ApiKey
-
Run the API:
cd ../HackDev.Host
dotnet runThe API runs at http://localhost:5500. Swagger UI is enabled in Development.
On startup the host auto-applies pending migrations (if the database does not exist) and runs seeders (UserSeeder, SpecializationSeeder).
cd frontend/hackdev
npm install
npm startThe frontend runs at http://localhost:4200. CORS is configured to allow localhost origins with credentials.
cd backend/Hackdev
dotnet test| Component | Technology |
|---|---|
| Frontend | Angular 19, TypeScript, Angular Material, SignalR client |
| Backend | ASP.NET Core (.NET 8), MediatR (CQRS), ErrorOr |
| Architecture | Clean Architecture |
| Database | MySQL 8, Entity Framework Core (snake_case) |
| Real-time | SignalR WebSockets |
| Video | Twilio Video API |
| Object storage | Azure Blob Storage |
| File security | VirusTotal API |
| Authentication | JWT + refresh tokens |
| Validation | FluentValidation |