using Application.Abstractions.Messaging; using Application.Abstractions.Data; using Application.Abstractions.Cache; using SharedKernel.Results; using Microsoft.EntityFrameworkCore; using BoardMetaResponse = Application.Features.Api.Forum.BoardMeta.Get.Response; namespace Application.Features.Api.Forum.Board.Get; public sealed class Handler(IAppDbContext db, ICacheService cache) : IQueryHandler> { public async Task> Handle(Query request, CancellationToken ct) { var item = await db.Board .AsNoTracking() .Include(x => x.BoardGroup) .Include(x => x.BoardPrefix.Where(p => p.IsActive).OrderBy(p => p.Order)) .Include(x => x.BoardManager) .ThenInclude(m => m.Member) .FirstOrDefaultAsync(x => x.Code == request.Code, ct); if (item is null) { return Result.Failure(Error.NotFound("Board.NotFound", "게시판을 찾을 수 없습니다.")); } // BoardMeta 조회 (캐시 우선) BoardMetaResponse? boardMeta = null; var cacheKey = CacheKeys.BoardMeta(item.ID); var cached = await cache.GetAsync(cacheKey, ct); if (cached is not null) { boardMeta = cached; } else { var meta = await db.BoardMeta.FirstOrDefaultAsync(x => x.BoardID == item.ID, ct); if (meta is null) { meta = new Domain.Entities.Forum.Boards.BoardMeta { BoardID = item.ID }; await db.BoardMeta.AddAsync(meta, ct); await db.SaveChangesAsync(ct); } boardMeta = new BoardMetaResponse( meta.ID, meta.BoardID, item.Code, item.Name, meta.List, meta.View, meta.Write, meta.Comment, meta.General, meta.Permission, meta.Notify, meta.NotifyTemplate, meta.Exp); await cache.SetAsync(cacheKey, boardMeta, ct); } return new Response( item.ID, item.BoardGroupID, item.Code, item.Name, item.IsSearch, item.IsActive, item.Posts, new BoardGroupDto( item.BoardGroup.ID, item.BoardGroup.Code, item.BoardGroup.Name ), [..item.BoardPrefix.Select(p => new BoardPrefixDto( p.ID, p.BoardID, p.Name, p.Color, p.Posts ))], [..item.BoardManager.Select(m => new BoardManagerDto( m.ID, m.BoardID, new BoardManagerUserDto(m.MemberID, m.Member.Email), m.CanEdit, m.CanDelete, m.UpdatedAt, m.CreatedAt ))], boardMeta ); } }