Skip to content

AntonShcherbatskyi/hackdev

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

HackDev

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.


Repository structure

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)

Application architecture

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-scheme into Mermaid, so arrows and Rel() labels end up nearly invisible. Every diagram below includes a %%{init}%% theme override (bright #58a6ff lines, 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

Level 1 — System Context

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")
Loading

Level 2 — Container diagram

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")
Loading

Level 3 — Backend components

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")
Loading

Backend component map

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

Level 3 — Frontend components

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")
Loading

Level 4 — Clean Architecture dependency rule

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
Loading

Dynamic view — Authentication

%%{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
Loading

Dynamic view — Hackathon creation & moderation

%%{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
Loading

Dynamic view — Project submission

%%{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
Loading

Dynamic view — Real-time chat

%%{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
Loading

State view — Hackathon phases

%%{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
Loading

Deployment view — External services 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'}}}%%
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")
Loading

Concepts used

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

Backend layers

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

Frontend structure

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

Domain model

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

Hackathon lifecycle

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
moderationenrollment Moderator approves the hackathon (POST /moderation/hackathon/approve)
enrollmentteam_formation Participant count reaches MaxParticipants
team_formationbriefing Phase timer expires or all teams are full
briefinghacking Phase timer expires
hackingjudging Phase timer expires
judgingreview All projects have been reviewed by assigned reviewers
reviewconcluded 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
Loading

Project submission flow

See the Dynamic view — Project submission sequence diagram above. In summary:

  1. Team members update project metadata via PUT /projects/update.
  2. A team member submits via POST /projects/submit with a GitHub link, demo video, and optional presentation.
  3. Demo files are scanned by VirusTotal and stored in Azure Blob (demo-videos / demo-presentations containers).
  4. During judging, assigned reviewers score projects via POST /projects/review.
  5. During review, participants vote via POST /projects/vote/{projectId} (limited votes per user per hackathon).

Role promotion flow

%%{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
Loading
  1. A user submits a promoting request via POST /promoting/promote with skills, social URLs, and certificate files.
  2. Certificates are stored in the Azure certificates container.
  3. A moderator or admin reviews the request via POST /promoting/review.
  4. On approval, the user's role is updated (e.g. to reviewer).

API

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

External services & deployment

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.

Entity relationships

%%{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
    }
Loading

Design decisions

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

Azure Blob containers

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

Local development

Prerequisites

Database (Docker)

cd backend/Hackdev
docker compose up -d

This starts MySQL 8.2 on port 3307 with root password example.

Backend

  1. Apply EF Core migrations:
cd backend/Hackdev/HackDev.Data
dotnet ef database update --startup-project ../HackDev.Host
  1. Configure appsettings.Development.json in HackDev.Host:

    • Database:DevelopmentConnectionString — MySQL connection string
    • AzureBlobStorage:ConnectionString — Azure Storage or Azurite
    • Authentication:Jwt:* and Authentication:Refresh:* — token secrets and expiry
    • Twilio:TWILIO_ACCOUNT_SID, TWILIO_API_KEY, TWILIO_API_SECRET
    • VirusTotal:ApiKey
  2. Run the API:

cd ../HackDev.Host
dotnet run

The 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).

Frontend

cd frontend/hackdev
npm install
npm start

The frontend runs at http://localhost:4200. CORS is configured to allow localhost origins with credentials.

Tests

cd backend/Hackdev
dotnet test

Tech stack

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

About

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

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors