diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..910cfff1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+################################################################################
+# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
+################################################################################
+
+/NUIX.InvestmentPerformance.API/obj
+/NUIX.InvestmentPerformance.API.Test/obj
+/NUIX.InvestmentPerformance.API/bin/Debug/net7.0
+/NUIX.InvestmentPerformance.API/bin/Debug/net8.0
+/NUIX.InvestmentPerformance.API.Test/bin/Debug
+/NUIX.InvestmentPerformance.API.Test/appsettings.Development.json
+/NUIX.InvestmentPerformance.API.Test/appsettings.json
+/CodingExercise - Shortcut.lnk
diff --git a/NUIX.InvestmentPerformance.API.Test/InvestmentServiceTests.cs b/NUIX.InvestmentPerformance.API.Test/InvestmentServiceTests.cs
new file mode 100644
index 00000000..70fed772
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API.Test/InvestmentServiceTests.cs
@@ -0,0 +1,39 @@
+using Microsoft.EntityFrameworkCore;
+using Moq;
+using NUIX.InvestmentPerformance.API.Data;
+using NUIX.InvestmentPerformance.API.Models;
+using NUIX.InvestmentPerformance.API.Models.Enums;
+using NUIX.InvestmentPerformance.API.Services;
+
+namespace NUIX.InvestmentPerformance.API.Test
+{
+ public class InvestmentServiceTests
+ {
+
+ [TestCase( "11111111-1111-1111-1111-111111111111","CFD2EC55-EC50-4160-AADC-18DB56C2E608", "Alphabet Inc. (Google)")]
+ [Test]
+ public void GetInvestmentDetails_ShouldCalculateCorrectValues(string userID, string investmentID, string investmentName)
+ {
+ // Arrange
+ var investment = new Investment
+ {
+ InvestmentID = Guid.Parse(investmentID),
+ UserID = Guid.Parse(userID),
+ InvestmentName = investmentName,
+ NumberOfShares = 10,
+ CostBasisPerShare = 150m,
+ CurrentPricePerShare = 180m,
+ PurchaseDate = DateTime.Now.AddMonths(-18)
+ };
+ var service = new InvestmentService();
+
+ // Act
+ var result = service.CalculateInvestmentDetails(investment);
+
+ // Assert
+ Assert.AreEqual(1800m, result.CurrentValue);
+ Assert.AreEqual(InvestmentTerm.LongTerm, result.Term);
+ Assert.AreEqual(300m, result.TotalGainOrLoss);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NUIX.InvestmentPerformance.API.Test/NUIX.InvestmentPerformance.API.Test.csproj b/NUIX.InvestmentPerformance.API.Test/NUIX.InvestmentPerformance.API.Test.csproj
new file mode 100644
index 00000000..28a8782f
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API.Test/NUIX.InvestmentPerformance.API.Test.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NUIX.InvestmentPerformance.API.Test/Usings.cs b/NUIX.InvestmentPerformance.API.Test/Usings.cs
new file mode 100644
index 00000000..cefced49
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API.Test/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/DesignTimeBuild/.dtbcache.v2 b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/DesignTimeBuild/.dtbcache.v2
new file mode 100644
index 00000000..05b31f1f
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/DesignTimeBuild/.dtbcache.v2 differ
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/2135542b-8b5c-4fd7-944f-ce7775837f66.vsidx b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/2135542b-8b5c-4fd7-944f-ce7775837f66.vsidx
new file mode 100644
index 00000000..7b872d1a
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/2135542b-8b5c-4fd7-944f-ce7775837f66.vsidx differ
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/acf8e340-f998-4880-8e8c-5921cd4fe399.vsidx b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/acf8e340-f998-4880-8e8c-5921cd4fe399.vsidx
new file mode 100644
index 00000000..3ad84263
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/acf8e340-f998-4880-8e8c-5921cd4fe399.vsidx differ
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/afd75703-9adf-4753-b1ab-ef34bcf2a799.vsidx b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/afd75703-9adf-4753-b1ab-ef34bcf2a799.vsidx
new file mode 100644
index 00000000..39d2c0b5
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/afd75703-9adf-4753-b1ab-ef34bcf2a799.vsidx differ
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/b010e24f-e131-489b-8030-2c397b9af43e.vsidx b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/b010e24f-e131-489b-8030-2c397b9af43e.vsidx
new file mode 100644
index 00000000..0ffba567
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/b010e24f-e131-489b-8030-2c397b9af43e.vsidx differ
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/read.lock b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/FileContentIndex/read.lock
new file mode 100644
index 00000000..e69de29b
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/config/applicationhost.config b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/config/applicationhost.config
new file mode 100644
index 00000000..600d7584
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/config/applicationhost.config
@@ -0,0 +1,972 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/v17/.futdcache.v2 b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/v17/.futdcache.v2
new file mode 100644
index 00000000..dbe38d6b
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/v17/.futdcache.v2 differ
diff --git a/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/v17/.suo b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/v17/.suo
new file mode 100644
index 00000000..d444f689
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/NUIX.InvestmentPerformance.API/v17/.suo differ
diff --git a/NUIX.InvestmentPerformance.API/.vs/ProjectEvaluation/nuix.investmentperformance.api.metadata.v6.1 b/NUIX.InvestmentPerformance.API/.vs/ProjectEvaluation/nuix.investmentperformance.api.metadata.v6.1
new file mode 100644
index 00000000..baa6fed8
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/ProjectEvaluation/nuix.investmentperformance.api.metadata.v6.1 differ
diff --git a/NUIX.InvestmentPerformance.API/.vs/ProjectEvaluation/nuix.investmentperformance.api.projects.v6.1 b/NUIX.InvestmentPerformance.API/.vs/ProjectEvaluation/nuix.investmentperformance.api.projects.v6.1
new file mode 100644
index 00000000..4f48feaf
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/.vs/ProjectEvaluation/nuix.investmentperformance.api.projects.v6.1 differ
diff --git a/NUIX.InvestmentPerformance.API/Controllers/InvestmentsController.cs b/NUIX.InvestmentPerformance.API/Controllers/InvestmentsController.cs
new file mode 100644
index 00000000..b2ad3b19
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Controllers/InvestmentsController.cs
@@ -0,0 +1,51 @@
+using Microsoft.AspNetCore.Mvc;
+using NUIX.InvestmentPerformance.API.DataTransferObjects;
+using NUIX.InvestmentPerformance.API.Services;
+
+namespace NUIX.InvestmentPerformance.API.Controllers
+{
+ [ApiController]
+ [Route("api/investments")]
+ public class InvestmentsController : ControllerBase
+ {
+ private readonly IInvestmentService investmentService;
+
+ public InvestmentsController(IInvestmentService investmentService)
+ {
+ this.investmentService = investmentService;
+ }
+
+ [HttpGet]
+ [Route("api/investments/get-investments")]
+ public ActionResult> GetInvestments(Guid userInvestmentID)
+ {
+ var investments = investmentService.GetInvestmentsForUser(userInvestmentID);
+
+ if (investments == null || investments.Count() == 0)
+ return NotFound("Unable to retrieve data for userInvestmentID:" + userInvestmentID + ". Please try again using a valid userInvestmentID.");
+
+ return Ok(investments);
+ }
+
+ [HttpGet("api/investments/get-user-investments-details")]
+ public ActionResult GetUserInvestmentDetails(Guid userInvestmentID, Guid investmentId)
+ {
+ var details = investmentService.GetInvestmentDetails(userInvestmentID, investmentId);
+ if (details == null)
+ return NotFound($"Unable to retrieve Investment Details for userInvestmentID:{userInvestmentID} and investmentID:{investmentId}. Please try again using a valid userInvestmentID and investmentID.");
+
+ return Ok(details);
+ }
+
+ ///
+ /// Adding this incase the dev team wants to see the middleware
+ ///
+ ///
+ ///
+ //[HttpGet("throw")]
+ //public IActionResult ThrowException()
+ //{
+ // throw new Exception("This is a test exception");
+ //}
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/Data/InvestmentDbContext.cs b/NUIX.InvestmentPerformance.API/Data/InvestmentDbContext.cs
new file mode 100644
index 00000000..0d666e41
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Data/InvestmentDbContext.cs
@@ -0,0 +1,32 @@
+using NUIX.InvestmentPerformance.API.Models;
+using System.Collections.Generic;
+using System.Reflection.Emit;
+using Microsoft.EntityFrameworkCore;
+
+namespace NUIX.InvestmentPerformance.API.Data
+{
+ public class InvestmentDbContext : DbContext
+ {
+ public InvestmentDbContext()
+ {
+
+ }
+
+ public InvestmentDbContext(DbContextOptions options)
+ : base(options) { }
+
+ public DbSet Users => Set();
+ public DbSet Investments => Set();
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ // Relationships
+ modelBuilder.Entity()
+ .HasMany(u => u.UserInvestments)
+ .WithOne()
+ .HasForeignKey(i => i.InvestmentID);
+ }
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/DataTransferObjects/InvestmentDetailDTO.cs b/NUIX.InvestmentPerformance.API/DataTransferObjects/InvestmentDetailDTO.cs
new file mode 100644
index 00000000..30ad7511
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/DataTransferObjects/InvestmentDetailDTO.cs
@@ -0,0 +1,16 @@
+using NUIX.InvestmentPerformance.API.Models.Enums;
+
+namespace NUIX.InvestmentPerformance.API.DataTransferObjects
+{
+ public class InvestmentDetailDTO
+ {
+ public Guid InvestmentID { get; set; }
+ public string InvestmentName { get; set; }
+ public int NumberOfShares { get; set; }
+ public decimal CostBasisPerShare { get; set; }
+ public decimal CurrentPrice { get; set; }
+ public decimal CurrentValue { get; set; }
+ public InvestmentTerm Term { get; set; }
+ public decimal TotalGainOrLoss { get; set; }
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/DataTransferObjects/InvestmentSummaryDTO.cs b/NUIX.InvestmentPerformance.API/DataTransferObjects/InvestmentSummaryDTO.cs
new file mode 100644
index 00000000..95049d8c
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/DataTransferObjects/InvestmentSummaryDTO.cs
@@ -0,0 +1,8 @@
+namespace NUIX.InvestmentPerformance.API.DataTransferObjects
+{
+ public class InvestmentSummaryDTO
+ {
+ public Guid InvestmentID { get; set; }
+ public string InvestmentName { get; set; }
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/Database/Investment.bak b/NUIX.InvestmentPerformance.API/Database/Investment.bak
new file mode 100644
index 00000000..116d3a2f
Binary files /dev/null and b/NUIX.InvestmentPerformance.API/Database/Investment.bak differ
diff --git a/NUIX.InvestmentPerformance.API/Middleware/ExceptionMiddleware.cs b/NUIX.InvestmentPerformance.API/Middleware/ExceptionMiddleware.cs
new file mode 100644
index 00000000..ad53f689
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Middleware/ExceptionMiddleware.cs
@@ -0,0 +1,41 @@
+using System.Net;
+using System.Text.Json;
+
+namespace NUIX.InvestmentPerformance.API.Middleware
+{
+ public class ExceptionMiddleware
+ {
+ private readonly RequestDelegate _next;
+ private readonly ILogger _logger;
+
+ public ExceptionMiddleware(RequestDelegate next, ILogger logger)
+ {
+ _next = next;
+ _logger = logger;
+ }
+
+ public async Task InvokeAsync(HttpContext context)
+ {
+ try
+ {
+ await _next(context);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unhandled exception occurred.");
+
+ context.Response.ContentType = "application/json";
+ context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
+
+ var response = new
+ {
+ StatusCode = context.Response.StatusCode,
+ Message = "An unexpected error occurred. Please check logs for more information."
+ };
+
+ var json = JsonSerializer.Serialize(response);
+ await context.Response.WriteAsync(json);
+ }
+ }
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/Models/Enums/InvestmentTerm.cs b/NUIX.InvestmentPerformance.API/Models/Enums/InvestmentTerm.cs
new file mode 100644
index 00000000..8fe3b813
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Models/Enums/InvestmentTerm.cs
@@ -0,0 +1,15 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.Xml.Linq;
+
+namespace NUIX.InvestmentPerformance.API.Models.Enums
+{
+ public enum InvestmentTerm
+ {
+ [Display(Name = "Short Term")]
+ ShortTerm = 0,
+
+ [Display(Name = "Long Term")]
+ LongTerm = 1,
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/Models/Investment.cs b/NUIX.InvestmentPerformance.API/Models/Investment.cs
new file mode 100644
index 00000000..57d36a64
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Models/Investment.cs
@@ -0,0 +1,15 @@
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace NUIX.InvestmentPerformance.API.Models
+{
+ public class Investment
+ {
+ public Guid InvestmentID { get; set; }
+ public Guid UserID { get; set; }
+ public string InvestmentName { get; set; }
+ public int NumberOfShares { get; set; }
+ public decimal CostBasisPerShare { get; set; }
+ public decimal CurrentPricePerShare { get; set; }
+ public DateTime PurchaseDate { get; set; }
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/Models/UserInvestment.cs b/NUIX.InvestmentPerformance.API/Models/UserInvestment.cs
new file mode 100644
index 00000000..915540e0
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Models/UserInvestment.cs
@@ -0,0 +1,8 @@
+namespace NUIX.InvestmentPerformance.API.Models
+{
+ public class UserInvestment
+ {
+ public Guid UserInvestmentID { get; set; }
+ public List UserInvestments { get; set; }
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.csproj b/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.csproj
new file mode 100644
index 00000000..5ec50f21
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.csproj.user b/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.csproj.user
new file mode 100644
index 00000000..031db340
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.csproj.user
@@ -0,0 +1,8 @@
+
+
+
+ https
+ MvcControllerEmptyScaffolder
+ root/Common/MVC/Controller
+
+
\ No newline at end of file
diff --git a/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.sln b/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.sln
new file mode 100644
index 00000000..16c471d6
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/NUIX.InvestmentPerformance.API.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33627.172
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NUIX.InvestmentPerformance.API", "NUIX.InvestmentPerformance.API.csproj", "{7DB4EABC-11FF-48B9-BBE3-B61D33877F3C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NUIX.InvestmentPerformance.API.Test", "..\NUIX.InvestmentPerformance.API.Test\NUIX.InvestmentPerformance.API.Test.csproj", "{29811233-607A-4DB2-AC79-08B1953CB421}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7DB4EABC-11FF-48B9-BBE3-B61D33877F3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7DB4EABC-11FF-48B9-BBE3-B61D33877F3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7DB4EABC-11FF-48B9-BBE3-B61D33877F3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7DB4EABC-11FF-48B9-BBE3-B61D33877F3C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {29811233-607A-4DB2-AC79-08B1953CB421}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {29811233-607A-4DB2-AC79-08B1953CB421}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {29811233-607A-4DB2-AC79-08B1953CB421}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {29811233-607A-4DB2-AC79-08B1953CB421}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {11E0EFE7-B57C-490A-9CE0-4B0DA2CE4ADE}
+ EndGlobalSection
+EndGlobal
diff --git a/NUIX.InvestmentPerformance.API/Program.cs b/NUIX.InvestmentPerformance.API/Program.cs
new file mode 100644
index 00000000..4d386b1b
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Program.cs
@@ -0,0 +1,35 @@
+using NUIX.InvestmentPerformance.API.Data;
+using NUIX.InvestmentPerformance.API.Middleware;
+using NUIX.InvestmentPerformance.API.Services;
+using Microsoft.EntityFrameworkCore;
+
+
+var builder = WebApplication.CreateBuilder(args);
+// Add services to the container.
+builder.Services.AddControllers();
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
+
+// Register investment service for dependency injection
+builder.Services.AddScoped();
+
+builder.Services.AddDbContext(options =>
+ options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
+
+var app = builder.Build();
+
+// Enable middleware to serve Swagger
+if (app.Environment.IsDevelopment())
+{
+ app.UseSwagger();
+ app.UseSwaggerUI();
+
+}
+
+app.UseMiddleware();
+
+app.UseHttpsRedirection();
+app.UseAuthorization();
+app.MapControllers();
+
+app.Run();
diff --git a/NUIX.InvestmentPerformance.API/Properties/launchSettings.json b/NUIX.InvestmentPerformance.API/Properties/launchSettings.json
new file mode 100644
index 00000000..f022a94c
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Properties/launchSettings.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:2303",
+ "sslPort": 44353
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "http://localhost:5217",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "https://localhost:7257;http://localhost:5217",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/README.md b/NUIX.InvestmentPerformance.API/README.md
new file mode 100644
index 00000000..bdbe809b
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/README.md
@@ -0,0 +1,39 @@
+# 📊 Investment Performance API
+
+This is a production-based Web API built in **C# (.NET 8)** for an investment trading platform.
+It allows querying of a user's investments and detailed performance data for individual investments.
+
+## 🚀 Features
+
+- Get a list of investments for a user
+- Get detailed performance metrics of an individual investment
+- SQL Server integration with Entity Framework Core
+- Global exception handling middleware
+- Unit-tested business logic
+
+## ✅ Requirements
+
+- [.NET 8 SDK](https://dotnet.microsoft.com/en-us/download)
+- [SQL Server](https://www.microsoft.com/en-us/sql-server/sql-server-downloads)
+- [SQL Server Management Studio (SSMS)](https://learn.microsoft.com/en-us/ssms/download-sql-server-management-studio-ssms)
+
+## 🗃️ Database Setup
+
+- Open SSMS and restore the database using the .bak file located at: /Database/InvestmentDb.bak
+
+## 🔐 Configuration
+
+- Ensure your connection string in appsettings.json looks like this or something similar to this:
+
+```json
+"ConnectionStrings": {
+ "DefaultConnection": "Server=localhost;Database=InvestmentDb;Trusted_Connection=True;TrustServerCertificate=True;"
+}
+```
+
+⚙️ Scalability Considerations
+Here’s how I would scale this system if the opportunity presented itself:
+
+- Indexing: Ensure DB indexes on UserID, InvestmentID
+- Pagination & Filtering: Add skip/take parameters to endpoints
+- Command Query Responsibility Segregation (CQRS): Split read/write logic if write and read scale differently.
diff --git a/NUIX.InvestmentPerformance.API/Services/IInvestmentService.cs b/NUIX.InvestmentPerformance.API/Services/IInvestmentService.cs
new file mode 100644
index 00000000..ac3cc636
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Services/IInvestmentService.cs
@@ -0,0 +1,10 @@
+using NUIX.InvestmentPerformance.API.DataTransferObjects;
+
+namespace NUIX.InvestmentPerformance.API.Services
+{
+ public interface IInvestmentService
+ {
+ public List GetInvestmentsForUser(Guid userId);
+ public InvestmentDetailDTO? GetInvestmentDetails(Guid userId, Guid investmentId);
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/Services/InvestmentService.cs b/NUIX.InvestmentPerformance.API/Services/InvestmentService.cs
new file mode 100644
index 00000000..88f34add
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/Services/InvestmentService.cs
@@ -0,0 +1,68 @@
+using NUIX.InvestmentPerformance.API.Data;
+using NUIX.InvestmentPerformance.API.DataTransferObjects;
+using NUIX.InvestmentPerformance.API.Models;
+using NUIX.InvestmentPerformance.API.Models.Enums;
+using InvestmentDbContext = NUIX.InvestmentPerformance.API.Data.InvestmentDbContext;
+
+namespace NUIX.InvestmentPerformance.API.Services
+{
+ public class InvestmentService : IInvestmentService
+ {
+ private readonly InvestmentDbContext _context;
+
+ public InvestmentService()
+ {
+
+ }
+
+ public InvestmentService(InvestmentDbContext context)
+ {
+ _context = context;
+ }
+
+ public List GetInvestmentsForUser(Guid userId)
+ {
+ return _context.Investments
+ .Where(i => i.UserID == userId)
+ .Select(i => new InvestmentSummaryDTO
+ {
+ InvestmentID = i.InvestmentID,
+ InvestmentName = i.InvestmentName
+ })
+ .ToList();
+ }
+
+ public InvestmentDetailDTO? GetInvestmentDetails(Guid userId, Guid investmentId)
+ {
+ var investment = _context.Investments
+ .FirstOrDefault(i => i.InvestmentID == investmentId && i.UserID == userId);
+
+ if (investment == null)
+ return null;
+
+ return CalculateInvestmentDetails(investment);
+ }
+
+ public InvestmentDetailDTO CalculateInvestmentDetails(Investment investment)
+ {
+
+ var currentValue = investment.NumberOfShares * investment.CurrentPricePerShare;
+ var term = (DateTime.UtcNow - investment.PurchaseDate).TotalDays > 365 ? InvestmentTerm.LongTerm : InvestmentTerm.ShortTerm;
+ var totalCost = investment.NumberOfShares * investment.CostBasisPerShare;
+ var gainLoss = currentValue - totalCost;
+
+ return new InvestmentDetailDTO
+ {
+ InvestmentID = investment.InvestmentID,
+ InvestmentName = investment.InvestmentName,
+ NumberOfShares = investment.NumberOfShares,
+ CostBasisPerShare = investment.CostBasisPerShare,
+ CurrentPrice = investment.CurrentPricePerShare,
+ CurrentValue = currentValue,
+ Term = term,
+ TotalGainOrLoss = gainLoss
+ };
+ }
+ }
+
+}
diff --git a/NUIX.InvestmentPerformance.API/appsettings.Development.json b/NUIX.InvestmentPerformance.API/appsettings.Development.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/NUIX.InvestmentPerformance.API/appsettings.json b/NUIX.InvestmentPerformance.API/appsettings.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/NUIX.InvestmentPerformance.API/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}