Init repo

This commit is contained in:
Stedoss
2026-07-27 19:21:52 +01:00
commit bb6a1159ec
60 changed files with 8277 additions and 0 deletions
@@ -0,0 +1,26 @@
using MissionControl.Domain.Entities;
namespace MissionControl.Server.Endpoints.Missions;
public record MissionResponse
{
public required Guid Id { get; init; }
public required string Name { get; init; }
public string? Description { get; init; }
public required MissionStatus Status { get; init; }
public required DateTimeOffset CreatedAt { get; init; }
public static MissionResponse FromDomain(Mission mission) =>
new()
{
Id = mission.Id,
Name = mission.Name,
Description = mission.Description,
Status = mission.Status,
CreatedAt = mission.CreatedAt,
};
}
@@ -0,0 +1,41 @@
using FastEndpoints;
using FluentValidation;
using MissionControl.Data;
using MissionControl.Domain.Entities;
namespace MissionControl.Server.Endpoints.Missions;
public class CreateMission(MissionControlContext dbContext)
: Endpoint<CreateMissionRequest, MissionResponse>
{
public override void Configure()
{
Post("/missions");
}
public override async Task HandleAsync(CreateMissionRequest req, CancellationToken ct)
{
var mission = new Mission { Name = req.Name, Description = req.Description };
dbContext.Missions.Add(mission);
await dbContext.SaveChangesAsync(ct);
await Send.OkAsync(MissionResponse.FromDomain(mission), ct);
}
}
public record CreateMissionRequest
{
public required string Name { get; init; }
public string? Description { get; init; }
}
public class CreateMissionRequestValidator : Validator<CreateMissionRequest>
{
public CreateMissionRequestValidator()
{
RuleFor(r => r.Name).NotEmpty().MaximumLength(100);
RuleFor(r => r.Description).MaximumLength(500);
}
}
@@ -0,0 +1,34 @@
using FastEndpoints;
using Microsoft.EntityFrameworkCore;
using MissionControl.Data;
namespace MissionControl.Server.Endpoints.Missions;
public class ListMissions(MissionControlContext dbContext)
: EndpointWithoutRequest<ListMissionsResponse>
{
public override void Configure()
{
Get("/missions");
}
public override async Task HandleAsync(CancellationToken ct)
{
var missions = await dbContext
.Missions.AsNoTracking()
.OrderByDescending(m => m.CreatedAt)
.ToListAsync(ct);
var response = new ListMissionsResponse
{
Missions = missions.Select(MissionResponse.FromDomain).ToList(),
};
await Send.OkAsync(response, ct);
}
}
public record ListMissionsResponse
{
public required IReadOnlyList<MissionResponse> Missions { get; init; }
}
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<SpaRoot>..\mission-control-client</SpaRoot>
<SpaProxyLaunchCommand>npm run dev</SpaProxyLaunchCommand>
<SpaProxyServerUrl>http://localhost:5173</SpaProxyServerUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FastEndpoints" Version="8.2.0" />
<PackageReference Include="FastEndpoints.Swagger" Version="8.2.0" />
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="10.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.10">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MissionControl.Domain\MissionControl.Domain.csproj" />
<ProjectReference Include="..\MissionControl.Data\MissionControl.Data.csproj" />
<ProjectReference Include="..\mission-control-client\mission-control-client.esproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
</Project>
+34
View File
@@ -0,0 +1,34 @@
using System.Text.Json.Serialization;
using FastEndpoints;
using FastEndpoints.Swagger;
using MissionControl.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMissionControlData(
builder.Configuration.GetConnectionString("MissionControl")
?? throw new InvalidOperationException("Missing connection string 'MissionControl'")
);
builder.Services.AddFastEndpoints();
builder.Services.SwaggerDocument(options => options.ShortSchemaNames = true);
var app = builder.Build();
app.UseDefaultExceptionHandler(useGenericReason: !app.Environment.IsDevelopment());
app.UseFastEndpoints(config =>
{
config.Endpoints.RoutePrefix = "api";
config.Endpoints.ShortNames = true;
// The exercise ships without authentication, so every endpoint is anonymous.
config.Endpoints.Configurator = endpoint => endpoint.AllowAnonymous();
config.Serializer.Options.Converters.Add(new JsonStringEnumConverter());
});
if (app.Environment.IsDevelopment())
{
app.UseSwaggerGen();
await DevelopmentDatabase.MigrateAndSeedAsync(app.Services);
}
app.Run();
@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"MissionControl.Server": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5010",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
}
}
}
}
@@ -0,0 +1,5 @@
{
"ConnectionStrings": {
"MissionControl": "Server=localhost,1433;Database=MissionControl;User Id=sa;Password=MissionControl!23;TrustServerCertificate=True"
}
}
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore.Database.Command": "Warning"
}
},
"AllowedHosts": "*"
}