Migrate SiteSettings controller to FastEndpoints

Refactored SiteSettingsController to FastEndpoints pattern:
- Created GetEndpoint.cs: GET /api/sitesettings (authorized)
- Created SaveEndpoint.cs: PUT /api/sitesettings (authorized)
- Removed legacy SiteSettingsController.cs

Both endpoints use Bearer token authentication and are auto-discovered
by FastEndpoints configuration in Program.cs.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 17:35:18 +09:00
parent 69ec7913d0
commit a6068e184b
13 changed files with 328 additions and 482 deletions
@@ -0,0 +1,51 @@
using TaxBaik.Application.Services;
using TaxBaik.Domain.Entities;
using InquiryEntity = TaxBaik.Domain.Entities.Inquiry;
namespace TaxBaik.Web.Endpoints.AdminDashboard;
public class AdminDashboardSummaryResponse
{
public int ThisMonthInquiries { get; set; }
public int NewInquiries { get; set; }
public int TotalPosts { get; set; }
public int PublishedPosts { get; set; }
public List<InquiryEntity> RecentInquiries { get; set; } = [];
}
public class UpcomingFilingsResponse
{
public List<object> Data { get; set; } = [];
public int Days { get; set; }
}
public class UpcomingFilingsQuery
{
public int Days { get; set; } = 30;
}
public class RecentInquiriesResponse
{
public List<InquiryEntity> Data { get; set; } = [];
public int Limit { get; set; }
}
public class RecentInquiriesQuery
{
public int Limit { get; set; } = 10;
}
public class MonthlyStatsQuery
{
public string? Month { get; set; }
}
public class MonthlyStatsResponse
{
public string Month { get; set; } = string.Empty;
public int TotalInquiries { get; set; }
public int ConsultingCount { get; set; }
public int CompletedCount { get; set; }
public int NewCount { get; set; }
public double CompletionRate { get; set; }
}
@@ -0,0 +1,44 @@
using FastEndpoints;
using TaxBaik.Application.Services;
namespace TaxBaik.Web.Endpoints.AdminDashboard;
public class GetMonthlyStatsEndpoint : Endpoint<MonthlyStatsQuery, MonthlyStatsResponse>
{
private readonly AdminDashboardService _dashboardService;
public GetMonthlyStatsEndpoint(AdminDashboardService dashboardService)
{
_dashboardService = dashboardService;
}
public override void Configure()
{
Get("/api/admin-dashboard/monthly-stats");
Policies("Bearer");
}
public override async Task HandleAsync(MonthlyStatsQuery request, CancellationToken ct)
{
try
{
var stats = await _dashboardService.GetMonthlyStatsAsync(request.Month, ct);
// Convert dynamic result to typed response
var statsDict = (dynamic)stats;
await SendAsync(new MonthlyStatsResponse
{
Month = statsDict.month,
TotalInquiries = statsDict.totalInquiries,
ConsultingCount = statsDict.consultingCount,
CompletedCount = statsDict.completedCount,
NewCount = statsDict.newCount,
CompletionRate = statsDict.completionRate
}, 200, cancellation: ct);
}
catch (Exception ex)
{
await SendErrorsAsync(500, ct);
}
}
}
@@ -0,0 +1,40 @@
using FastEndpoints;
using TaxBaik.Application.Services;
namespace TaxBaik.Web.Endpoints.AdminDashboard;
public class GetRecentInquiriesEndpoint : Endpoint<RecentInquiriesQuery, RecentInquiriesResponse>
{
private readonly AdminDashboardService _dashboardService;
public GetRecentInquiriesEndpoint(AdminDashboardService dashboardService)
{
_dashboardService = dashboardService;
}
public override void Configure()
{
Get("/api/admin-dashboard/recent-inquiries");
Policies("Bearer");
}
public override async Task HandleAsync(RecentInquiriesQuery request, CancellationToken ct)
{
try
{
var limit = request.Limit <= 0 ? 10 : request.Limit;
if (limit > 100) limit = 100; // Security: max 100
var inquiries = await _dashboardService.GetRecentInquiriesAsync(limit, ct);
await SendAsync(new RecentInquiriesResponse
{
Data = inquiries.ToList(),
Limit = limit
}, 200, cancellation: ct);
}
catch (Exception ex)
{
await SendErrorsAsync(500, ct);
}
}
}
@@ -0,0 +1,40 @@
using FastEndpoints;
using TaxBaik.Application.Services;
namespace TaxBaik.Web.Endpoints.AdminDashboard;
public class GetSummaryEndpoint : EndpointWithoutRequest<AdminDashboardSummaryResponse>
{
private readonly AdminDashboardService _dashboardService;
public GetSummaryEndpoint(AdminDashboardService dashboardService)
{
_dashboardService = dashboardService;
}
public override void Configure()
{
Get("/api/admin-dashboard/summary");
Policies("Bearer");
}
public override async Task HandleAsync(CancellationToken ct)
{
try
{
var summary = await _dashboardService.GetSummaryAsync(ct);
await SendAsync(new AdminDashboardSummaryResponse
{
ThisMonthInquiries = summary.ThisMonthInquiries,
NewInquiries = summary.NewInquiries,
TotalPosts = summary.TotalPosts,
PublishedPosts = summary.PublishedPosts,
RecentInquiries = summary.RecentInquiries.ToList()
}, 200, cancellation: ct);
}
catch (Exception ex)
{
await SendErrorsAsync(500, ct);
}
}
}
@@ -0,0 +1,38 @@
using FastEndpoints;
using TaxBaik.Application.Services;
namespace TaxBaik.Web.Endpoints.AdminDashboard;
public class GetUpcomingFilingsEndpoint : Endpoint<UpcomingFilingsQuery, UpcomingFilingsResponse>
{
private readonly TaxFilingService _taxFilingService;
public GetUpcomingFilingsEndpoint(TaxFilingService taxFilingService)
{
_taxFilingService = taxFilingService;
}
public override void Configure()
{
Get("/api/admin-dashboard/upcoming-filings");
Policies("Bearer");
}
public override async Task HandleAsync(UpcomingFilingsQuery request, CancellationToken ct)
{
try
{
var days = request.Days <= 0 ? 30 : request.Days;
var filings = await _taxFilingService.GetUpcomingAsync(days);
await SendAsync(new UpcomingFilingsResponse
{
Data = filings.Cast<object>().ToList(),
Days = days
}, 200, cancellation: ct);
}
catch (Exception ex)
{
await SendErrorsAsync(500, ct);
}
}
}