docs(notice): 예약 공개 요구사항과 관리자 연동 계약을 정의한다

This commit is contained in:
2026-10-30 22:51:45 +09:00
parent 394949ab6e
commit e6afae2763
2 changed files with 263 additions and 0 deletions
@@ -0,0 +1,100 @@
# 관리자 공지 예약 공개 API 연동 작업
아래 요구사항에 따라 기존 ADMIN 공지사항 생성·수정 화면의 API 연동을 변경하세요. 이 작업은 기존 화면에 예약 공개 입력과 처리만 추가하며 화면을 새로 설계하지 않습니다. **아래 API 계약을 기준으로 작업하며 실제 연결은 대상 API 사용 가능 여부를 확인한다.**
## 작업 범위
- 기존 공지 생성과 수정 기능에 선택적 예약 공개 시각 `publishAt` 입력과 전송을 추가합니다.
- API 요청·응답 및 화면 상태 연결만 다룹니다. 서버 구현이나 서버 설정을 변경하지 않습니다.
- 기존 화면 구조와 사용자 동작을 유지하고, 필요한 API 연동만 수정합니다.
## 공통 계약
- 기존 ADMIN Bearer 인증을 재사용합니다. 새 인증 흐름이나 권한 체계를 만들지 않습니다.
- 성공은 `ApiResponse`의 `success`, `message`, `data`, `errorProperty` envelope로 판별합니다. HTTP 200이어도 `success: false`면 실패입니다.
- 오류 응답의 기존 필드를 보존하고, 사용자에게는 응답 `message`를 표시합니다. 인증 오류는 기존 로그인 흐름을 따릅니다.
- 시각 문자열은 모두 Asia/Seoul 기준 `yyyy-MM-dd HH:mm:ss`입니다. `T`, `Z`, offset, 밀리초를 포함하지 않습니다.
- 브라우저 시간대를 거쳐 변환하거나 KST 시각을 다시 변환하지 않습니다. 표시·입력한 시각을 그대로 계약 형식으로 보내 이중 시간대 이동을 막습니다.
## 생성
`POST /notice`
요청 필드: `title`, `content`, 선택 필드 `publishAt` (`string | null`).
```json
{
"title": "서비스 점검 안내",
"content": "점검 시간과 안내 내용",
"publishAt": "2026-11-15 09:00:00"
}
```
- `publishAt` 생략 또는 `null`은 즉시 공개입니다.
- 미래의 유효한 시각 문자열은 예약 공개입니다. 예시 시각은 실제 요청 시점보다 미래여야 합니다.
- 현재 또는 과거 시각은 허용하지 않습니다. 오류를 정상 성공처럼 처리하지 않습니다.
- 요청에 `isScheduled`, `createdAt`, `isActive`를 추가하지 않습니다. 생성 성공 응답의 `data`는 숫자 공지 ID입니다.
## 수정
`PUT /notice`
요청 필드: 필수 `id`, 선택 `title`, `content`, `publishAt` (`string | null`).
```json
{
"id": 42,
"publishAt": "2026-11-20 10:30:00"
}
```
- `publishAt` 생략은 기존 예약 상태를 보존합니다. 제목만 또는 본문만 수정할 때도 이 규칙을 따릅니다.
- 명시적 `null`은 아직 공개되지 않은 예약 공지를 지금 공개하겠다는 의도일 때만 보냅니다.
- 미래 시각 문자열은 아직 공개되지 않은 예약 공지의 예약 시각을 변경합니다. 시각만 변경하는 요청도 유효합니다.
- 이미 공개된 공지는 제목·본문 수정은 허용되지만 공개 시각 변경은 허용되지 않습니다. 그런 요청의 API 실패를 존중하고 우회하거나 재시도하지 않습니다.
- 제목만 수정할 때 폼에 조회한 `publishAt` 값이 있어도 요청에서 반드시 생략합니다. 기본값 `null`을 무심코 직렬화하지 말고, 사용자가 즉시 공개 전환을 명시한 경우에만 `publishAt: null`을 보냅니다.
- 수정 성공 시 `data`의 구체적인 값에 의존하지 않습니다. `success`를 확인한 뒤 목록을 다시 조회합니다.
## 관리자 목록
`GET /api/v2/admin/notices?page=0&size=20`
기존 ADMIN 인증을 사용합니다. 공개된 항목만 반환하는 공개 공지 API를 대신 사용하지 않습니다. ADMIN 토큰으로 공개 API를 호출해도 예약 공개 전 공지는 반환되지 않습니다.
응답 `data` 형식:
```json
{
"totalCount": 1,
"noticeList": [
{
"id": 42,
"title": "서비스 점검 안내",
"content": "점검 시간과 안내 내용",
"isActive": true,
"isScheduled": true,
"publishAt": "2026-11-15 09:00:00",
"createdAt": "2026-10-30 14:20:00"
}
]
}
```
각 항목은 `id`, `title`, `content`, `isActive`, `isScheduled`, `publishAt`, `createdAt`을 가집니다. `publishAt`은 공개 시각 문자열 또는 `null`이며, 예약을 즉시 공개로 전환한 항목에는 전환 시각이 들어 있습니다. `null`은 시각을 지정하지 않고 즉시 등록한 공지입니다. 목록에는 활성 공개 공지와 아직 공개되지 않은 활성 예약 공지가 모두 포함됩니다. 페이지 인덱스는 0부터 시작하고 `totalCount`는 이 관리자 목록의 전체 대상 건수입니다.
별도의 공지 상세 API는 없습니다. 편집 시 목록에서 받은 전체 항목을 사용하고, 존재하지 않는 상세 경로를 만들지 않습니다.
## 날짜 표시와 목록 갱신
- 예약 공개 공지의 날짜 표시는 `publishAt`의 KST 날짜를 사용합니다.
- 즉시 생성된 공지와 예약에서 즉시 공개로 전환한 공지의 날짜 표시는 원래 등록 시각인 `createdAt`의 KST 날짜를 사용합니다.
- `isScheduled`는 응답 전용 표시 상태이며 요청에 보내지 않습니다. 예약이 자연 공개된 뒤에도 `true`일 수 있으므로 이를 미공개 여부로 해석하지 않습니다. `isScheduled`와 미래 `publishAt`을 함께 화면 동작 판단에 참고할 수 있지만, 공개 경계를 최종 판단하는 주체는 API입니다. 클라이언트 시계나 이 불리언만으로 공개 상태를 확정하거나 API 거부를 무시하지 않습니다.
- 생성·수정 성공 후 목록을 다시 조회합니다. 응답은 공개 시각 내림차순, 같은 시각이면 ID 내림차순입니다. 이 순서를 유지하고 표시 날짜를 기준으로 클라이언트에서 재정렬하지 않습니다. 특히 예약을 즉시 공개로 전환한 경우 표시 날짜는 원래 등록일이지만 목록 순서는 공개 시각 변경에 따라 달라질 수 있습니다.
- 목록을 불러오거나 저장할 수 없을 때 임의의 공개 API로 자동 대체하지 않습니다. API 실패를 보존해 기존 오류 흐름으로 처리합니다.
## 완료 확인
- 생성에서 `publishAt` 생략/null은 즉시 공개, 미래 시각은 예약 요청으로 전달됩니다.
- 수정에서 `publishAt` 생략은 보존, 명시적 null은 의도된 즉시 전환, 미래 시각은 재예약으로 전달됩니다. 제목만 수정할 때 `publishAt`은 생략됩니다.
- 관리자 목록은 위 경로와 페이지 파라미터를 사용하며 응답의 `success`를 확인하고 목록 순서를 유지합니다.
- 모든 시각 요청·표시는 KST `yyyy-MM-dd HH:mm:ss`이며 브라우저 시간대 변환을 추가하지 않습니다.