계약과 운영 문서: API Spec부터 Runbook, SLO, Postmortem까지
서비스가 커질수록 내부 구현보다 경계의 약속이 중요해진다. 이 층위에는 API Spec, OpenAPI, AsyncAPI, ERD, Data Dictionary, Schema, ICD가 들어간다. 그리고 배포 뒤에는 Threat Model, Release Plan, Migration Plan, Rollback Plan, Runbook, SLI/SLO/SLA, Postmortem이 필요해진다. 운영만 있으면 나머지는 따라올 거라고 믿었다. 그래서 용어 사전 대신, 그 날 무엇을 보고 무엇을 바꿨는지부터 적는다.

운영 문서가 커진 문제
이런 문서는 평소에는 지루하다. 하지만 장애가 나면 가장 빨리 읽히는 문서가 된다. 이 문서들은 서로 멀어 보이지만 같은 질문을 공유한다. 시스템은 다른 시스템과 무엇을 약속했고, 그 약속이 깨졌을 때 어떻게 움직일 것인가? 특히 계약과에서는 재현 조건을 같이 적어야 의미가 있었다. Runbook은 반복 운영 절차를 적는다. 장애가 났을 때 누가 무엇을 확인하고, 어떤 명령을 실행하고, 어디까지 되돌릴 수 있는지 남긴다. 참고: OWASP Threat Modeling Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/Threat_Modeling_Cheat_Sheet.html

