Skip to content

docs(S15P11A705-125): Collection published_at NOT NULL 불변식을 정본에 반영 - #22

Merged
colosair merged 2 commits into
mainfrom
docs/S15P11A705-125-published-at-invariant
Jul 29, 2026
Merged

docs(S15P11A705-125): Collection published_at NOT NULL 불변식을 정본에 반영#22
colosair merged 2 commits into
mainfrom
docs/S15P11A705-125-published-at-invariant

Conversation

@colosair

@colosair colosair commented Jul 28, 2026

Copy link
Copy Markdown
Member

요약

Collection.published_at의 DB 불변식을 정본 문서(06·07)에 반영한다. 구현은 back#75V5__collection_published_at_invariant.sql이 담당하고, 이 PR은 그 제약을 정본 규칙·무결성 표·ERD에 옮기는 문서 변경이다. 정본 문서 2개 외 변경 없음(코드·API 명세·AI 설계 무변경).

S15P11A705-125의 3번째이자 마지막 PR이다(사유는 아래 "왜 한 티켓에 세 번째 PR인가").

Jira

병합 순서 — back#75 이후

이 PR은 back#75가 병합된 뒤에 병합한다.

정본 문서는 "현재 시스템이 보장하는 것"을 기술한다. 제약이 적용되지 않은 상태에서 이 PR만 병합하면 문서가 구현보다 앞서간다.

변경 사항

초안은 NOT NULL DEFAULT now()였으나 back#75 리뷰에서 CHECK 함의형으로 바뀌었고, 이 PR도 그에 맞춰 다시 썼다. 아래가 최종 형태다.

파일 무엇을
06_데이터모델_및_무결성.md §2.6 규칙 published_at은 컬럼 자체로는 NULL을 허용하지만 발행된 행은 반드시 값을 가진다는 규칙 한 줄 추가. 백필 소스(created_at)와 NOT NULL로 만들지 않은 이유를 함께 기술 스키마 표는 TIMESTAMPTZ(nullable) 그대로다. 제약이 컬럼이 아니라 CHECK에 있으므로 표가 아니라 규칙에 적어야 실제와 일치한다
06_데이터모델_및_무결성.md §4.1 DB 보장 표 발행된 Collection의 발행 시각 누락 금지 → CHECK (NOT is_published OR published_at IS NOT NULL) 행 추가 §4.1은 "DB가 보장하는 것"의 목록이다. 새로 DB로 내려간 불변식이 없으면 목록이 실제 제약보다 적어진다
07_ERD.md COLLECTION 블록 timestamptz published_attimestamptz published_at "발행 시 필수 (CHECK)" ERD가 §2.6·§4.1과 어긋나지 않게 한다

05_AI_설계.md의도적으로 건드리지 않았다 — 아래 참조.

NOT NULL이 아니라 CHECK인가

back#75 리뷰에서 나온 판단을 그대로 따른다. is_published가 false일 수 있다는 전제 위에 published_at이 존재하므로, 컬럼을 NOT NULL로 만들면 미발행 상태를 표현할 수 없게 되어 스키마가 자기모순이 된다. 함의 한 방향(NOT is_published OR published_at IS NOT NULL)만 걸면 오늘 얻는 보호는 같으면서(Feed 후보 쿼리가 전부 is_published = true를 건다) 비공개 전환이나 발행 취소가 들어와도 제약을 풀 필요가 없다.

상세 근거는 BD-33에 있다.

배경

이 변경은 back 레포 미커밋 변경을 back#74·back#75로 외부화하던 시점에 docs 레포 로컬에도 생겼는데, 당시 외부화 범위에 docs가 포함되지 않아 커밋되지 못했다. 로컬 정리 중 발견해 stash·patch로 보존한 뒤 이 PR로 살렸다.

보존물에는 05_AI_설계.md의 Feed category/region 제외 변경도 있었으나 제외했다docs#21이 같은 내용을 더 자세히 담고 있어 중복·충돌이 된다. 반면 06·07published_at 변경은 docs#21에도 없는 유일본이라 이 PR이 유일한 반영 경로다.

왜 한 Jira 티켓에 세 번째 PR인가

S15P11A705-125는 "로컬 미커밋 변경의 외부화"라는 한 작업이고, 그 산출물이 성격이 다른 세 덩어리로 나왔다. 리뷰 축이 각각 달라 하나로 묶으면 리뷰가 흐려진다.

# PR 리뷰 축
1 back#74 Feed 계약 문서 — MVP 후보·점수·Cache에서 Place category·region 제외 (설계 판단)
2 back#75 구현 — V5 마이그레이션·마이그레이션 테스트 (동작·배포 호환성)
3 이 PR 정본 문서 정합 — 규칙·무결성 표·ERD (구현과의 일치 여부)

레포도 갈린다(1·2는 back, 3은 docs). 티켓을 쪼개는 대신 PR을 쪼갠 이유는 세 산출물이 "같은 로컬 변경 하나에서 나왔다"는 추적성을 티켓 한 개로 유지하기 위해서다.

테스트 / 검증

