feat(admin): 예전/최신 어드민 통합 — 실데이터 복원 + 인증 아키텍처 정리

예전 배포본(HEAD)의 상세 기능을 새 아키텍처(인증=.NET 백엔드, 데이터=Supabase)
위에 실데이터로 복원. 예전 HEAD는 서명 쿠키를 거부하고 위조 쿠키는 통과시키는
인증 결함이 있었고, 삭제된 페이지 다수는 백엔드 호출 0인 하드코딩 목업이었음.

인증/세션
- 로그인 이메일 전용화(username 폐지), 에러 키별 안내 메시지
- ADMIN_COOKIE_SECURE 옵션: TLS 없는 LAN HTTP 배포에서 Secure 쿠키 유실로
  로그인이 유지되지 않던 문제 해결 (login/logout route, admin-session, compose, .env.example)
- Supabase 미설정 시 우아한 저하: isSupabaseAdminConfigured + UnavailableAdminPanel

기능 복원 (실데이터)
- Release Hub: Forgejo API 실데이터(다운로드 수/SHA-256 체크섬/릴리스 이력)
- Ad Monetization: 데스크톱 미디에이션 10개 어댑터 로스터(fail-closed) + ad_reward_claims 통계
- License Issuer: 서버사이드 Ed25519 서명(/api/admin/license, super_admin 전용),
  개인키는 ADMIN_LICENSE_PRIVATE_KEY env로만, 발급 감사를 .NET AdminAuditEntries에 기록
- Service Models: STT 7종/LLM 5종 프리셋 드롭다운 + 자동채움
- 대시보드 ARR/MRR KPI: Supabase 구독 실집계(티어 월단가 기반)
- 사용자 상세 티어별 기능 배지(pro_plus 조건부)

.NET
- SuperAdminOnly 정책 추가, /api/admin/license-audit 엔드포인트, LicenseAuditDto
This commit is contained in:
Yun Chan 2026-08-23 23:38:08 +09:00
parent a9c9a1ca6e
commit 5a34f66981
66 changed files with 4471 additions and 3501 deletions

View file

@ -9,6 +9,14 @@ public record LoginDto(string Email, string Password);
public record AuthResponseDto(string Token, string Email, string Role, DateTime ExpiresAt);
public record UserInfoDto(int Id, string Email, string Role, DateTime CreatedAt, DateTime? LastLoginAt, bool IsActive);
// License issuance audit trail (offline Ed25519 license keys issued from the admin console)
public record LicenseAuditDto(
string LicenseId,
string CustomerEmail,
string Tier,
string Validity,
long? ExpiresAt);
// LLM DTOs
public record LlmGenerateRequest(string Prompt, string? Model = null, string? SystemPrompt = null, double Temperature = 0.7, int MaxTokens = 2048);
public record LlmGenerateResponse(string Text, string Model, int PromptTokens, int CompletionTokens, double TotalDurationMs, decimal Cost);
@ -23,7 +31,8 @@ public record CreateModelEndpointDto(
string EndpointUrl,
string ApiKey,
decimal CostPer1kPromptTokens,
decimal CostPer1kCompletionTokens
decimal CostPer1kCompletionTokens,
string? Memo = null
);
public record UpdateModelEndpointDto(
@ -33,7 +42,8 @@ public record UpdateModelEndpointDto(
string ApiKey,
decimal CostPer1kPromptTokens,
decimal CostPer1kCompletionTokens,
bool IsActive
bool IsActive,
string? Memo = null
);
public record ServerStatsDto(
@ -117,7 +127,8 @@ public record CreateSttEndpointDto(
bool IsDefault,
bool IsActive,
int FallbackPriority,
string? ExtraHeadersJson
string? ExtraHeadersJson,
string? Memo = null
);
public record UpdateSttEndpointDto(
@ -135,9 +146,12 @@ public record UpdateSttEndpointDto(
bool IsDefault,
bool IsActive,
int FallbackPriority,
string? ExtraHeadersJson
string? ExtraHeadersJson,
string? Memo = null
);
public record AdminActionDto(string? Memo);
public record SttTestResultDto(
bool Success,
string Message,
@ -147,6 +161,8 @@ public record SttTestResultDto(
string? ModelId
);
public record DirectSttTestDto(string EndpointUrl, string? ApiKey);
public record SttUsageReportDto(
int TotalTranscriptions,
double TotalAudioMinutes,
@ -172,4 +188,3 @@ public record SttUserUsageSummaryDto(
double TotalAudioMinutes,
decimal TotalCost
);