using Application.Abstractions.Data; using Domain.Entities.Forum.ValueObject; using Microsoft.EntityFrameworkCore; using BoardEntity = Domain.Entities.Forum.Boards.Board; using BoardGroupEntity = Domain.Entities.Forum.Boards.BoardGroup; using BoardMetaEntity = Domain.Entities.Forum.Boards.BoardMeta; namespace Application.Helpers; /// /// 물리 게시판 lazy 시드 (d2 §③ M3) — 코드별 물리 Board 행이 없으면 BoardGroup+Board+BoardMeta 를 생성하고 Board.ID 를 반환한다. /// 종목 가상보드(CreatePost 의 ResolveStockBoardID)와 동일한 패턴이며, 수익인증(proof)/장전브리핑(briefing) 처럼 /// 물리 보드가 필요한 곳에서 재사용한다. 마이그레이션 데이터 시드 대신 최초 사용 시점 provisioning 을 택해 /// (예측 채점처럼) 시드 여부와 무관하게 항상 존재를 보장한다. /// public static class BoardSeeder { /// 수익인증 게시판 코드 — 이미지 필수(RequireImage), 사진/동영상 레이아웃. public const string ProofBoardCode = "proof"; /// 장전 브리핑 게시판 코드 — 공지 리스트(IsNotice 발행). public const string BriefingBoardCode = "briefing"; /// 고객지원(공지) 게시판 코드 — 상단 네비 "고객지원" 대상. public const string NoticeBoardCode = "notice"; /// 고객지원 게시판(Code="notice")을 해석 — 없으면 기본 리스트로 lazy 시드하고 Board.ID 반환. public static Task ResolveNoticeBoardIDAsync(IAppDbContext db, CancellationToken ct) { return ResolveAsync(db, NoticeBoardCode, "고객지원", meta => { meta.List = new Domain.Entities.Forum.Boards.BoardMetaList { Layout = BoardLayout.Default, PerPage = 20 }; meta.View = new Domain.Entities.Forum.Boards.BoardMetaView { AllowLike = true, AllowBookmark = true }; meta.Write = new Domain.Entities.Forum.Boards.BoardMetaWrite { AllowEditor = true, AllowImage = true }; meta.Comment = new Domain.Entities.Forum.Boards.BoardMetaComment { EnableComment = true, AllowLike = true }; }, ct); } /// 피드 게시판 코드 — 피드 시스템 대상(SeedFeedBoard 마이그레이션과 동일 코드). public const string FeedBoardCode = "feed"; /// 피드 게시판(Code="feed")을 해석 — 없으면 Feed 레이아웃으로 lazy 시드. BoardGroup 만 남은 재빌드 상태를 복구. public static Task ResolveFeedBoardIDAsync(IAppDbContext db, CancellationToken ct) { return ResolveAsync(db, FeedBoardCode, "피드", meta => { meta.List = new Domain.Entities.Forum.Boards.BoardMetaList { Layout = BoardLayout.Feed, PerPage = 20 }; meta.View = new Domain.Entities.Forum.Boards.BoardMetaView { AllowLike = true, AllowBookmark = true }; meta.Write = new Domain.Entities.Forum.Boards.BoardMetaWrite { AllowEditor = true, AllowImage = true }; meta.Comment = new Domain.Entities.Forum.Boards.BoardMetaComment { EnableComment = true, AllowLike = true }; }, ct); } /// 수익인증 게시판(Code="proof")을 해석 — 없으면 이미지 필수·사진/동영상 레이아웃으로 lazy 시드하고 Board.ID 반환. public static Task ResolveProofBoardIDAsync(IAppDbContext db, CancellationToken ct) { return ResolveAsync(db, ProofBoardCode, "수익인증", meta => { meta.List = new Domain.Entities.Forum.Boards.BoardMetaList { Layout = BoardLayout.Media, PerPage = 20 }; meta.View = new Domain.Entities.Forum.Boards.BoardMetaView { AllowLike = true, AllowBookmark = true, ShowMemberThumb = true }; meta.Write = new Domain.Entities.Forum.Boards.BoardMetaWrite { AllowEditor = true, AllowImage = true, RequireImage = true }; meta.Comment = new Domain.Entities.Forum.Boards.BoardMetaComment { EnableComment = true, AllowLike = true }; }, ct); } /// 장전 브리핑 게시판(Code="briefing")을 해석 — 없으면 공지 리스트로 lazy 시드하고 Board.ID 반환. public static Task ResolveBriefingBoardIDAsync(IAppDbContext db, CancellationToken ct) { return ResolveAsync(db, BriefingBoardCode, "장전 시황", meta => { meta.List = new Domain.Entities.Forum.Boards.BoardMetaList { Layout = BoardLayout.Default, PerPage = 20 }; meta.View = new Domain.Entities.Forum.Boards.BoardMetaView { AllowLike = true, AllowBookmark = true }; meta.Write = new Domain.Entities.Forum.Boards.BoardMetaWrite { AllowEditor = true, AllowImage = true }; meta.Comment = new Domain.Entities.Forum.Boards.BoardMetaComment { EnableComment = true, AllowLike = true }; }, ct); } private static async Task ResolveAsync(IAppDbContext db, string code, string name, Action configureMeta, CancellationToken ct) { var existing = await db.Board.AsNoTracking().Where(c => c.Code == code).Select(c => (int?)c.ID).FirstOrDefaultAsync(ct); if (existing is int id) { return id; } var group = await db.BoardGroup.FirstOrDefaultAsync(c => c.Code == code, ct); if (group is null) { group = new BoardGroupEntity { Code = code, Name = name }; await db.BoardGroup.AddAsync(group, ct); await db.SaveChangesAsync(ct); } var board = new BoardEntity { BoardGroupID = group.ID, Code = code, Name = name, IsActive = true, IsSearch = true }; await db.Board.AddAsync(board, ct); await db.SaveChangesAsync(ct); var meta = new BoardMetaEntity { BoardID = board.ID }; configureMeta(meta); await db.BoardMeta.AddAsync(meta, ct); await db.SaveChangesAsync(ct); return board.ID; } }