refactor: 분리되어 관리하고 있던 문서 시스템을 하나로 통일
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
결정(PROJECT_DECISION)의 공개 주소 — V15 마이그레이션 적용 후
|
||||
출처: hyeonworks-prod / postgres-0 / appdb — 2026-09-04 조회
|
||||
|
||||
배경: 게시 시점에 만든 주소가 /projects/{slug}/decisions/{slug} 였는데 그런 라우트가
|
||||
없어 다른 기록이 건 링크가 404 였다. 계약은 이미 #{slug} 앵커라고 적어 두었다.
|
||||
주소는 게시 시점에 굳어져 저장되므로 코드만 고치면 기존 행은 깨진 채 남는다 —
|
||||
그래서 V15 가 이미 게시된 행도 함께 고쳤다.
|
||||
|
||||
V15 의 UPDATE:
|
||||
UPDATE public_resource_projection
|
||||
SET navigation_path = regexp_replace(navigation_path,
|
||||
'^(/projects/[^/]+/decisions)/', '\1#')
|
||||
WHERE resource_type = 'PROJECT_DECISION'
|
||||
AND navigation_path ~ '^/projects/[^/]+/decisions/';
|
||||
----------------------------------------------------------------------
|
||||
[현재] public_resource_projection 의 PROJECT_DECISION 행
|
||||
/projects/keycloak-patterns/decisions#bff-owns-token-when-browser-must-not ← BFF가 OAuth Token을 관리하는 조건
|
||||
/projects/keycloak-patterns/decisions#federation-is-not-an-application-pattern ← 외부 IdP와의 연동이라도 별도의 인증 방식이 아니다.
|
||||
|
||||
[현재] publication.public_path
|
||||
/projects/keycloak-patterns/decisions#bff-owns-token-when-browser-must-not
|
||||
/projects/keycloak-patterns/decisions#federation-is-not-an-application-pattern
|
||||
|
||||
[적용된 마이그레이션] flyway_schema_history 의 V14/V15
|
||||
14 | techlog topic variant | true
|
||||
15 | techlog decision anchor path | true
|
||||
@@ -0,0 +1,64 @@
|
||||
작업본 삭제를 막는 참조 — 실제 사례와 그 해소
|
||||
출처: hyeonworks-prod / postgres-0 / appdb
|
||||
진단 시각: 2026-09-04 (아래 [1]~[4])
|
||||
사후 확인: 2026-09-04, 사용자가 조치한 뒤 (아래 [5])
|
||||
|
||||
증상
|
||||
「DTO 변환 과정에서 발생한 Highlight 컬렉션 N+1」을 지우려는데, 관계를 다 지웠는데도
|
||||
삭제가 안 된다.
|
||||
|
||||
삭제 가드가 보는 다섯 테이블 (DeleteDocumentDraftUseCase → documentReferenced)
|
||||
SELECT 1 FROM document_relation WHERE target_document_id = :id
|
||||
UNION ALL SELECT 1 FROM question_document_link WHERE document_id = :id
|
||||
UNION ALL SELECT 1 FROM project_document_link WHERE document_id = :id ← 여기서 걸림
|
||||
UNION ALL SELECT 1 FROM topic_featured_document WHERE document_id = :id
|
||||
UNION ALL SELECT 1 FROM project_decision WHERE source_case_id = :id
|
||||
|
||||
다섯 이유가 전부 같은 한 문장으로 나온다:
|
||||
"another record still links to this one; unlink it first"
|
||||
「another record」라고 하니 관계를 찾아 지우게 되는데, 정작 막는 것은 record 가 아니라
|
||||
프로젝트 연결이다. 그리고 프로젝트 연결은 「관계」 편집기가 아니라 문서의 Project 필드다.
|
||||
|
||||
======================================================================
|
||||
[1] 대상 문서 (진단 시점 캡처)
|
||||
|
||||
58c2d5d9-5865-4b2c-b1cc-3c5c955c33dc | CASE | collection-nplus1-dto-mapping
|
||||
| DRAFT | PRIVATE | DTO 변환 과정에서 발생한 Highlight 컬렉션 N+1
|
||||
|
||||
→ workflow_status=DRAFT, target_visibility=PRIVATE 이고 publication /
|
||||
public_resource_projection / public_route 에 행이 없다. 즉 게시 가드는 통과한다.
|
||||
|
||||
[2] 이 문서 id 를 참조하는 행 — uuid 컬럼 전수 스캔 (진단 시점 캡처)
|
||||
|
||||
NOTICE: project_document_link . document_id => 1 행
|
||||
NOTICE: document . id => 1 행
|
||||
NOTICE: case_detail . document_id => 1 행
|
||||
|
||||
→ 셋뿐이다. document(자신), case_detail(본문), 그리고 project_document_link 1행.
|
||||
|
||||
[3] 막고 있는 그 행의 정체 (진단 시점 캡처)
|
||||
|
||||
relation_type=PRIMARY | featured_order=- | project=Liner N + 1문제
|
||||
|
||||
→ relation_type 이 PRIMARY 이므로 ProjectLinkStore.setPrimary() 의 DELETE 대상이다.
|
||||
즉 Studio 에서 Project 를 「미지정」으로 바꿔 저장하면 이 행이 지워진다.
|
||||
(setPrimary 는 relation_type='PRIMARY' 인 행만 지운다. 만약 이 행이 RELATED 였다면
|
||||
화면에서 풀 방법이 없어 진짜로 막혔을 것이다 — 그 경우는 아니었다.)
|
||||
|
||||
[4] document_relation 은 실제로 비어 있었다 (진단 시점 캡처)
|
||||
|
||||
document_relation 참조 행 수: 0
|
||||
|
||||
→ 사용자가 관계를 다 지운 것이 맞다. 관계는 문제가 아니었다.
|
||||
|
||||
======================================================================
|
||||
[5] 사후 확인 — 사용자가 Project 를 미지정으로 바꾸고 삭제한 뒤
|
||||
document 행: 0
|
||||
project_document_link 행: 0
|
||||
case_detail 행: 0
|
||||
|
||||
→ 삭제가 통과했다. 진단이 맞았다는 것이 이것으로 확인된다 — 프로젝트 연결을 푸는 것이
|
||||
막힘의 해소였다.
|
||||
|
||||
주의: 그래서 이 결함은 이제 실시간으로 재현할 수 없다. [1]~[4] 는 진단 당시의 캡처이고
|
||||
[5] 만 지금 다시 조회한 값이다.
|
||||
@@ -0,0 +1,34 @@
|
||||
축에 실제로 걸린 기록 (record_variant)
|
||||
출처: hyeonworks-prod / postgres-0 / appdb — 2026-09-04 조회
|
||||
쿼리: topic_variant JOIN record_variant, 제목은 public_resource_projection 에서
|
||||
칸: variant.slug | record_kind | 기록 제목
|
||||
메모: record_variant 는 외래키가 없다 — 기록이 종류마다 다른 테이블에 살아
|
||||
(kind, id) 쌍으로 가리키기 때문이다(document / open_question / project_decision).
|
||||
----------------------------------------------------------------------
|
||||
bff | CASE | Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정
|
||||
bff | QUESTION | 서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가
|
||||
bff | QUESTION | BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가
|
||||
bff | QUESTION | Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가
|
||||
bff | REFERENCE | BFF 인증 구조 설계 기준
|
||||
derived-query | CASE | Fetch 타입이 아닌 조회 방식으로 인한 N+1
|
||||
fetch-join | CASE | Collection Fetch Join으로 N+1을 해결하다 만난 MultiBag예외와 행 폭증 문제
|
||||
fetch-join-paging | CASE | Collection Fetch Join Pagination의 In-memory Paging
|
||||
forward-auth | CASE | Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유
|
||||
forward-auth | QUESTION | Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가
|
||||
forward-auth | REFERENCE | Forward-Auth에서 Identity Header를 신뢰하기 위한 조건
|
||||
mediator | CASE | Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출
|
||||
mediator | QUESTION | 서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가
|
||||
mediator | QUESTION | Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가
|
||||
mediator | REFERENCE | Authorization Code Flow의 Endpoint와 Credential 이동 기준
|
||||
mediator | REFERENCE | Public Client와 Confidential Client 구분 기준
|
||||
spa | CASE | SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계
|
||||
spa | REFERENCE | Authorization Code Flow의 Endpoint와 Credential 이동 기준
|
||||
spa | REFERENCE | 외부 IdP 연동과 Application 인증 구조의 경계
|
||||
spa | REFERENCE | Public Client와 Confidential Client 구분 기준
|
||||
|
||||
=== 어느 축에도 걸리지 않은 기록 (= 그 주제의 공통 기록) ===
|
||||
oauth-oidc-auth-boundary | CONCEPT | 외부 IdP Brokering의 동작
|
||||
oauth-oidc-auth-boundary | PROJECT_DECISION | BFF가 OAuth Token을 관리하는 조건
|
||||
oauth-oidc-auth-boundary | PROJECT_DECISION | 외부 IdP와의 연동이라도 별도의 인증 방식이 아니다.
|
||||
oauth-oidc-auth-boundary | REFERENCE | OAuth Token과 Application Session을 구분하는 기준
|
||||
oauth-oidc-auth-boundary | REFERENCE | OAuth/OIDC 인증 패턴 선택 기준
|
||||
@@ -0,0 +1,12 @@
|
||||
주제와 축(topic / topic_variant)의 실제 행
|
||||
출처: hyeonworks-prod / postgres-0 / appdb — 2026-09-04 조회
|
||||
쿼리: topic LEFT JOIN topic_variant, display_order 순
|
||||
칸: topic.slug | topic.variant_label | display_order | variant.slug | variant.title
|
||||
----------------------------------------------------------------------
|
||||
jpa-feed-query-performance | 조회 전략 | 1 | derived-query | 파생 쿼리 그대로
|
||||
jpa-feed-query-performance | 조회 전략 | 2 | fetch-join | 컬렉션 fetch join
|
||||
jpa-feed-query-performance | 조회 전략 | 3 | fetch-join-paging | fetch join + 페이징
|
||||
oauth-oidc-auth-boundary | 구조 | 1 | spa | SPA
|
||||
oauth-oidc-auth-boundary | 구조 | 2 | mediator | Mediator
|
||||
oauth-oidc-auth-boundary | 구조 | 3 | bff | BFF
|
||||
oauth-oidc-auth-boundary | 구조 | 4 | forward-auth | Forward-Auth
|
||||
Reference in New Issue
Block a user