namespace Domain.Entities.Common;
public sealed class Config
{
public int ID { get; private set; }
public DateTime LastUpdatedAt { get; private set; } = DateTime.UtcNow;
public byte[] RowVersion { get; private set; } = [];
public BasicConfig Basic { get; private set; } = new();
public ImagesConfig Images { get; private set; } = new();
public MetaConfig Meta { get; private set; } = new();
public CompanyConfig Company { get; private set; } = new();
public AccountConfig Account { get; private set; } = new();
public EmailTemplateConfig EmailTemplate { get; private set; } = new();
public ExternalApiConfig External { get; private set; } = new();
public CryptoConfig Crypto { get; private set; } = new();
public AttendanceConfig Attendance { get; private set; } = new();
public SignupRewardConfig SignupReward { get; private set; } = new();
public ActivityTokenConfig ActivityToken { get; private set; } = new();
public ChatExpConfig ChatExp { get; private set; } = new();
public PaperConfig Paper { get; private set; } = new();
private Config() { }
public static Config Create()
{
return new();
}
public void Update(
BasicConfig basic,
ImagesConfig images,
MetaConfig meta,
CompanyConfig company,
AccountConfig account,
EmailTemplateConfig emailTemplate,
ExternalApiConfig external,
CryptoConfig crypto,
AttendanceConfig attendance,
SignupRewardConfig signupReward
) {
Basic = basic ?? throw new ArgumentNullException(nameof(basic));
Images = images ?? throw new ArgumentNullException(nameof(images));
Meta = meta ?? throw new ArgumentNullException(nameof(meta));
Company = company ?? throw new ArgumentNullException(nameof(company));
Account = account ?? throw new ArgumentNullException(nameof(account));
EmailTemplate = emailTemplate ?? throw new ArgumentNullException(nameof(emailTemplate));
External = external ?? throw new ArgumentNullException(nameof(external));
Crypto = crypto ?? throw new ArgumentNullException(nameof(crypto));
Attendance = attendance ?? throw new ArgumentNullException(nameof(attendance));
SignupReward = signupReward ?? throw new ArgumentNullException(nameof(signupReward));
LastUpdatedAt = DateTime.UtcNow;
}
public void UpdateChatExp(ChatExpConfig chatExp)
{
ChatExp = chatExp ?? throw new ArgumentNullException(nameof(chatExp));
LastUpdatedAt = DateTime.UtcNow;
}
public void UpdateActivityToken(ActivityTokenConfig activityToken)
{
ActivityToken = activityToken ?? throw new ArgumentNullException(nameof(activityToken));
LastUpdatedAt = DateTime.UtcNow;
}
public void UpdatePaper(PaperConfig paper)
{
Paper = paper ?? throw new ArgumentNullException(nameof(paper));
LastUpdatedAt = DateTime.UtcNow;
}
}
#region Owned Groups
// ==================================================
// 기본 정보 (Basic)
// ==================================================
public sealed class BasicConfig
{
public string? SiteName { get; set; }
public string? SiteURL { get; set; }
public string? RootID { get; set; }
public string? FromEmail { get; set; }
public string? FromName { get; set; }
public string? SmtpServer { get; set; }
public int? SmtpPort { get; set; }
public bool SmtpEnableSSL { get; set; }
public string? SmtpUsername { get; set; }
public string? SmtpPassword { get; set; }
public string? AdminWhiteIPList { get; set; }
public string? FrontWhiteIPList { get; set; }
public string? BlockAlertTitle { get; set; }
public string? BlockAlertContent { get; set; }
public bool IsMaintenance { get; set; } = false;
public string? MaintenanceContent { get; set; }
/// 쪽지 일일 발송 제한 (사용자 1인당 / 시스템 쪽지 제외). 0 = 발송 차단
public int NoteDailySendLimit { get; set; } = 3;
}
// ==================================================
// 기본 이미지 (Images)
// ==================================================
public sealed class ImagesConfig
{
public string? Favicon { get; set; }
public string? LogoSquare { get; set; }
public string? LogoHorizontal { get; set; }
public string? OgDefault { get; set; }
public string? TwitterImage { get; set; }
public string? AppleTouchIcon { get; set; }
public string? AppIcon_192 { get; set; }
public string? AppIcon_512 { get; set; }
}
// ==================================================
// 메타 태그 (Meta)
// ==================================================
public sealed class MetaConfig
{
public string? Keywords { get; set; }
public string? Description { get; set; }
public string? Author { get; set; }
public string? Viewport { get; set; }
public string? ApplicationName { get; set; }
public string? Generator { get; set; }
public string? Robots { get; set; }
public string? Adds { get; set; }
}
// ==================================================
// 회사 정보 (Company)
// ==================================================
public sealed class CompanyConfig
{
public string? Name { get; set; }
public string? RegNo { get; set; }
public string? Address { get; set; }
public string? ZipCode { get; set; }
public string? Owner { get; set; }
public string? Tel { get; set; }
public string? Fax { get; set; }
public string? RetailSaleNo { get; set; }
public string? AddedSaleNo { get; set; }
public string? Hosting { get; set; }
public string? AdminName { get; set; }
public string? AdminEmail { get; set; }
public string? SiteUrl { get; set; }
public string? BankCode { get; set; }
public string? BankOwner { get; set; }
public string? BankNumber { get; set; }
}
// ==================================================
// 회원가입 설정 (Account)
// ==================================================
public sealed class AccountConfig
{
// 회원 가입 시
public bool IsRegisterBlock { get; set; } = false;
public bool IsRegisterEmailAuth { get; set; } = false;
public ushort? PasswordMinLength { get; set; }
public ushort? PasswordUppercaseLength { get; set; }
public ushort? PasswordNumbersLength { get; set; }
public ushort? PasswordSpecialcharsLength { get; set; }
public string? DeniedEmailList { get; set; }
public string? DeniedNameList { get; set; }
// 회원 수정 시 — 프로필(닉네임·한마디·이미지) 기본 90일 쿨다운 (변경권 아이템으로 우회 — Wave 3 P3)
public ushort? ChangeEmailDay { get; set; }
public ushort? ChangeNameDay { get; set; } = 90;
public ushort? ChangeSummaryDay { get; set; }
public ushort? ChangeIntroDay { get; set; } = 90;
public ushort? ChangeThumbDay { get; set; } = 90;
public ushort? ChangePasswordDay { get; set; }
// 로그인 시
public bool IsLoginEmailVerifiedOnly { get; set; } = false;
public ushort? MaxLoginTryCount { get; set; }
public ushort? MaxLoginTryLimitSecond { get; set; }
}
// ==================================================
// 알림 발송 양식 - 이메일 (EmailTemplate)
// ==================================================
public sealed class EmailTemplateConfig
{
public string? RegisterEmailFormTitle { get; set; }
public string? RegisterEmailFormContent { get; set; }
public string? RegistrationEmailFormTitle { get; set; }
public string? RegistrationEmailFormContent { get; set; }
public string? ResetPasswordEmailFormTitle { get; set; }
public string? ResetPasswordEmailFormContent { get; set; }
public string? ChangedPasswordEmailFormTitle { get; set; }
public string? ChangedPasswordEmailFormContent { get; set; }
public string? WithdrawEmailFormTitle { get; set; }
public string? WithdrawEmailFormContent { get; set; }
public string? WithdrawVerifyEmailFormTitle { get; set; }
public string? WithdrawVerifyEmailFormContent { get; set; }
public string? EmailVerifyFormTitle { get; set; }
public string? EmailVerifyFormContent { get; set; }
public string? ChangedEmailFormTitle { get; set; }
public string? ChangedEmailFormContent { get; set; }
}
// ==================================================
// 외부 API 설정 (External)
// ==================================================
public sealed class ExternalApiConfig
{
/** YouTube **/
public string? YouTubeApiKeyEnc { get; set; }
public string? YouTubeApiName { get; set; }
/** 구글 **/
public string? GoogleClientId { get; set; }
public string? GoogleClientSecretEnc { get; set; }
public string? GoogleAppId { get; set; }
/** 토스페이먼츠 **/
/// Toss 결제 환경 (test / live)
public string? TossPayMode { get; set; }
/// Toss Test Client Key (암호화 저장 권장)
public string? TossTestClientKeyEnc { get; set; }
/// Toss Test Secret Key (암호화 저장 권장)
public string? TossTestSecretKeyEnc { get; set; }
/// Toss Live Client Key (암호화 저장 권장)
public string? TossLiveClientKeyEnc { get; set; }
/// Toss Live Secret Key (암호화 저장 권장)
public string? TossLiveSecretKeyEnc { get; set; }
}
// ==================================================
// 코인/시세 설정 (Crypto)
// ==================================================
public sealed class CryptoConfig
{
public int TickerRefreshSeconds { get; set; } = 5;
public decimal SurgeThreshold { get; set; } = 5.0m;
public decimal PlungeThreshold { get; set; } = -5.0m;
public int MainPageCoinCount { get; set; } = 10;
}
// ==================================================
// 채팅 경험치/리더보드 설정 (ChatExp)
// 관리자: /Channel/Exp 페이지에서 편집
// ==================================================
public sealed class ChatExpConfig
{
/// 채팅 1건당 지급 XP
public int ChatXpPerMessage { get; set; } = 1;
/// 후원 N POINT당 1 XP (기본 1000 = 1,000원당 1XP)
public int DonationXpPerAmount { get; set; } = 1000;
/// 방송 세션당 채팅 XP 상한 (후원 XP는 무제한)
public int ChatXpSessionLimit { get; set; } = 50;
/// XP 적립 최소 글자수
public int MinContentLength { get; set; } = 2;
/// 채팅 쿨다운(초) — 기존 RateLimit 재정의
public int RateLimitSec { get; set; } = 2;
/// 리더보드 표시 인원 (Top N)
public int LeaderboardSize { get; set; } = 50;
/// 크라운 뱃지 부여 Top N
public int CrownTopN { get; set; } = 3;
/// watch 페이지에서 리더보드 기능 노출
public bool UxShowLeaderboard { get; set; } = true;
/// watch 페이지 채팅창 상단에 "내 XP" 뱃지 노출
public bool UxShowMyXpBadge { get; set; } = true;
}
// ==================================================
// 출석 설정 (Attendance)
// ==================================================
public sealed class AttendanceConfig
{
/// 출석 기능 활성화
public bool IsEnabled { get; set; } = false;
/// 기본 경험치
public int BaseExp { get; set; } = 0;
/// 기본 포인트
public int BasePoint { get; set; } = 0;
/// 연속 출석 가중치 사용
public bool UseStreakBonus { get; set; } = false;
/// 연속 출석 1일당 추가 경험치
public int StreakBonusPerDay { get; set; } = 0;
/// 연속 출석 1일당 추가 포인트
public int StreakBonusPointPerDay { get; set; } = 0;
/// 가중치 최대 적용 일수
public int StreakBonusMaxDays { get; set; } = 0;
/// 순위 보상 사용
public bool UseRankBonus { get; set; } = false;
/// 순위별 보상 설정 (JSON) [{"rank":1,"exp":100,"point":50},...]
public string? RankBonusConfig { get; set; }
}
// ==================================================
// 가입 축하 보상 설정 (SignupReward)
// 신규 회원 최초 가입 시 1회 지급. 멱등: WalletTransaction RefID "signup:{memberID}"
// ==================================================
public sealed class SignupRewardConfig
{
/// 가입 축하 보상 활성화
public bool Enabled { get; set; } = false;
/// 지급 코인(무상, Airdrop 파티션)
public int CoinAmount { get; set; } = 0;
/// 지급 캐시(유상 취급, Adjusted 파티션). 기본 0
public int CashAmount { get; set; } = 0;
/// 지급 경험치(XP)
public int ExpAmount { get; set; } = 0;
}
// ==================================================
// 활동 토큰 보상 설정 (ActivityToken) — d4 M0
// 게시글/댓글 작성 시 작성자에게 토큰(Reward 파티션) 적립. 멱등: refID "activity-post:{postID}" / "activity-comment:{commentID}"
// ==================================================
public sealed class ActivityTokenConfig
{
/// 게시글 1건 작성 시 지급 토큰 (0 = 미지급)
public int PostToken { get; set; } = 0;
/// 댓글 1건 작성 시 지급 토큰 (0 = 미지급)
public int CommentToken { get; set; } = 0;
/// 활동 토큰 일일 지급 상한 (0 = 무제한)
public int DailyTokenCap { get; set; } = 0;
}
// ==================================================
// 모의투자 설정 (Paper) — Admin /Config, d4 §④
// ==================================================
public sealed class PaperConfig
{
/// 모의투자 노출/주문 토글
public bool Enabled { get; set; } = true;
/// 매매 수수료 Bp (기본 15 = 0.15%; 토큰 sink)
public int FeeRateBp { get; set; } = 15;
/// 매도 거래세 Bp (기본 18; 토큰 sink)
public int TaxRateBp { get; set; } = 18;
/// 최소 입금 토큰
public int MinDeposit { get; set; } = 10000;
/// 계좌 최대 보유 토큰 (0 = 무제한)
public int MaxHolding { get; set; } = 0;
/// 출금 시 수익분 소각 Bp (0 = 꺼둠, 인플레 밸브)
public int WithdrawProfitBurnBp { get; set; } = 0;
/// 1주문 상한 Bp (기본 3000 = Equity 30%)
public int OrderMaxPctBp { get; set; } = 3000;
/// 리더보드 등재 최소 체결 수
public int MinFillsForRank { get; set; } = 3;
}
#endregion