refactor: move buildable .NET source into src/, update CI/doc paths
TaxBaik CI/CD / build-and-deploy (push) Successful in 2m7s
TaxBaik CI/CD / build-and-deploy (push) Successful in 2m7s
Groups the repo root into src (buildable source), docs (already existed), and everything else (db/, scripts/, tests/, deploy/ - deployment/ops/test assets that aren't compiled, already organized as their own folders). CI now only needs src/ to build: dotnet restore/build/test/publish all point at src/TaxBaik.sln, src/TaxBaik.Web/, src/TaxBaik.Proxy/. - git mv every project (Domain, Infrastructure, Application, Application.Tests, Web, Web.Client, Proxy) and TaxBaik.sln into src/ as a unit, so relative ProjectReference/.sln paths stay valid unchanged. - .gitea/workflows/deploy.yml: 6 dotnet restore/clean/build/test/publish invocations now point at src/. db/migrations and scripts/ stay at root (deploy_gb.sh and browser-e2e.yml only touch published output and the deployed URL, not source paths - verified, no changes needed there). - scripts/validate_admin_render.sh: admin render-mode file paths now src/TaxBaik.Web.Client/... - scripts/validate_kst_timestamps.sh: dropped deploy.sh from its target list - that script was removed in the prior cleanup commit (dead, no CI workflow referenced it) but this validator still expected it to exist. - CLAUDE.md, docs/ENGINEERING_HARNESS.md, docs/ADMIN_PATTERN_CRITIQUE_WBS.md: updated project-structure diagram, dotnet run/build commands, and grep targets to the new src/ paths (also fixed a pre-existing stale path in ADMIN_PATTERN_CRITIQUE_WBS.md that still said TaxBaik.Web/Components/Admin from before that ever moved to TaxBaik.Web.Client). - Added a Repo Root harness rule + Architecture Guardrail entries: new files belong under src/docs/tests/scripts/db/deploy, not loose at root; temp work stays outside the repo (or under a gitignored .scratch/) and is never committed. Verified locally: dotnet build/test src/TaxBaik.sln (26/26 tests), and all three scripts/validate_*.sh pass against the new layout. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,93 +0,0 @@
|
||||
namespace TaxBaik.Web.Services;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using TaxBaik.Application.Services;
|
||||
|
||||
public class TelegramReportBackgroundService(
|
||||
IServiceScopeFactory scopeFactory,
|
||||
ILogger<TelegramReportBackgroundService> logger) : BackgroundService
|
||||
{
|
||||
private static readonly TimeZoneInfo KoreaTimeZone = GetKoreaTimeZone();
|
||||
private DateOnly? _lastDailyReportDate;
|
||||
private DateOnly? _lastWeeklyReportWeekStart;
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(30));
|
||||
|
||||
try
|
||||
{
|
||||
while (await timer.WaitForNextTickAsync(stoppingToken))
|
||||
{
|
||||
try
|
||||
{
|
||||
var now = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, KoreaTimeZone);
|
||||
await TrySendReportsAsync(now, stoppingToken);
|
||||
}
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Telegram report background loop failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
// Normal shutdown path.
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TrySendReportsAsync(DateTimeOffset nowKst, CancellationToken ct)
|
||||
{
|
||||
if (nowKst.Hour is 9 or 10)
|
||||
await SendDailyIfNeededAsync(DateOnly.FromDateTime(nowKst.DateTime), ct);
|
||||
|
||||
if (nowKst.DayOfWeek == DayOfWeek.Monday && nowKst.Hour is 9 or 10)
|
||||
await SendWeeklyIfNeededAsync(DateOnly.FromDateTime(nowKst.DateTime).AddDays(-7), ct);
|
||||
}
|
||||
|
||||
private async Task SendDailyIfNeededAsync(DateOnly date, CancellationToken ct)
|
||||
{
|
||||
if (_lastDailyReportDate == date)
|
||||
return;
|
||||
|
||||
using var scope = scopeFactory.CreateScope();
|
||||
var reportService = scope.ServiceProvider.GetRequiredService<TelegramReportService>();
|
||||
var telegram = scope.ServiceProvider.GetRequiredService<ITelegramNotificationService>();
|
||||
|
||||
var report = await reportService.BuildDailyReportAsync(date, ct);
|
||||
await telegram.SendReportAsync("일간 세무/상담 현황 리포트", TelegramReportService.FormatDailyMessage(report), ct);
|
||||
_lastDailyReportDate = date;
|
||||
logger.LogInformation("Daily telegram report sent for {Date}", date);
|
||||
}
|
||||
|
||||
private async Task SendWeeklyIfNeededAsync(DateOnly weekStart, CancellationToken ct)
|
||||
{
|
||||
if (_lastWeeklyReportWeekStart == weekStart)
|
||||
return;
|
||||
|
||||
using var scope = scopeFactory.CreateScope();
|
||||
var reportService = scope.ServiceProvider.GetRequiredService<TelegramReportService>();
|
||||
var telegram = scope.ServiceProvider.GetRequiredService<ITelegramNotificationService>();
|
||||
|
||||
var report = await reportService.BuildWeeklyReportAsync(weekStart, ct);
|
||||
await telegram.SendReportAsync("주간 세무/매출 종합 리포트", TelegramReportService.FormatWeeklyMessage(report), ct);
|
||||
_lastWeeklyReportWeekStart = weekStart;
|
||||
logger.LogInformation("Weekly telegram report sent for {WeekStart}", weekStart);
|
||||
}
|
||||
|
||||
private static TimeZoneInfo GetKoreaTimeZone()
|
||||
{
|
||||
try
|
||||
{
|
||||
return TimeZoneInfo.FindSystemTimeZoneById("Korea Standard Time");
|
||||
}
|
||||
catch (TimeZoneNotFoundException)
|
||||
{
|
||||
return TimeZoneInfo.FindSystemTimeZoneById("Asia/Seoul");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user