문서 전용 변경이라 실행 가능한 테스트가 없다. 대신 아래를 확인했다.

  • 변경이 06·07 두 파일에 한정됨 — 의도 외 변경 없음
  • 05_AI_설계.md 변경 0 (docs#21 범위 침범 없음)
  • 문서에 적은 제약이 back#75 산출물과 일치 — CHECK (NOT is_published OR published_at IS NOT NULL), 백필 소스 created_at (BD-33 · BI-19 · V5__collection_published_at_invariant.sql)
  • 스키마 표를 바꾸지 않았음 — 컬럼은 nullable 그대로이고 제약은 CHECK에 있다
  • 렌더링 확인 — 미실행. Mermaid ERD 문법은 기존 행과 동일한 "주석" 형태만 추가했고(예: int record_count "활성 연결 수 비정규화"), 배포 시 GitHub Pages 빌드에서 검증된다

리뷰 포인트

  1. §2.6에 넣은 백필 문구. "기존 NULL 데이터는 created_at으로 백필합니다"는 마이그레이션 시점의 일회성 처리인데 이를 정본 스키마 문서에 남길지 판단이 필요하다. 남긴 이유는 백필 소스를 지우면 나중에 "기존 행의 발행 시각은 어디서 왔나"를 back 레포 BD-33까지 가야 알 수 있기 때문이다. 정본을 순수 현재 스키마로만 유지하는 편이 낫다면 이 한 줄만 빼면 된다.
  2. §4.1 행의 문구. "발행된 Collection의 발행 시각 누락 금지"로 적었다. 같은 표의 다른 행이 "~ 금지" 꼴이라 맞췄고, 조건부라는 점을 "발행된"으로 드러냈다.
  3. ERD 주석 표기. "발행 시 필수 (CHECK)"로 적었다. 이 ERD는 지금까지 NULL 여부를 표기하지 않아 와서 이 컬럼만 표기가 붙는다. 전체 컬럼 표기는 이 PR 범위를 넘어서므로 하지 않았다.

미결 / 후속

  • ERD의 NULL 표기 일관성 — 리뷰 포인트 3. 현재는 published_at만 제약이 표기된다. 전체 컬럼 표기 정책은 별도로 다룰 것.
  • is_published MVP 활용 여부06 §8 미확정 항목에 그대로 남아 있다. 비공개 전환이나 예약 발행을 도입하면 "발행 전 published_at이 NULL"이 실제 상태가 되며, CHECK는 그때도 제약을 풀 필요 없이 유효하다.
  • published_at 컬럼 존치 검토 — back#75에서 백엔드가 제기했다. AI 파트는 유지 의견(recency가 "최근 공개"를 재는 값이라 created_at으로 대체 불가)이며, 근거를 back#75에 회신했다. 결정은 스키마 소유자인 백엔드 몫이다.
  • Feed 런타임 구현(S15P11A705-120)은 이 PR·back#75 어느 쪽 범위도 아니다.

🤖 Generated with Claude Code

back#75가 V4 마이그레이션으로 `collection.published_at`을 백필 후
`DEFAULT now()` · `NOT NULL`로 고정했다. 정본 문서는 여전히
`TIMESTAMPTZ NULL`이라 구현과 어긋난 상태였다.

- 06 §2.6 스키마 표: `published_at TIMESTAMPTZ NOT NULL DEFAULT now()`
- 06 §2.6 규칙: 생성 즉시 발행이므로 NULL 불허, 기존 NULL은 created_at 백필
- 06 §4.1 DB 보장 표: "Collection 발행 시각 누락 금지" 행 추가
- 07 ERD: COLLECTION.published_at 제약 표기

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
back#75 리뷰를 수용해 구현이 `NOT NULL DEFAULT now()`에서
`CHECK (NOT is_published OR published_at IS NOT NULL)`로 바뀌었습니다. 앞선 커밋이
정본에 반영한 NOT NULL 표기를 그에 맞게 정정합니다.

- 06 §2.6 스키마 표: `TIMESTAMPTZ NULL`로 되돌립니다. 컬럼 자체는 nullable입니다
- 06 §2.6 규칙: 발행된 행만 값을 반드시 갖는다는 것과, 컬럼을 NOT NULL로 만들지
  않는 이유(`is_published`가 false일 수 있다는 전제 위의 컬럼이라는 점)를 적습니다
- 06 §4.1 DB 보장 표: "Collection 발행 시각 누락 금지 / NOT NULL DEFAULT now()"를
  "발행된 Collection의 발행 시각 누락 금지 / CHECK"로 바꿉니다
- 07 ERD: COLLECTION.published_at 표기를 "발행 시 필수 (CHECK)"로 맞춥니다

08 API 명세의 `publishedAt` 응답 필드는 제약 형태와 무관해 손대지 않았습니다.
@colosair
colosair marked this pull request as ready for review July 29, 2026 03:24
@colosair
colosair merged commit 96f4b3c into main Jul 29, 2026
@colosair
colosair deleted the docs/S15P11A705-125-published-at-invariant branch July 29, 2026 03:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant