feat: 메시지 미리보기 API 구현 (#120)

- POST /v1/in/message/preview 엔드포인트 추가
- MessageService: 메시지 조회 → 변수 치환 → 미리보기 데이터 반환
- IMessageService 인터페이스 정의 (향후 CRUD 확장용)

Closes #120
This commit is contained in:
SEAN 2026-02-10 17:27:56 +09:00
parent 6f58633de9
commit ef6d71a921
6 changed files with 89 additions and 1 deletions

View File

@ -12,10 +12,12 @@ namespace SPMS.API.Controllers;
public class MessageController : ControllerBase public class MessageController : ControllerBase
{ {
private readonly IMessageValidationService _validationService; private readonly IMessageValidationService _validationService;
private readonly IMessageService _messageService;
public MessageController(IMessageValidationService validationService) public MessageController(IMessageValidationService validationService, IMessageService messageService)
{ {
_validationService = validationService; _validationService = validationService;
_messageService = messageService;
} }
[HttpPost("validate")] [HttpPost("validate")]
@ -26,6 +28,15 @@ public class MessageController : ControllerBase
return Ok(ApiResponse<MessageValidationResultDto>.Success(result)); return Ok(ApiResponse<MessageValidationResultDto>.Success(result));
} }
[HttpPost("preview")]
[SwaggerOperation(Summary = "메시지 미리보기", Description = "메시지 템플릿에 변수를 치환하여 미리보기를 생성합니다.")]
public async Task<IActionResult> PreviewAsync([FromBody] MessagePreviewRequestDto request)
{
var serviceId = GetServiceId();
var result = await _messageService.PreviewAsync(serviceId, request);
return Ok(ApiResponse<MessagePreviewResponseDto>.Success(result));
}
private long GetServiceId() private long GetServiceId()
{ {
if (HttpContext.Items.TryGetValue("ServiceId", out var serviceIdObj) && serviceIdObj is long serviceId) if (HttpContext.Items.TryGetValue("ServiceId", out var serviceIdObj) && serviceIdObj is long serviceId)

View File

@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace SPMS.Application.DTOs.Message;
public class MessagePreviewRequestDto
{
[Required]
public string MessageCode { get; set; } = string.Empty;
public Dictionary<string, string>? Variables { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace SPMS.Application.DTOs.Message;
public class MessagePreviewResponseDto
{
public string Title { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public string? ImageUrl { get; set; }
public string? LinkUrl { get; set; }
}

View File

@ -20,6 +20,7 @@ public static class DependencyInjection
services.AddScoped<IFileService, FileService>(); services.AddScoped<IFileService, FileService>();
services.AddScoped<IPushService, PushService>(); services.AddScoped<IPushService, PushService>();
services.AddSingleton<IMessageValidationService, MessageValidationService>(); services.AddSingleton<IMessageValidationService, MessageValidationService>();
services.AddScoped<IMessageService, MessageService>();
return services; return services;
} }

View File

@ -0,0 +1,8 @@
using SPMS.Application.DTOs.Message;
namespace SPMS.Application.Interfaces;
public interface IMessageService
{
Task<MessagePreviewResponseDto> PreviewAsync(long serviceId, MessagePreviewRequestDto request);
}

View File

@ -0,0 +1,48 @@
using SPMS.Application.DTOs.Message;
using SPMS.Application.Interfaces;
using SPMS.Domain.Common;
using SPMS.Domain.Exceptions;
using SPMS.Domain.Interfaces;
namespace SPMS.Application.Services;
public class MessageService : IMessageService
{
private readonly IMessageRepository _messageRepository;
public MessageService(IMessageRepository messageRepository)
{
_messageRepository = messageRepository;
}
public async Task<MessagePreviewResponseDto> PreviewAsync(long serviceId, MessagePreviewRequestDto request)
{
var message = await _messageRepository.GetByMessageCodeAndServiceAsync(request.MessageCode, serviceId);
if (message == null)
throw new SpmsException(ErrorCodes.MessageNotFound, "존재하지 않는 메시지 코드입니다.", 404);
var title = ApplyVariables(message.Title, request.Variables);
var body = ApplyVariables(message.Body, request.Variables);
return new MessagePreviewResponseDto
{
Title = title,
Body = body,
ImageUrl = message.ImageUrl,
LinkUrl = message.LinkUrl
};
}
private static string ApplyVariables(string template, Dictionary<string, string>? variables)
{
if (variables == null || variables.Count == 0)
return template;
var result = template;
foreach (var (key, value) in variables)
{
result = result.Replace($"{{{{{key}}}}}", value);
}
return result;
}
}