Files
sodalive-backend-spring-boot/docs/20261027_콘텐츠배너예약기간/prd.md
T

83 lines
6.9 KiB
Markdown

# 오디오 콘텐츠 배너 예약 기간 PRD
## 문서 정보
| 항목 | 내용 |
|---|---|
| 문서 상태 | 구현 완료 |
| 작성일 | 2026-10-27 |
| 최종 수정일 | 2026-10-27 |
| 대상 제품 | 관리자 오디오 콘텐츠 배너 예약 노출 |
| 작성자·결정권자 | 제품 승인 요구사항 |
| 관련 API Contract | 관리자 예약 필드 추가, 기존 공개 response 유지, 본 문서 §7 |
| 관련 구현 계획 | `docs/20261027_콘텐츠배너예약기간/plan-task.md` |
| 관련 review | `reviews/admin-reservation-review.md`, `reviews/banner-reservation-final-review.md` |
## 1. Overview
관리자는 오디오 콘텐츠 배너에 선택적인 노출 시작·종료 시각을 설정한다. 공개 배너 조회는 현재 시각이 해당 기간에 포함될 때만 배너를 반환하고, 기존 배너는 NULL 기간으로 계속 노출한다.
## 2. Problem Statement
현재 배너는 노출 시작과 종료 시점을 관리할 수 없어서 기간성 콘텐츠를 수동으로 활성화·비활성화해야 한다. 기간이 지나도 공개 조회에서 배너가 선택될 수 있다.
## 3. Goals
- 관리자가 예약 기간을 생성·조회·수정·해제할 수 있다.
- 공개 오디오 배너 조회 네 경로가 동일한 기간 조건을 적용하고 기존 필터·정렬·limit 동작을 보존한다.
- 기존 레코드의 동작과 공개 응답 스키마를 유지한다.
## 4. Non-Goals
- 오디오 이외 배너 유형, 예약 실행 scheduler, 활성 상태 자동 변경은 범위 밖이다.
- 공개 API 응답 필드, 권한·인증, 공통 시간대 설정 및 dependency 변경은 하지 않는다.
- 운영 DB에 DDL을 자동 실행하지 않는다.
## 5. 사용자 및 권한
- 사용자는 기존 관리자 배너 API의 기존 권한으로 생성·조회·수정한다. 권한 범위는 변경하지 않는다.
- 공개 조회 권한과 성인·언어·탭·비활성·차단 대상 필터는 기존 계약을 유지한다.
## 6. 핵심 흐름
1. 관리자가 생성 요청에 선택적 예약 시각을 입력한다.
2. 관리자가 목록에서 저장된 두 시각을 확인한다. 예약 여부로 관리자 목록 행을 숨기지 않는다.
3. 관리자가 수정을 생략하면 기존 값을 유지하고, 해당 필드를 JSON `null`로 보내면 그 경계만 해제한다.
4. 공개 조회는 예약 기간 안에 있는 활성 배너만 기존 조건에 따라 반환한다.
## 7. 확정 기능 요구사항 및 계약
| ID | 상태 | 요구사항 및 수용 기준 | 계약/Goal |
|---|---|---|---|
| SCH-001 | 확정 | `startDate`, `endDate`는 nullable 시각이다. 둘 다 NULL이면 항상 노출, 시작만 있으면 `startDate <= now`, 종료만 있으면 `now <= endDate`, 둘 다 있으면 `startDate <= now <= endDate`이다. | `P1-T1`, `P1-T2` |
| SCH-002 | 확정 | 관리자 생성 입력의 두 필드는 optional이다. 관리자 목록은 두 값을 반환하되 기간으로 행을 필터링하지 않으며 기존 `isActive` 및 tab 조건을 유지한다. | `P1-T1` |
| SCH-003 | 확정 | 관리자 수정은 생략한 경계를 유지하고, 명시적 JSON null은 해당 값을 해제한다. effective start가 end보다 늦으면 `common.error.invalid_request`로 거부한다. 형식 오류도 같은 공통 오류를 사용하며, 검증은 이미지 업로드 전에 끝난다. | `P1-T1` |
| SCH-004 | 확정 | 관리자 입력 형식은 기존 이벤트 입력 관례인 KST 문자열 `yyyy-MM-dd HH:mm`, 저장은 UTC다. 끝 시각은 입력 분의 `:59`까지 포함한다. 응답 시각은 KST 동일 형식이다. 이는 기존 관리자 이벤트 관례를 적용한 구현 결정이며 사용자 지정 초 형식은 아니다. | `P1-T1` |
| SCH-005 | 확정 | DB는 두 컬럼을 MySQL `TIMESTAMP NULL DEFAULT NULL` 초 정밀도로 추가하고 모든 컬럼에 설명 COMMENT를 둔다. 기존 데이터는 NULL 유지, backfill 없음. DDL은 문서로 제공하며 적용이 앱 rollout보다 먼저다. 운영 DB 자동 실행 금지. | `P1-T1`, Gate |
| SCH-006 | 확정 | 공개 경로 네 곳 모두 기간 필터를 DB 조회에 적용해 limit 전에 제외한다. 기존 조건과 정렬을 보존한다. | `P1-T2` |
| SCH-007 | 확정 | 공개 응답 schema·권한·security는 그대로 유지한다. | 전체 |
관리자 수정에서 JSON 필드 생략과 명시적 null을 구분하기 위해 raw JSON의 presence만 감지한다. 신규 dependency는 추가하지 않는다.
공개 조회 경로는 `AudioContentQueryRepositoryImpl.getAudioContentMainBannerList(isAdult)`, `AudioContentBannerQueryRepositoryImpl.getAudioContentMainBannerList(tabId, isAdult, lang)`, `DefaultHomeRecommendationQueryRepository.findHomeBanners(limit, memberId, includeAdultBanners, lang)`, `DefaultAudioRecommendationQueryRepository.findBanners(limit, memberId, canViewAdultContent, lang)`이다. 각 경로에 이미 적용된 활성·탭·언어·성인·대상 소유자/차단 조건과 기존 정렬을 보존한다.
## 8. 데이터·오류·시각
- 입력 필드명은 사용자 요청대로 `startDate`, `endDate`; 값은 `yyyy-MM-dd HH:mm` 문자열 또는 null이다. 응답은 nullable 문자열이다.
- 형식 오류 및 기간 역전은 기존 `common.error.invalid_request`로 응답한다.
- DDL 소수초 미지정 `TIMESTAMP`의 초 정밀도에 맞춰 초 단위 단일 값으로 저장·응답한다. 공개 조회의 현재 UTC 시각도 초 단위로 비교해 종료 분의 마지막 초 전체를 포함한다. 테스트는 고정 UTC 현재 시각 seam을 사용하고 실제 DB 저장 후 `flush`/`clear`/재조회로 왕복을 확인한다. H2 검증 컬럼은 `TIMESTAMP(0)`로 운영 DDL의 정밀도를 재현한다.
## 9. 성공 기준과 추적
- [x] 관리자 create/update/list에서 선택적 기간, 생략 유지와 명시적 null 해제를 검증한다. (`SCH-002~005`, `P1-T1`)
- [x] 잘못된 입력과 역전 기간이 업로드 전 공통 오류로 거부된다. (`SCH-003`, `P1-T1`, `P1-T1-R1`)
- [x] 네 공개 경로가 경계 시각 포함 여부를 판정하고 예약 외 레코드를 limit 전에 제외한다. (`SCH-001`, `SCH-006`, `P1-T2`)
- [x] 기존 공개 필터·정렬, 관리자 isActive/tab 필터, 공개 응답 schema가 보존된다. (`SCH-002`, `SCH-006~007`, Gate)
- [x] DDL과 앱 배포 순서를 문서화하고 자동 운영 DB 적용이 없다. (`SCH-005`, Gate)
## 10. 제외 항목 및 결정 기록
- 제외: 다른 banner type, scheduler, 공개 response 변경, 자동 isActive 전환, 신규 dependency, global time 설정, live DB 실행.
- 2026-10-27, DEC-001, 확정: 이벤트 관리자의 기존 KST 분 단위 입력/응답 관례를 적용하고 종료 분을 `:59`까지 포함한다. 요구사항은 timestamp 예약을 지정했으며 seconds format을 지정하지 않았으므로 기존 관리자 관례를 따른다.
- 2026-10-27, DEC-002, 확정: 기간 필터는 공개 네 조회에만 적용한다. 관리자 목록은 예약과 무관하게 기존 활성/tab 정책을 유지한다.