diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..f83c930
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+# Default owners for all files
+* @eventhub/maintainers
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..ffaffde
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+ - package-ecosystem: "nuget"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..603dccd
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,13 @@
+## Summary
+- [ ] Describe the change in 1-2 bullet points
+- [ ] Mention any related issues or links
+
+## Testing
+- [ ] Added or updated tests
+- [ ] `dotnet test` (with coverage)
+- [ ] Other: ______
+
+## Additional checks
+- [ ] Documentation updated (if needed)
+- [ ] Breaking changes noted and communicated
+- [ ] Security/privacy impact considered
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c653894..131f601 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -31,8 +31,14 @@ jobs:
- name: Restore dependencies
run: dotnet restore
+ - name: Check code format
+ run: dotnet format --verify-no-changes
+
- name: Build solution
run: dotnet build --configuration Release --no-restore
- - name: Skip tests (for now)
- run: echo "No test project yet — skipping tests"
+ - name: Run tests with coverage
+ run: dotnet test --configuration Release --no-build --collect "XPlat Code Coverage"
+
+ - name: Scan for vulnerable packages
+ run: dotnet list package --vulnerable
diff --git a/EventHub.sln b/EventHub.sln
index 3c42a07..91aab19 100644
--- a/EventHub.sln
+++ b/EventHub.sln
@@ -1,87 +1,103 @@
-
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.Domain", "src\EventHub.Domain\EventHub.Domain.csproj", "{1CDAA880-1542-4644-9DF3-78BCADCE543E}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{848702C5-0F6F-443E-9835-9B6AF62862CC}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.Application", "src\EventHub.Application\EventHub.Application.csproj", "{8D99A724-5894-4C57-A4A8-A59460512D15}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.Domain", "src\\EventHub.Domain\\EventHub.Domain.csproj", "{1CDAA880-1542-4644-9DF3-78BCADCE543E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.Infrastructure", "src\EventHub.Infrastructure\EventHub.Infrastructure.csproj", "{B97C9E27-790A-489E-B0EA-9F8B4700ECF9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.Application", "src\\EventHub.Application\\EventHub.Application.csproj", "{8D99A724-5894-4C57-A4A8-A59460512D15}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.API", "src\EventHub.API\EventHub.API.csproj", "{B514BAC6-A727-4A6F-AB52-D89F40FCB561}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.Infrastructure", "src\\EventHub.Infrastructure\\EventHub.Infrastructure.csproj", "{B97C9E27-790A-489E-B0EA-9F8B4700ECF9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.API", "src\\EventHub.API\\EventHub.API.csproj", "{B514BAC6-A727-4A6F-AB52-D89F40FCB561}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHub.Domain.Tests", "tests\\EventHub.Domain.Tests\\EventHub.Domain.Tests.csproj", "{482DFB1D-EC75-44AA-953A-3557DA2B91F0}"
EndProject
Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|x64.Build.0 = Debug|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|x86.Build.0 = Debug|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|Any CPU.Build.0 = Release|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|x64.ActiveCfg = Release|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|x64.Build.0 = Release|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|x86.ActiveCfg = Release|Any CPU
- {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|x86.Build.0 = Release|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|x64.Build.0 = Debug|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|x86.Build.0 = Debug|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|Any CPU.Build.0 = Release|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|x64.ActiveCfg = Release|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|x64.Build.0 = Release|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|x86.ActiveCfg = Release|Any CPU
- {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|x86.Build.0 = Release|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|x64.ActiveCfg = Debug|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|x64.Build.0 = Debug|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|x86.ActiveCfg = Debug|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|x86.Build.0 = Debug|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|Any CPU.Build.0 = Release|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|x64.ActiveCfg = Release|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|x64.Build.0 = Release|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|x86.ActiveCfg = Release|Any CPU
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|x86.Build.0 = Release|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|x64.ActiveCfg = Debug|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|x64.Build.0 = Debug|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|x86.ActiveCfg = Debug|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|x86.Build.0 = Debug|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|Any CPU.Build.0 = Release|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|x64.ActiveCfg = Release|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|x64.Build.0 = Release|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|x86.ActiveCfg = Release|Any CPU
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|x86.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {1CDAA880-1542-4644-9DF3-78BCADCE543E} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- {8D99A724-5894-4C57-A4A8-A59460512D15} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- {B97C9E27-790A-489E-B0EA-9F8B4700ECF9} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- {B514BAC6-A727-4A6F-AB52-D89F40FCB561} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {D8BB9D14-EA84-4F5B-A466-7721011ED58D}
- EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|x64.Build.0 = Debug|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Debug|x86.Build.0 = Debug|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|x64.ActiveCfg = Release|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|x64.Build.0 = Release|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|x86.ActiveCfg = Release|Any CPU
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E}.Release|x86.Build.0 = Release|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|x64.Build.0 = Debug|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Debug|x86.Build.0 = Debug|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|x64.ActiveCfg = Release|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|x64.Build.0 = Release|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|x86.ActiveCfg = Release|Any CPU
+ {8D99A724-5894-4C57-A4A8-A59460512D15}.Release|x86.Build.0 = Release|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|x64.Build.0 = Debug|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Debug|x86.Build.0 = Debug|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|x64.ActiveCfg = Release|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|x64.Build.0 = Release|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|x86.ActiveCfg = Release|Any CPU
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9}.Release|x86.Build.0 = Release|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|x64.Build.0 = Debug|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Debug|x86.Build.0 = Debug|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|x64.ActiveCfg = Release|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|x64.Build.0 = Release|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|x86.ActiveCfg = Release|Any CPU
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561}.Release|x86.Build.0 = Release|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Debug|x64.Build.0 = Debug|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Debug|x86.Build.0 = Debug|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Release|x64.ActiveCfg = Release|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Release|x64.Build.0 = Release|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Release|x86.ActiveCfg = Release|Any CPU
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {1CDAA880-1542-4644-9DF3-78BCADCE543E} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
+ {8D99A724-5894-4C57-A4A8-A59460512D15} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
+ {B97C9E27-790A-489E-B0EA-9F8B4700ECF9} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
+ {B514BAC6-A727-4A6F-AB52-D89F40FCB561} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
+ {482DFB1D-EC75-44AA-953A-3557DA2B91F0} = {848702C5-0F6F-443E-9835-9B6AF62862CC}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D8BB9D14-EA84-4F5B-A466-7721011ED58D}
+ EndGlobalSection
EndGlobal
diff --git a/README.md b/README.md
index ba93269..7de1d7c 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,29 @@
# EventHub
A clean-architecture, cloud-ready event scheduling and registration API built with .NET 8, Postgres, Docker, and full CI/CD pipelines.
+
+## Local setup
+Ensure your environment matches CI so pull requests succeed:
+
+1. Install the .NET 8 SDK (the repo pins 8.0.100 via `global.json`).
+2. Restore packages:
+ ```bash
+ dotnet restore
+ ```
+3. Verify formatting (CI runs this step):
+ ```bash
+ dotnet format --verify-no-changes
+ ```
+4. Build in Release mode:
+ ```bash
+ dotnet build --configuration Release --no-restore
+ ```
+5. Run tests with coverage (mirrors CI):
+ ```bash
+ dotnet test --configuration Release --no-build --collect "XPlat Code Coverage"
+ ```
+6. Check vulnerable dependencies:
+ ```bash
+ dotnet list package --vulnerable
+ ```
+
+Running the above commands locally before opening a PR will align with the CI workflow and reduce failures.
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..391ba3c
--- /dev/null
+++ b/global.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "8.0.100",
+ "rollForward": "latestFeature"
+ }
+}
diff --git a/src/EventHub.API/EventHub.API.csproj b/src/EventHub.API/EventHub.API.csproj
index cde9405..1c4296f 100644
--- a/src/EventHub.API/EventHub.API.csproj
+++ b/src/EventHub.API/EventHub.API.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/src/EventHub.Application/DTOs/EventDto.cs b/src/EventHub.Application/DTOs/EventDto.cs
index 4c995ab..f2229c0 100644
--- a/src/EventHub.Application/DTOs/EventDto.cs
+++ b/src/EventHub.Application/DTOs/EventDto.cs
@@ -1,21 +1,12 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+namespace EventHub.Application.DTOs;
-namespace EventHub.Application.DTOs
+public class EventDto
{
-
- public class EventDto
- {
- public Guid Id { get; set; }
- public string Title { get; set; } = string.Empty;
- public string Description { get; set; } = string.Empty;
- public DateTime StartTimeUtc { get; set; }
- public DateTime EndTimeUtc { get; set; }
- public string Location { get; set; } = string.Empty;
- public DateTime CreatedAtUtc { get; set; }
- }
-
+ public Guid Id { get; set; }
+ public string Title { get; set; } = string.Empty;
+ public string Description { get; set; } = string.Empty;
+ public DateTime StartTimeUtc { get; set; }
+ public DateTime EndTimeUtc { get; set; }
+ public string Location { get; set; } = string.Empty;
+ public DateTime CreatedAtUtc { get; set; }
}
diff --git a/src/EventHub.Domain/Exceptions/InvalidEmailException.cs b/src/EventHub.Domain/Exceptions/InvalidEmailException.cs
index ba88799..d519a0f 100644
--- a/src/EventHub.Domain/Exceptions/InvalidEmailException.cs
+++ b/src/EventHub.Domain/Exceptions/InvalidEmailException.cs
@@ -1,6 +1,8 @@
namespace EventHub.Domain.Exceptions;
-public class InvalidEmailException :DomainException
+public class InvalidEmailException : DomainException
{
- public InvalidEmailException(string message) : base(message) { }
+ public InvalidEmailException(string message) : base(message)
+ {
+ }
}
\ No newline at end of file
diff --git a/src/EventHub.Domain/ValueObjects/Email.cs b/src/EventHub.Domain/ValueObjects/Email.cs
index c9e4fad..884251d 100644
--- a/src/EventHub.Domain/ValueObjects/Email.cs
+++ b/src/EventHub.Domain/ValueObjects/Email.cs
@@ -1,6 +1,5 @@
-using EventHub.Domain.Exceptions;
using System.Text.RegularExpressions;
-using EventHub.Domain.ValueObjects;
+using EventHub.Domain.Exceptions;
namespace EventHub.Domain.ValueObjects;
@@ -8,12 +7,13 @@ public record Email
{
public string Value { get; }
private static readonly Regex EmailRegex = new(@"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.Compiled);
-
+
public Email(string value)
{
if (string.IsNullOrWhiteSpace(value) || !EmailRegex.IsMatch(value))
throw new InvalidEmailException("Invalid email format.");
Value = value;
}
+
public override string ToString() => Value;
}
\ No newline at end of file
diff --git a/src/EventHub.Infrastructure/EventHub.Infrastructure.csproj b/src/EventHub.Infrastructure/EventHub.Infrastructure.csproj
index bbd9c33..ba10ca6 100644
--- a/src/EventHub.Infrastructure/EventHub.Infrastructure.csproj
+++ b/src/EventHub.Infrastructure/EventHub.Infrastructure.csproj
@@ -1,13 +1,13 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
diff --git a/src/EventHub.Infrastructure/Repositories/RepositoryBase.cs b/src/EventHub.Infrastructure/Repositories/RepositoryBase.cs
index a020f63..6ece9c9 100644
--- a/src/EventHub.Infrastructure/Repositories/RepositoryBase.cs
+++ b/src/EventHub.Infrastructure/Repositories/RepositoryBase.cs
@@ -1,6 +1,5 @@
-using EventHub.Application.Interfaces;
+using EventHub.Application.Interfaces;
using Microsoft.EntityFrameworkCore;
-using System.Collections.Generic;
namespace EventHub.Infrastructure.Repositories;
@@ -24,7 +23,7 @@ public async Task> GetAllAsync() =>
public async Task AddAsync(T entity)
{
await _set.AddAsync(entity);
- await _context.SaveChangesAsync();
+ await _context.SaveChangesAsync();
}
public async Task RemoveAsync(T entity)
diff --git a/tests/EventHub.Domain.Tests/EmailTests.cs b/tests/EventHub.Domain.Tests/EmailTests.cs
new file mode 100644
index 0000000..ae4ceef
--- /dev/null
+++ b/tests/EventHub.Domain.Tests/EmailTests.cs
@@ -0,0 +1,27 @@
+using EventHub.Domain.Exceptions;
+using EventHub.Domain.ValueObjects;
+using Xunit;
+
+namespace EventHub.Domain.Tests;
+
+public class EmailTests
+{
+ [Fact]
+ public void Constructor_WithValidEmail_SetsValue()
+ {
+ var email = new Email("user@example.com");
+
+ Assert.Equal("user@example.com", email.Value);
+ Assert.Equal("user@example.com", email.ToString());
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData("invalid")]
+ [InlineData("user@domain")]
+ [InlineData("@example.com")]
+ public void Constructor_WithInvalidEmail_Throws(string input)
+ {
+ Assert.Throws(() => new Email(input));
+ }
+}
diff --git a/tests/EventHub.Domain.Tests/EventHub.Domain.Tests.csproj b/tests/EventHub.Domain.Tests/EventHub.Domain.Tests.csproj
new file mode 100644
index 0000000..c712735
--- /dev/null
+++ b/tests/EventHub.Domain.Tests/EventHub.Domain.Tests.csproj
@@ -0,0 +1,22 @@
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
diff --git a/tests/EventHub.Domain.Tests/EventTests.cs b/tests/EventHub.Domain.Tests/EventTests.cs
new file mode 100644
index 0000000..bf9571b
--- /dev/null
+++ b/tests/EventHub.Domain.Tests/EventTests.cs
@@ -0,0 +1,52 @@
+using EventHub.Domain.Entities;
+using EventHub.Domain.Exceptions;
+using Xunit;
+
+namespace EventHub.Domain.Tests;
+
+public class EventTests
+{
+ [Fact]
+ public void Constructor_WithValidData_SetsProperties()
+ {
+ var start = DateTime.UtcNow.AddHours(1);
+ var end = start.AddHours(2);
+
+ var @event = new Event("Launch", "Product launch", start, end, "Online");
+
+ Assert.Equal("Launch", @event.Title);
+ Assert.Equal("Product launch", @event.Description);
+ Assert.Equal(start, @event.StartTimeUtc);
+ Assert.Equal(end, @event.EndTimeUtc);
+ Assert.Equal("Online", @event.Location);
+ Assert.True((DateTime.UtcNow - @event.CreatedAtUtc).TotalSeconds < 5);
+ }
+
+ [Fact]
+ public void Constructor_WithEndBeforeStart_Throws()
+ {
+ var start = DateTime.UtcNow.AddHours(2);
+ var end = start.AddHours(-1);
+
+ Assert.Throws(() => new Event("Title", "Description", start, end, "Room 1"));
+ }
+
+ [Fact]
+ public void Update_WithValidData_ChangesProperties()
+ {
+ var start = DateTime.UtcNow.AddHours(1);
+ var end = start.AddHours(2);
+ var @event = new Event("Original", "Description", start, end, "Room 1");
+
+ var newStart = start.AddDays(1);
+ var newEnd = newStart.AddHours(3);
+
+ @event.Update("Updated", "New description", newStart, newEnd, "Room 42");
+
+ Assert.Equal("Updated", @event.Title);
+ Assert.Equal("New description", @event.Description);
+ Assert.Equal(newStart, @event.StartTimeUtc);
+ Assert.Equal(newEnd, @event.EndTimeUtc);
+ Assert.Equal("Room 42", @event.Location);
+ }
+}
diff --git a/tests/EventHub.Domain.Tests/ParticipantTests.cs b/tests/EventHub.Domain.Tests/ParticipantTests.cs
new file mode 100644
index 0000000..95b7641
--- /dev/null
+++ b/tests/EventHub.Domain.Tests/ParticipantTests.cs
@@ -0,0 +1,28 @@
+using EventHub.Domain.Entities;
+using EventHub.Domain.ValueObjects;
+using Xunit;
+
+namespace EventHub.Domain.Tests;
+
+public class ParticipantTests
+{
+ [Fact]
+ public void Constructor_WithValidData_SetsProperties()
+ {
+ var email = new Email("jane.doe@example.com");
+ var participant = new Participant("Jane Doe", email);
+
+ Assert.Equal("Jane Doe", participant.Name);
+ Assert.Equal(email, participant.Email);
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData(" ")]
+ public void Constructor_WithEmptyName_Throws(string name)
+ {
+ var email = new Email("john@example.com");
+
+ Assert.Throws(() => new Participant(name, email));
+ }
+}
diff --git a/tests/EventHub.Domain.Tests/RegistrationTests.cs b/tests/EventHub.Domain.Tests/RegistrationTests.cs
new file mode 100644
index 0000000..fed8cc8
--- /dev/null
+++ b/tests/EventHub.Domain.Tests/RegistrationTests.cs
@@ -0,0 +1,20 @@
+using EventHub.Domain.Entities;
+using Xunit;
+
+namespace EventHub.Domain.Tests;
+
+public class RegistrationTests
+{
+ [Fact]
+ public void Constructor_SetsPropertiesAndTimestamp()
+ {
+ var eventId = Guid.NewGuid();
+ var participantId = Guid.NewGuid();
+
+ var registration = new Registration(eventId, participantId);
+
+ Assert.Equal(eventId, registration.EventId);
+ Assert.Equal(participantId, registration.ParticipantId);
+ Assert.True((DateTime.UtcNow - registration.RegisteredAtUtc).TotalSeconds < 5);
+ }
+}