Skip to content
This repository was archived by the owner on Sep 24, 2026. It is now read-only.

[운영] DDL 이 빠졌으면 뜨지 않는다 - #99

Merged
RosieOh merged 3 commits into
releasefrom
feat/schema-guard
Sep 22, 2026
Merged

RosieOh merged 3 commits into
releasefrom
feat/schema-guard

Conversation

@RosieOh

@RosieOh RosieOh commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Closes #98

막으려는 것

DB-first 라 prisma/sql/*.sql 을 사람이 적용한다. 코드만 배포되고 DDL 이 빠지면 앱은 멀쩡히 뜨고 조용히 못 한다.

빠진 DDL 조용히 실패하는 것
008 risk_scores.missing_factors 위험도 저장 → 시민 화면에 아무 단계도 안 나온다
007 prediction_evaluations.actual_granularity 예측 대조 배치
009 static_guide_translations 응급대처법이 화면에서 사라진다

기동 로그는 정상이고 실패는 한 시간 뒤 배치에서 처음 드러난다. 그 한 시간은 하필 배포 직후다.

지금 이 저장소에 적용 대기 중인 DDL 이 정확히 그 셋이다.

어떻게

shared/persistence/schema-guard.ts 가 기동 시 점검하고, 없으면 뜨지 않는다.

DB 스키마가 코드보다 뒤쳐져 있습니다 (2건).
  · risk_scores.not_applied_yet 없음 → 테스트용 가짜 요구사항
    적용: mysql -u <user> -p <db> < prisma/sql/010-future.sql
  · table_that_does_not_exist 없음 → 테스트용 가짜 테이블
    적용: mysql -u <user> -p <db> < prisma/sql/011-future.sql
이 상태로 뜨면 앱은 정상으로 보이지만 위 기능이 조용히 실패합니다. 그래서 기동을 막습니다.

무엇이 없고, 무엇이 안 되고, 어떤 파일을 적용해야 하는지가 한 번에 나온다. 막을 때는 다음 행동이 분명해야 한다.

"조용히 열린 채 뜨는 것보다 실패하는 쪽이 낫다" 는 이 저장소의 기준을 스키마에도 적용한다 — CORS_ORIGIN 이 운영에서 기동을 막는 것과 같은 이유다.

⚠️ 두 가지 실패를 다르게 다룬다

없는 것을 확인함 기동을 막는다
확인 자체가 실패함 경고만 남기고 통과

뒤를 통과시키는 이유 — 관리형 DB 에서 information_schema 권한이 제한될 수 있는데, 점검기가 서비스 전면 중단의 원인이 되면 안 된다. 레이트 리밋이 Redis 장애 때 fail-open 하는 것과 같은 기준이다.

검증

lint 0 · unit 1386 · e2e 65 · 실 DB 스모크 174 (신규 2) · build OK
git rebase --exec 'npx tsc --noEmit'  → 3 커밋 전부 단독 통과
  • 정상 DB 에서 스키마 점검 통과 (7개 요소) 후 기동
  • 없는 컬럼·없는 테이블을 요구 목록에 넣으면 기동이 막히는 것 확인
  • SQL 파일명을 틀리게 바꾸면 스모크가 깨지는 것 확인 — 오류가 존재하지 않는 파일을 안내하면 막은 것이 도움이 아니라 방해가 된다

규칙

prisma/sql/ 에 파일을 추가하면 schema-requirements.ts 에도 함께 적는다. 안 적으면 다음 사람이 DDL 을 빠뜨려도 아무도 모른다 — 이 목록의 값은 빠짐없음에 있다. README 에 적었다.

인덱스처럼 "있으면 빠르고 없으면 느린" 것은 넣지 않는다. 기동을 막을 근거가 아니다.

DB-first 라 운영에 prisma migrate 를 쓰지 않는다. prisma/sql/*.sql 을 **사람이 적용**하므로
코드만 배포되고 DDL 이 빠지는 일이 구조적으로 가능하다.

지금 이 저장소에 적용 대기 중인 DDL 이 셋(007·008·009)이고, 그중 008 이 빠지면 위험도
저장이 매번 실패한다. 목록이 없으면 그걸 아무도 세지 않는다.

⚠️ 여기에 적는 것은 **없으면 못 도는 것**만이다. 인덱스처럼 있으면 빠르고 없으면 느린 것은
적지 않는다 — 기동을 막을 근거가 아니다.

각 항목에 "없으면 무엇이 안 되는가" 를 사람 말로 적는다. 기동을 막을 때 다음 행동이
분명해야 하고, 컬럼 이름만으로는 그게 안 된다.
⚠️ 지금까지는 **멀쩡히 뜨고 조용히 못 했다.** missing_factors 컬럼이 없으면 위험도 저장이
매번 실패해 시민 화면에 아무 단계도 안 나오는데, 기동 로그는 정상이고 실패는 한 시간 뒤
배치에서 처음 드러난다. **그 한 시간은 하필 배포 직후다.**

"조용히 열린 채 뜨는 것보다 실패하는 쪽이 낫다" 는 이 저장소의 기준을 스키마에도 적용한다
(CORS_ORIGIN 이 운영에서 기동을 막는 것과 같은 이유).

두 가지 실패를 다르게 다룬다:
  · 없는 것을 확인함  → 기동을 막는다
  · 확인 자체가 실패함 → 경고만 남기고 통과

뒤를 통과시키는 이유 — 관리형 DB 에서 information_schema 권한이 제한될 수 있는데,
**점검기가 서비스 전면 중단의 원인이 되면 안 된다.** 레이트 리밋이 Redis 장애 때 fail-open
하는 것과 같은 기준이다. 대신 로그에 크게 남긴다.

KyselyModule 에 둔 이유는 스키마 점검이 **DB 연결이 준비된 직후** 한 번 돌아야 하고 이
모듈이 그 연결을 만드는 곳이기 때문이다. 컨텍스트 모듈에 두면 모듈 기동 순서에 따라
점검 시점이 달라진다.

오류 메시지에 적용할 SQL 파일 경로를 그대로 싣는다 — 막을 때는 다음 행동이 분명해야 한다.
실 DB 스모크 2건.

  · 코드가 가정하는 스키마가 실제 DB 에 전부 있는가
  · 요구 목록이 가리키는 SQL 파일이 실제로 존재하는가

두 번째가 필요한 이유 — 파일명을 잘못 적으면 오류 메시지가 **존재하지 않는 파일을 적용하라고
안내한다.** 기동을 막는 순간에 그 안내가 틀리면, 막은 것이 도움이 아니라 방해가 된다.
파일명을 틀리게 바꿔 깨지는 것을 확인했다.

첫 번째가 깨지면 prisma/sql 에 파일을 추가하고 적용하지 않았거나, 요구 목록에 적지 않았다는
뜻이다. 둘 다 배포 사고로 이어진다.

README 의 "DB 스키마 변경" 절에 규칙을 적었다 — **파일을 추가하면 목록에도 함께 적는다.**
@RosieOh
RosieOh merged commit e2a4111 into release Sep 22, 2026
2 checks passed
@RosieOh
RosieOh deleted the feat/schema-guard branch September 22, 2026 10:42
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant