docs(TechLog): 글감 56개를 기록으로 쓴다
주제 13개 · Case 28 · Concept 5 · Reference 15 · Question 4 · Decision 4. 계약의 노드마다 종류가 요구하는 칸을 채우고, 본문이 있는 두 종류에는 SSOT 가 이미 그려 둔 도식 셋(value-boundaries · decision-path-404 · topic-variant-model)을 tech-log-studio/ 로 옮겨 붙였다. 새로 그린 그림은 없다. 검사 셋 전부 통과한다. check_body.mjs 56 편 중 본문이 있는 33 편 PASS check_prose.mjs 56 편 error 0 check_evidence.mjs --repo 포함 문제 없음 verify-tech-log-tree.py 프로젝트 5 · error 0 · warn 0 인용한 코드블록은 전부 SSOT 에서 찾아 대조했다. check_evidence.mjs 가 본문의 각 줄과 source 앵커와 계약 제목을 다시 확인한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6955611439
commit
f6c825e858
+85
@@ -0,0 +1,85 @@
|
||||
---
|
||||
kind: CASE
|
||||
slug: a-link-that-pointed-at-itself
|
||||
title: 축 링크가 자기 자신을 가리켰고, 고친 뒤에는 백엔드를 먼저 배포했다
|
||||
topic: addresses-frozen-at-publish-time
|
||||
topicName: 주소가 만들어지고 굳어지는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
lastVerifiedOn: 2026-09-04
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§9.1
|
||||
- final/document.md#§9.3
|
||||
---
|
||||
|
||||
# 축 링크가 자기 자신을 가리켰고, 고친 뒤에는 백엔드를 먼저 배포했다
|
||||
|
||||
주제 화면의 네 줄은 링크인데 눌러도 아무 일이 없었다. 축의 주소를 주제 화면 안의 앵커로 바꿨더니, 정작 주제 화면에서는 그 링크가 자기 자신을 가리켰다. 결국 축에 자기 화면을 줬고, 그 화면을 만들고 백엔드를 프론트보다 먼저 배포해 사용자가 네 링크 전부 404 인 화면을 봤다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **새 라우트는 프론트엔드를 먼저 배포한다**
|
||||
이 사건에서 정한 순서다.
|
||||
- **우회를 남길 때는 되돌릴 조건을 함께 적는다**
|
||||
같은 주제 링크를 다루며 굳힌 기준이다.
|
||||
- **축은 주제가 이름을 정하고, 기록은 종류와 아이디의 쌍으로 축에 걸린다**
|
||||
축에 자기 화면을 주려면 알아야 하는 구조다.
|
||||
|
||||
## 문제
|
||||
|
||||
주제 화면의 네 줄(SPA·Mediator·BFF·Forward-Auth)은 링크로 그려져 있었다. 눌러도 아무 일이 없었다.
|
||||
|
||||
처음에 `/topics/{주제}/{축}` 이라 적어 두었는데 그런 화면이 없었다.
|
||||
|
||||
## 결론
|
||||
|
||||
주소를 두 번 옮긴 끝에 축에 자기 화면을 줬다.
|
||||
|
||||
1차 : 축의 주소를 주제 화면 안의 앵커로 바꿨다 — 주제 화면에서는 그 링크가 자기 자신을 가리켰다
|
||||
2차 : 축에 자기 화면을 줬다 — 목록 조회에 축 필터를 더해 걸러 낸다
|
||||
|
||||
축 slug 는 주제 안에서만 유일하므로 조회에서 주제까지 함께 맞춘다. 주제를 빼면 다른 주제의 같은 이름 축이 함께 걸린다.
|
||||
|
||||
같은 시기에 주제가 없는 기록이 이름 없는 주제 링크를 달고 있던 것도 고쳤다. 문서 머리말의 breadcrumb 과 탐색의 「주제 없음」 묶음 둘 다였고, 프로젝트 조각은 처음부터 조건부였는데 주제 쪽만 아니었다.
|
||||
|
||||
## 검증 환경
|
||||
|
||||
tech-log-frontend : 8828005 · 67a5491
|
||||
tech-log-backend : 63eb177 · 6d3b68b
|
||||
tech-log-design-package : 71bab4c · b93d62a
|
||||
확인 방식 : 배포본에서 주제 화면의 네 링크를 눌러 각각 어디로 가는지 확인
|
||||
|
||||
## 재현 조건
|
||||
|
||||
1. 주제에 축을 넷 만들고 기록을 각 축에 건다
|
||||
2. 주제 화면에서 축 줄을 누른다
|
||||
3. 주소가 바뀌는지, 화면이 바뀌는지를 따로 본다
|
||||
|
||||
## 본문
|
||||
|
||||
<!-- body:start -->
|
||||
|
||||
## 주소만 바뀌고 화면은 그대로였다
|
||||
|
||||
처음에 축의 주소를 `/topics/{주제}/{축}` 이라 적어 두었는데 그런 화면이 없었다. 그래서 축의 주소를 주제 화면 안의 앵커로 바꿨다.
|
||||
|
||||
주제 화면에서 그 링크를 누르면 주소에 앵커가 붙는다. 화면은 이미 그 주제 화면이므로 아무것도 바뀌지 않는다.
|
||||
|
||||
## 축에 자기 화면을 줬다
|
||||
|
||||
목록 조회에 축 필터를 더하고 `record_variant` 로 거른다. 축 slug 는 주제 안에서만 유일하므로 주제까지 함께 맞춘다 — 주제를 빼면 다른 주제의 같은 이름 축이 함께 걸린다.
|
||||
|
||||
## 배포 순서로 만든 2차 사고
|
||||
|
||||
> **이 건에서 제가 만든 2차 사고:** 축 화면을 만들고 **백엔드를 프론트보다 먼저 배포했습니다.** nginx 설정은 라우트 계약에서 생성되므로, 프론트가 배포되기 전까지 `/topics/x/y` 는 404 입니다. 서버는 이미 그 주소를 내보내고 있었고, 사용자는 네 링크가 전부 404 인 화면을 봤습니다. **순서가 있습니다 — 새 라우트는 프론트가 먼저입니다.**
|
||||
|
||||
## 주제가 없는 기록
|
||||
|
||||
같은 시기에 주제 없이 게시된 기록이 이름 없는 주제 링크를 달고 있었다. 문서 머리말의 breadcrumb 과 탐색의 「주제 없음」 묶음 둘 다였다. 프로젝트 조각은 처음부터 조건부였는데 주제 쪽만 아니었다.
|
||||
|
||||
## 확인하지 못한 것
|
||||
|
||||
축 slug 가 주제 안에서만 유일하다는 전제를 조회에 반영했다. 주제를 빼고 조회하는 경로가 남아 있는지는 세지 않았다.
|
||||
|
||||
<!-- body:end -->
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
---
|
||||
kind: CASE
|
||||
slug: a-slug-rule-that-threw-korean-away
|
||||
title: slug 생성이 한글을 버려 주제 만들기가 간헐적으로 실패했다
|
||||
topic: addresses-frozen-at-publish-time
|
||||
topicName: 주소가 만들어지고 굳어지는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
lastVerifiedOn: 2026-09-04
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§13.6
|
||||
---
|
||||
|
||||
# slug 생성이 한글을 버려 주제 만들기가 간헐적으로 실패했다
|
||||
|
||||
주제 만들기가 간헐적으로 실패했다 — 「그 slug 를 가진 주제가 이미 있습니다」. 다른 이름으로 다시 하면 됐다. 규칙은 간헐적이었던 적이 없었고 보이지 않았을 뿐이다. slug 생성이 영문 소문자와 숫자만 남기고 나머지를 버려서, 한글 이름은 아무것도 기여하지 못했다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **계약은 앵커라고 적었고 만드는 쪽은 경로를 만들었다**
|
||||
주소를 만드는 다른 곳에서 난 사건이다.
|
||||
- **한 화면에 종류 이름이 아홉 개 떠 있었다 — 표가 여섯 벌이었다**
|
||||
이름을 다루는 다른 사건이다.
|
||||
- **서버가 준 주소는 라우트 표에 맞춰 보고, 맞는 라우트가 없으면 링크로 그리지 않는다**
|
||||
slug 가 주소의 재료라는 점에서 이어진다.
|
||||
|
||||
## 문제
|
||||
|
||||
주제를 만들면 가끔 「그 slug 를 가진 주제가 이미 있습니다」가 나왔다. 다른 이름으로 다시 하면 됐다.
|
||||
|
||||
같은 이름으로 두 번 만든 적은 없었다.
|
||||
|
||||
## 결론
|
||||
|
||||
간헐적으로 보인 것은 두 가지 결정적 어긋남이었고, 사용자는 둘 다 만났다.
|
||||
|
||||
`인증` : 남는 글자가 없어 빈 문자열 → 폼이 요청 전에 거절
|
||||
`Redis 캐시` 와 `Redis 클러스터` : 둘 다 `redis` → 두 번째가 충돌
|
||||
|
||||
> 규칙은 간헐적이었던 적이 없다. **보이지 않았을 뿐이다** — slug 생성이 `[a-z0-9]` 만 남기고 나머지를 버려서, 한글 이름은 아무것도 기여하지 못했다.
|
||||
|
||||
한글을 버리지 않고 로마자로 옮긴다. 음절을 초성·중성·종성으로 산술 분해하므로 표가 필요 없고 결정적이다.
|
||||
|
||||
`백엔드 아키텍처` → `baekendeu-akitekcheo`
|
||||
|
||||
국어의 로마자 표기법의 자모 대응만 적용하고 음운 변화 규칙은 일부러 뺐다. slug 는 읽는 것이지 발음하는 것이 아니고, 그 규칙을 넣으면 같은 이름이 문맥에 따라 다른 slug 가 된다.
|
||||
|
||||
## 검증 환경
|
||||
|
||||
tech-log-frontend : 5cffe30 · 7093d84
|
||||
변환 : 국어의 로마자 표기법의 자모 대응 · 음운 변화 규칙 제외
|
||||
확인 방식 : 한글 이름 여럿으로 주제를 만들어 생성된 slug 를 확인
|
||||
|
||||
## 재현 조건
|
||||
|
||||
1. 주제 이름을 `인증` 으로 적고 저장한다 — 옛 규칙에서는 빈 slug 가 되어 폼이 거절한다
|
||||
2. `Redis 캐시` 와 `Redis 클러스터` 를 차례로 만든다 — 옛 규칙에서는 두 번째가 충돌한다
|
||||
3. 새 규칙에서 같은 이름들의 slug 를 확인한다
|
||||
|
||||
## 본문
|
||||
|
||||
<!-- body:start -->
|
||||
|
||||
## 간헐적으로 보인 이유
|
||||
|
||||
slug 생성이 `[a-z0-9]` 만 남기고 나머지를 버렸다. 한글 이름은 통째로 사라지므로 이름에 영문이 얼마나 섞였는지에 따라 결과가 갈린다.
|
||||
|
||||
영문이 하나도 없으면 빈 문자열이 되어 폼이 요청 전에 거절한다. 영문이 앞에 붙어 있으면 그 부분만 남으므로 뒤가 다른 두 이름이 같은 slug 가 된다.
|
||||
|
||||
`Redis 캐시` 와 `Redis 클러스터` 가 둘 다 `redis` 였다. 두 번째를 만들 때 충돌이 났고, 사용자에게는 「가끔 안 된다」로 보였다.
|
||||
|
||||
## 산술 분해로 로마자를 만든다
|
||||
|
||||
한글 음절은 초성·중성·종성이 정해진 순서로 조합된 코드다. 음절 코드에서 세 값을 산술로 분해할 수 있으므로 변환표가 필요 없고 결과가 결정적이다.
|
||||
|
||||
`백엔드 아키텍처` → `baekendeu-akitekcheo`
|
||||
|
||||
## 음운 변화 규칙을 뺀 이유
|
||||
|
||||
국어의 로마자 표기법에는 자모 대응 외에 음운 변화 규칙이 있다. 그것을 넣지 않았다.
|
||||
|
||||
slug 는 읽는 것이지 발음하는 것이 아니다. 음운 변화를 적용하면 같은 이름이 앞뒤 글자에 따라 다른 slug 가 되고, 그러면 같은 이름을 두 번 만들 때 결과가 갈린다.
|
||||
|
||||
## 확인하지 못한 것
|
||||
|
||||
음운 변화 규칙을 빼서 같은 발음의 다른 이름이 다른 slug 가 된다. 그 충돌이 실제로 얼마나 자주 나는지는 재지 않았다.
|
||||
|
||||
<!-- body:end -->
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
---
|
||||
kind: CASE
|
||||
slug: an-address-frozen-at-publish-time
|
||||
title: 계약은 앵커라고 적었고 만드는 쪽은 경로를 만들었다 — 이미 저장된 행까지 고쳤다
|
||||
topic: addresses-frozen-at-publish-time
|
||||
topicName: 주소가 만들어지고 굳어지는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
lastVerifiedOn: 2026-09-04
|
||||
assets:
|
||||
- key: decision-path-404
|
||||
file: ../../../final/assets/tech-log-studio/decision-path-404.svg
|
||||
evidence:
|
||||
- ../../../final/evidence/raw/db/decision-path-after-v15.txt
|
||||
- ../../../final/evidence/raw/api/decision-anchor-fixed.txt
|
||||
- ../../../final/evidence/raw/audit/dead-link-sweep.txt
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§9.2
|
||||
---
|
||||
|
||||
# 계약은 앵커라고 적었고 만드는 쪽은 경로를 만들었다 — 이미 저장된 행까지 고쳤다
|
||||
|
||||
공개 화면의 「다음에 읽을 것」 두 번째 항목이 404 였다. 계약은 결정의 공개 주소가 목록 위의 앵커라고 이미 적어 두었는데, 주소를 만드는 두 곳이 그 대신 별도 경로를 만들고 있었다. 주소는 게시할 때 만들어 DB 에 저장되므로 코드만 고치면 이미 게시된 링크는 깨진 채 남는다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **서버가 준 주소는 라우트 표에 맞춰 보고, 맞는 라우트가 없으면 링크로 그리지 않는다**
|
||||
이 사건에서 세운 두 겹 가드다.
|
||||
- **결정에는 상세 화면이 없어 목록 항목이 문서 전체를 실어야 했다**
|
||||
같은 앵커 구조에서 난 계약 쪽 사건이다.
|
||||
- **축 링크가 자기 자신을 가리켰고, 고친 뒤에는 백엔드를 먼저 배포했다**
|
||||
같은 시기에 주소를 옮기다 난 다른 사건이다.
|
||||
|
||||
## 문제
|
||||
|
||||
`/references/external-idp-federation-application-boundary` 의 「다음에 읽을 것」 두 번째 항목이 404 였다.
|
||||
|
||||
화면 코드 어디에도 그 주소를 만드는 곳이 없다. 주소는 게시할 때 서버가 만들어 DB 에 저장한 문자열이고, 화면은 그것을 그대로 링크로 그린다.
|
||||
|
||||
## 결론
|
||||
|
||||
결정에는 상세 화면이 없고 공개 라우트는 목록 하나뿐인데, 게시할 때 만든 주소는 목록 아래에 slug 를 붙인 경로였다.
|
||||
|
||||
계약 : 공개 주소가 앵커라고 이미 적혀 있었다
|
||||
게시 시점 : 앵커가 아니라 경로를 만들어 저장했다
|
||||
조회 시점 : 저장된 주소를 읽어 링크로 내보냈다
|
||||
방문자 : 맞는 라우트가 없어 404
|
||||
|
||||
고친 것은 넷이다.
|
||||
|
||||
두 곳이 앵커를 만들게 했다
|
||||
이미 게시된 행도 V15 마이그레이션에서 함께 고쳤다 — 코드만 고치면 기존 링크는 깨진 채 남는다
|
||||
공개 라우트의 slug 를 앵커가 있으면 그 뒤를 조각으로 읽게 했다
|
||||
목록 항목이 앵커를 달 수 있도록 계약에 slug 를 더하고, 화면이 그 slug 를 element id 로 달고 앵커로 들어오면 데이터를 받아 그린 뒤 스크롤하게 했다
|
||||
|
||||
배포 후 서버가 내보내는 주소 26개와 주제·축 9개를 더해 35개 전부 200 인 것을 확인했다.
|
||||
|
||||
## 검증 환경
|
||||
|
||||
tech-log-design-package : 1aae8dc
|
||||
tech-log-backend : 8cd8ee3 · V15 마이그레이션 적용
|
||||
tech-log-frontend : fe6b56a
|
||||
확인 방식 : 배포본에서 서버가 내보내는 주소를 전수로 훑어 상태 코드를 셌다
|
||||
|
||||
## 재현 조건
|
||||
|
||||
1. 결정을 하나 게시하고 다른 기록에서 그것을 관계로 건다
|
||||
2. 공개 화면에서 그 관계 링크를 누른다
|
||||
3. 저장된 주소와 공개 라우트 패턴을 대조한다 — 맞는 라우트가 없으면 404 다
|
||||
|
||||
## 본문
|
||||
|
||||
<!-- body:start -->
|
||||
|
||||
## 주소가 만들어져 저장되고 방문에서 끝난다
|
||||
|
||||
:::evidence key="decision-path-404" alt="계약·게시 시점 경로 생성·저장 테이블·조회 시점 경로 생성·방문자·공개 라우트 여섯 참가자 사이의 순서도" caption=" " zoom="true"
|
||||
:::
|
||||
|
||||
계약은 결정의 공개 주소가 앵커라고 규정한다. 게시 시점의 `PublicPaths.forKind` 는 그 대신 경로를 만들어 `public_resource_projection` 에 저장한다. 조회 시점의 `PublicSql.pathOf` 가 저장된 주소를 읽고 방문자에게 링크로 내보낸다. 방문자가 그 주소를 요청하면 공개 라우트에는 목록 하나뿐이라 맞는 라우트가 없다.
|
||||
|
||||
## 계약은 이미 맞게 적혀 있었다
|
||||
|
||||
이 사건에서 계약은 고칠 것이 없었다. 공개 주소가 `#{slug}` 앵커라는 것이 계약에 있었고, 만드는 쪽 두 곳이 그것을 따르지 않았다.
|
||||
|
||||
## 저장된 행까지 고쳐야 한다
|
||||
|
||||
주소가 게시 시점에 굳어져 저장되므로 코드만 고치면 이미 게시된 링크는 깨진 채 남는다. V15 마이그레이션에서 저장된 행을 함께 고쳤다.
|
||||
|
||||
`public_route.slug` 도 함께 손봤다. 마지막 슬래시 뒤를 자르면 앵커가 붙은 주소에서 `decisions#slug` 전체가 slug 로 저장된다. 앵커가 있으면 그 뒤를 조각으로 읽게 했다.
|
||||
|
||||
## 두 겹 가드
|
||||
|
||||
`PublicPathsTest` 는 백엔드에서 종류마다 만들어 낸 경로가 실제 공개 라우트 패턴에 맞는지 본다.
|
||||
|
||||
`resolvesToPublicRoute` 는 프론트에서 라우트 계약이 준 표에 서버가 준 주소를 맞춰 보고, 맞는 라우트가 없으면 링크로 그리지 않는다. 이 부류가 또 생겨도 방문자가 404 를 만나지는 않는다.
|
||||
|
||||
## 배포 뒤 전수 감사
|
||||
|
||||
배포 후 사이트 전체를 훑어 서버가 내보내는 주소 26개와 주제·축 9개를 더해 35개 전부 200 인 것을 확인했다.
|
||||
|
||||
:::evidence key="dead-link-sweep" alt="서버가 내보내는 주소 35개를 전수로 훑은 감사 출력" caption=" " zoom="false"
|
||||
:::
|
||||
|
||||
## 확인하지 못한 것
|
||||
|
||||
이 감사는 서버가 내보내는 주소만 본다. 본문 안에 작성자가 손으로 쓴 링크는 대상이 아니다.
|
||||
|
||||
<!-- body:end -->
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
---
|
||||
kind: PROJECT_DECISION
|
||||
slug: a-new-route-ships-frontend-first
|
||||
title: 새 라우트는 프론트엔드를 먼저 배포한다
|
||||
topic: addresses-frozen-at-publish-time
|
||||
topicName: 주소가 만들어지고 굳어지는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
decisionStatus: ADOPTED
|
||||
decidedOn: 2026-09-01
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§9.1
|
||||
---
|
||||
|
||||
# 새 라우트는 프론트엔드를 먼저 배포한다
|
||||
|
||||
새 라우트를 여는 변경은 프론트엔드를 먼저 배포한다. nginx 설정이 라우트 계약에서 생성되므로, 프론트가 배포되기 전까지 그 경로는 엣지에서 404 다. 백엔드를 먼저 배포하면 서버는 이미 그 주소를 내보내고 사용자는 전부 404 인 화면을 본다.
|
||||
|
||||
## 근거
|
||||
|
||||
- **축 링크가 자기 자신을 가리켰고, 고친 뒤에는 백엔드를 먼저 배포했다**
|
||||
이 순서를 정하게 된 사건이다. 반대 순서로 배포해 사용자가 네 링크 전부 404 인 화면을 봤다.
|
||||
- **nginx 가 모르는 라우트는 새로고침에서 404 다**
|
||||
엣지가 왜 그 경로를 모르는지가 그 기록에 있다.
|
||||
- **catch-all 라우트는 nginx 패턴으로 번역하지 않는다**
|
||||
이 순서가 필요해진 이유가 그 결정에 있다.
|
||||
|
||||
## 결정문
|
||||
|
||||
새 공개 라우트를 여는 변경은 프론트엔드를 먼저 배포하고, 그 주소를 내보내는 백엔드 변경을 다음 배포에 넣는다.
|
||||
|
||||
## 판단 이유
|
||||
|
||||
nginx 설정은 라우트 계약에서 생성된다. 프론트 이미지가 배포되기 전까지 그 경로는 서빙 패턴에 없고, 엣지에서 404 로 끝난다.
|
||||
|
||||
백엔드를 먼저 배포하면 서버는 이미 그 주소를 링크로 내보낸다. 방문자는 화면에 그려진 링크를 누르고 404 를 만난다. 축 화면을 만들 때 실제로 그렇게 배포했고 사용자가 네 링크 전부 404 인 화면을 봤다.
|
||||
|
||||
catch-all 을 서빙 패턴으로 번역하지 않기로 했으므로 이 구간이 soft 200 으로 덮이지 않는다. 그 결정과 이 순서는 함께 간다.
|
||||
|
||||
## 영향
|
||||
|
||||
새 주소를 내보내는 백엔드 변경이 한 배포 늦게 나간다. 두 저장소를 한 번에 배포하고 싶은 변경에서 그 사이가 벌어진다.
|
||||
|
||||
프론트를 먼저 배포한 뒤에는 그 경로가 열려 있지만 서버가 아직 그 주소를 내보내지 않는다. 이 구간에서는 화면에 링크가 그려지지 않으므로 방문자에게 보이는 문제가 없다.
|
||||
|
||||
배포 순서를 사람이 기억해야 한다. 이 순서를 강제하는 검사는 없다.
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: do-not-draw-a-link-that-does-not-resolve
|
||||
title: 서버가 준 주소는 라우트 표에 맞춰 보고, 맞는 라우트가 없으면 링크로 그리지 않는다
|
||||
topic: addresses-frozen-at-publish-time
|
||||
topicName: 주소가 만들어지고 굳어지는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
verifiedOn: 2026-09-04
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§9.2
|
||||
---
|
||||
|
||||
# 서버가 준 주소는 라우트 표에 맞춰 보고, 맞는 라우트가 없으면 링크로 그리지 않는다
|
||||
|
||||
주소를 서버가 만들어 내보내고 화면이 그대로 링크로 그리면, 그 주소가 틀렸다는 것은 방문자만 안다. 화면 코드 어디에도 그 주소가 없기 때문이다. 만드는 쪽과 그리는 쪽 양쪽에서 라우트 표와 맞춘다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **계약은 앵커라고 적었고 만드는 쪽은 경로를 만들었다**
|
||||
이 기준의 근거 사건이다.
|
||||
- **catch-all 라우트는 nginx 패턴으로 번역하지 않는다**
|
||||
엣지의 404 가 감사에 남아야 이 기준이 성립한다.
|
||||
- **라우트에 딸린 목록은 라우트 계약에서 유도하고, 유도할 수 없는 것은 대조 검사를 둔다**
|
||||
라우트 표가 어디서 오는지가 그 기준에 있다.
|
||||
|
||||
## 목적
|
||||
|
||||
서버가 만든 주소가 열리지 않는 것을 방문자보다 먼저 잡는다. 이 부류는 화면 코드에 흔적이 없어 저장소 안의 링크 리터럴을 훑는 감사로는 잡히지 않는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
**만드는 쪽에서 생성한 경로를 공개 라우트 패턴에 맞춘다**
|
||||
종류마다 만들어 낸 주소가 실제 라우트에 걸리는지 백엔드 테스트가 본다.
|
||||
|
||||
**그리는 쪽에서 서버가 준 주소를 라우트 표에 맞추고, 맞는 라우트가 없으면 링크로 그리지 않는다**
|
||||
같은 부류가 또 생겨도 방문자가 404 를 만나지는 않는다.
|
||||
|
||||
**주소를 고쳤으면 이미 저장된 행도 함께 고친다**
|
||||
주소가 게시 시점에 굳어져 저장되면 코드만 고쳐도 기존 링크는 깨진 채 남는다.
|
||||
|
||||
**배포 뒤 서버가 내보내는 주소를 전수로 훑는다**
|
||||
저장소를 훑는 감사와 다른 것을 본다. 실제로 나가는 주소는 DB 에 있다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
주소를 서버가 만들어 내보내고 화면이 그대로 링크로 그리는 구조. 게시 시점에 주소가 굳어져 저장되면 특히 걸린다.
|
||||
|
||||
## 예외
|
||||
|
||||
외부 주소는 라우트 표에 없으므로 이 대조의 대상이 아니다.
|
||||
|
||||
그리는 쪽에만 가드를 두면 링크가 아예 그려지지 않는 것으로 끝나고 원인이 남는다. 만드는 쪽에도 같은 검사를 둔다.
|
||||
|
||||
## 예시
|
||||
|
||||
결정 링크가 404 였다. 계약은 앵커라고 적었고 만드는 두 곳이 경로를 만들었다.
|
||||
|
||||
배포 후 서버가 내보내는 주소 26개와 주제·축 9개를 더해 35개 전부 200 인 것을 확인했다.
|
||||
|
||||
저장소 안의 링크 리터럴을 훑는 감사로는 이 결함이 잡히지 않았다. 그 주소는 코드에 없다.
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
---
|
||||
kind: REFERENCE
|
||||
slug: write-down-what-would-undo-a-workaround
|
||||
title: 우회를 남길 때는 되돌릴 조건을 함께 적는다
|
||||
topic: addresses-frozen-at-publish-time
|
||||
topicName: 주소가 만들어지고 굳어지는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
verifiedOn: 2026-09-04
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§9.4
|
||||
---
|
||||
|
||||
# 우회를 남길 때는 되돌릴 조건을 함께 적는다
|
||||
|
||||
그 화면이 줄 수 있는 것이 아직 비어 있어 링크를 다른 곳으로 돌린 적이 있다. 우회 자체는 틀리지 않았다. 문제는 우회를 남겨 두면 「왜 이 링크가 저기로 가지?」라는 질문이 계속 남는다는 것이다. 우회할 때 되돌릴 조건을 함께 적는다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **축 링크가 자기 자신을 가리켰고, 고친 뒤에는 백엔드를 먼저 배포했다**
|
||||
같은 주제 링크를 다루며 이 기준이 나왔다.
|
||||
- **홈의 비교 구역이 세 번 바뀌었다**
|
||||
단계마다 무엇을 고치려 했는지 적어 둔 다른 예다.
|
||||
- **새 라우트는 프론트엔드를 먼저 배포한다**
|
||||
같은 사건에서 나온 짝이 되는 결정이다.
|
||||
|
||||
## 목적
|
||||
|
||||
임시 조치가 영구 구조로 굳는 것을 막는다. 되돌릴 조건이 적혀 있지 않으면 다음 사람이 그 우회를 설계로 읽는다.
|
||||
|
||||
## 규칙
|
||||
|
||||
**우회를 넣는 커밋에 되돌릴 조건을 적는다**
|
||||
무엇이 채워지면 되돌리는지 한 줄로 적는다. 그 조건이 충족됐을 때 실제로 되돌린다.
|
||||
|
||||
**우회할 때 무엇이 비어 있어서 우회하는지 함께 적는다**
|
||||
채울 것이 없어서 돌린 것과 구조상 그쪽이 맞아서 돌린 것은 다르다.
|
||||
|
||||
**되돌릴 생각이 없으면 우회가 아니라 결정으로 적는다**
|
||||
그때는 조건이 아니라 근거와 감수한 비용을 적는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
그 화면이 줄 수 있는 것이 아직 비어 있어 링크나 흐름을 다른 곳으로 돌릴 때.
|
||||
|
||||
## 예외
|
||||
|
||||
되돌릴 생각이 없는 영구 변경은 우회가 아니다. 조건 대신 근거를 적는다.
|
||||
|
||||
조건을 적을 수 없으면 그것은 우회가 아니라 아직 정하지 않은 것이다. 열린 질문으로 남긴다.
|
||||
|
||||
## 예시
|
||||
|
||||
주제 화면이 주제 셋을 하드코딩해 두고 있어 실제 주제는 무엇이든 404 였다. 그때 주제 페이지를 채우는 대신 링크를 탐색 필터로 돌렸다.
|
||||
|
||||
돌린 이유는 그 페이지만 줄 수 있는 것 — 설명, 범위, 선별한 대표 기록 — 이 전부 비어 있었고 Studio 에 주제 설명을 쓸 칸조차 없었기 때문이다.
|
||||
|
||||
그 조건을 커밋 메시지에 적었고, 주제 화면을 계약에 잇고 하드코딩을 없앤 뒤 링크를 곧장 주제 화면으로 되돌렸다.
|
||||
Reference in New Issue
Block a user