현재 구성의 가정
참고: Google SRE Service Level Objectives — https://sre.google/sre-book/s ```md
- 증상: public desk detail이 500을 반환한다.
- 먼저 확인: app process, DATABASE_URL, SQLite file permission
- 임시 조치: 최근 DB 백업으로 교체하기 전 현재 DB를 별도 보관한다.
- 롤백 조건: 새 배포 후 5분 이상 500이 지속된다.
- 확인 URL: /writing, /writing/projects, 대표 글 상세 페이지 ```
참고: Google SRE Postmortem Culture — https://sre. 코드만 보면 지금의 형태는 알 수 있다. 하지만 그 필드가 어떤 약속을 대표하는지는 알기 어렵다. 데이터 문서는 이름표가 아니라 의미의 경계다. 특히 계약과에서는 재현 조건을 같이 적어야 의미가 있었다. 이 질문을 코드 안에만 두면 프론트엔드, 백엔드, 운영자가 서로 다른 약속을 믿게 된다.

계약 누락이 선명해진 순간
Postmortem은 실패 뒤에 남는 문서다. Google SRE는 postmortem을 incident, impact, mitigation, root cause, follow-up action의 기록으로 설명한다. 핵심은 blameless다. 사람을 탓하지 않고 시스템과 프로세스가 어떻게 다음 실패를 줄일지 본다. 이 구분은 작아 보여도 중요하다. “99.9%로 운영하자”라고 말하는 것과 “어떤 요청의 어떤 지표를 어떤 기간 동안 99.9%로 볼 것인가”는 완전히 다르다. API Spec은 “백엔드가 프론트엔드에게 이렇게 부르면 된다”고 적어주는 문서가 아니다.
시스템 사이의 계약이다. 이 계약에는 endpoint, request, response, error shape, auth, rate limit, versioning, deprecation policy가 들어가야 한다. md - 무엇을 만들고 있는가? - 무엇이 잘못될 수 있는가? - 그것에 대해 무엇을 할 것인가? - 충분히 잘했는가? 특히 계약과에서는 재현 조건을 같이 적어야 의미가 있었다. 설계는 배포 전에 끝나지 않는다. API 계약, 데이터 의미, 보안 경계, 운영 기준, 장애 학습이 이어질 때 설계는 실제 서비스의 생명주기와 연결된다.
운영 문서는 서비스가 실제로 살아 있을 때 필요하다. Google SRE Book은 SLI를 서비스 수준을 나타내는 정량 지표, SLO를 그 지표의 목표값, SLA를 목표를 못 지켰을 때의 결과가 포함된 계약으로 구분한다. 계약과를 설명할 때 서버/클라이언트/사용자 중 누구 문장으로 말하는지 먼저 고르면 논쟁이 줄었다.
분리·중계·직접연결 선택
OpenAPI Specification은 HTTP API를 위한 language-agnostic interface description이다. 소스코드, 추가 문서, 네트워크 트래픽 검사 없이도 서비스의 capability를 이해할 수 있게 한다. 잘 정의된 OpenAPI 문서는 문서 생성, 코드 생성, 테스트 도구에도 쓰일 수 있다. 작은 팀에서도 이 층위를 무시하면 금방 문제가 생긴다. API response의 status가 결제 상태인지 요청 상태인지, expiredAt이 만료 예정인지 실제 폐기 시각인지, userId가 내부 사용자 ID인지 외부 공개 ID인지 헷갈리기 시작한다. 특히 계약과에서는 재현 조건을 같이 적어야 의미가 있었다. ```md
- incident: 새 글 발행 후 상세 URL이 404를 반환했다.
- impact: 사용자가 새 글에 직접 접근할 수 없었다.
- root cause: DB는 교체됐지만 실행 중인 SQLite connection이 이전 inode를 보고 있었다.
- mitigation: 운영 프로세스를 재시작하고 no-cache HTTP client로 확인했다.
- follow-up: DB 교체 시 프로세스 재시작과 live URL 검증을 배포 체크리스트에 넣는다. ``` 데이터 쪽에는 ERD와 Data Dictionary가 있다. ERD는 엔티티와 관계를 보여 준다. Data Dictionary는 필드 이름, 의미, 타입, nullable 여부, 단위, 소유권, 보존 기간을 적는다. schema는 이 약속을 기계가 검증할 수 있는 형태로 만든다.
다시 짜 본 구조
md - pending, approved, rejected는 어떤 상태 전이를 허용하는가? - rejected reason은 사용자에게 그대로 보여도 되는가? - expired request는 404인가, 410인가, 상태값인가? - 관리자 권한 실패와 사용자 권한 실패의 error shape는 같은가? - API version이 바뀌면 기존 링크는 얼마나 유지하는가? 이 질문은 설계 단계에서 해야 한다. DFD, trust boundary, data flow, data store, process, external entity를 보면서 STRIDE 같은 방법으로 위협을 찾는다. 보안은 체크리스트가 아니라 시스템 구조 안에 들어가야 한다. 사용자에게 보이는 문장과 내부 상태 이름을 분리해 두니 논의가 빨라졌다. 여기서 중요한 것은 “누가 실수했나”가 아니다. 다음번에는 어떤 체크가 자동으로 들어가야 하는가다. 참고: OpenAPI Specification — https://spec.openapis.org/oas/latest. Threat Model은 보안을 설계 끝에 붙이는 문서가 아니다. OWASP Threat Modeling Cheat Sheet는 threat modeling을 보안 관점에서 시스템을 모델링하고, 적용 가능한 위협과 대응을 찾는 구조적 반복 프로세스로 설명한다. 특히 계약과에서는 재현 조건을 같이 적어야 의미가 있었다. '계약과 운영 문서: API Spec부터 Runbook, SLO, Postmortem까지'을 관통하는 질문은 이 섹션에서도 같았고, 답만 더 구체적이 됐다.
마치며
참고: Google SRE Postmortem Culture — https://sre.google/sre-book/postmortem-culture/ 코드만 보면 지금의 형태는 알 수 있다. 하지만 그 필드가 어떤 약속을 대표하는지는 알기 어렵다. 데이터 문서는 이름표가 아니라 의미의 경계다. 이 질문을 코드 안에만 두면 프론트엔드, 백엔드, 운영자가 서로 다른 약속을 믿게 된다. Postmortem은 실패 뒤에 남는 문서다. Google SRE는 postmortem을 incident, impact, mitigation, root cause, follow-up action의 기록으로 설명한다. 핵심은 blameless다. 사람을 탓하지 않고 시스템과 프로세스가 어떻게 다음 실패를 줄일지 본다. 특히 계약과에서는 재현 조건을 같이 적어야 의미가 있었다.