A code-to-column change-impact knowledge graph for AI coding agents.
| English | 한국어 |
cascade view 는 MCP 서버가 쓰는 바로 그 도구 카탈로그 위에서 로컬 웹 앱
하나를 띄웁니다. 이 페이지는 질의를 다시 구현하지 않습니다. 화면의 모든 숫자는
엔진이 계약을 지켜 만든 답으로 도착하므로, 이 페이지와 MCP 로 묻는 모델이 서로
다른 이야기를 들을 수 없습니다.
node bin/cascade.mjs view # every registered project
node bin/cascade.mjs view --project mall # just this one
node bin/cascade.mjs view --pack .cascade/pack # one pack directly
# → http://127.0.0.1:4319/
페이지에는 머리글과 여덟 개의 탭이 있고, 그 전부를 관통하는 규칙이 하나 있습니다. 한눈에 보는 것은 숫자나 그림이고, 한 줄짜리 글은 한 문장이며, 문단 전체는 한 번의 클릭 뒤에 있고 스스로 열리지 않습니다.
맨 윗줄은 데이트라인입니다. 어느 프로젝트가 답했는지, 그 다이제스트, 어떤
분석기가 돌았는지, 어느 커밋으로 만들었는지입니다. 그 아래로 이 엔진이 따라가는
체인이 단계마다 개수를 달고 흐릅니다. 화면, api 그룹, 엔드포인트, 서비스, SQL,
테이블, 컬럼입니다. 이 개수는 overview 답 자신의 것이며 페이지는 아무것도
세지 않습니다.
그 옆에 칩이 셋 있습니다.
그다음이 언어 토글과 테마 토글입니다.
모든 탭의 툴바 아래에는 한 줄짜리 리드가 있습니다. 갈매기표를 누르면 문단이 열립니다. 이 탭이 무엇을 위한 것인지, 그림을 어떻게 읽는지, 엔진이 무엇을 증명하지 못했는지입니다. 접는다고 지워지는 것은 없습니다. 개수는 언제나 접힘 바깥에 남습니다. 한눈에 보라고 있는 것이 개수이기 때문입니다.
각 접힘은 여러분이 열어 둔 상태를 localStorage 에 접힘 단위로 기억합니다.
언어를 바꾸면 블록을 카탈로그에서 다시 만들면서도 여러분이 둔 상태 그대로
돌려 놓습니다.
하나의 토큰 위에 테마 둘이 있고, 토글은 머리글에 있습니다.
선택은 여러분의 것이고 기억됩니다(cascade.viewer.theme). prefers-color-scheme
는 보지 않습니다. 제품에는 기본값이 있고 그것을 여러분이 덮는 것이지, 이 페이지의
생김새를 운영체제가 정하는 것이 아니기 때문입니다.
상단의 다이얼 넷은 overview 답의 reach 에서 옵니다. 몇 개의 엔드포인트가
SQL 에 닿는지, 몇 개의 statement 와 테이블과 컬럼이 닿았는지입니다. 각 숫자
아래에는 그 단계의 용어로 무엇이 빠졌는지가 적혀 있습니다. 비율은 나머지와
나란히 놓일 때만 뜻이 있기 때문입니다.
다이얼 옆은 지도입니다. Graph 탭이 쓰는 바로 그 map 답으로 그린, 높이를 줄인
살아 있는 프로젝트 전체 지도입니다. 한 번만 물어 공유하므로 Graph 탭을 열어도
다시 가져오지 않습니다. 노드에 커서를 올리면 체인 하나에 불이 들어오고, 누르면
고정되고, 더블클릭하면 Graph 탭에서 엽니다.
그 아래 접힘 하나에 캐스케이드 리본이 있습니다. 체인의 단계마다 막대 하나이고, 진한 부분이 엔드포인트가 닿는 것, 줄무늬 부분이 아무것도 닿지 않는 것이며, 막대 사이의 띠가 얼마나 이월되는지를 보여 줍니다. 그 아래로 pack 안에 무엇이 있는지, 타입과 등급별 엣지, Java 쪽, 허브 테이블과 엔드포인트, 그리고 엔진이 못 본 것이 패널로 놓입니다.
Explore, Flow, Impact 는 빈 검색창이 아니라 목록으로 열립니다. 왼쪽 열에 그
탭이 보여 줄 수 있는 종류와 개수, 필터, 정렬, 개수 줄, 그리고 고를 때 근거가 될
숫자가 붙은 행들이 있습니다. 모든 행과 모든 숫자는 하나의 browse 답이므로
페이지는 아무것도 세지 않습니다. 입력창에 치면 이미 들고 있는 행을 걸러 낼 뿐
요청을 보내지 않습니다. 정확한 이름을 넣고 Enter 를 누르면 예전처럼 서버에
묻습니다. / 는 필터로 커서를 옮기고, 방향키가 강조를 옮기고, Enter 가 고릅니다.
1100px 아래에서는 레일이 Browse 버튼 뒤의 서랍이 되며, 하나를 고르거나
Escape 를 누르면 닫힙니다.
Flow 는 엔드포인트를 각자가 속한 API 그룹 아래로 묶습니다. Impact 는 테이블마다 캐럿을 주어 그 테이블의 컬럼으로 펼치며, 테이블당 한 번의 요청이므로 테이블에서 바꾸려는 컬럼까지 걸어 내려갈 수 있습니다. 아무것도 고르지 않은 상태에서는 오른쪽에 한 문장과, 이미 불러온 목록에서 가장 바쁜 행 다섯 개가 놓입니다.
레일에서 statement 와 메서드는 짧은 이름으로 읽힙니다
(PmsProductDao.getUpdateInfo, OmsPortalOrderController#generateOrder). 체인
레인과 그래프 카드가 쓰는 것과 같은 이름입니다. 320px 에서 완전한 이름은 모든
행이 공유하는 패키지 접두사에 한 줄을 다 쓰고, 말줄임표가 정작 구분되는 부분을
먹어 버립니다. 전체 id 는 행의 툴팁에 있고 필터가 대조하는 것도 여전히 전체
id 이므로, 패키지 이름을 치면 그 행들이 찾아집니다.
그림이 주장이라면 소스는 증거입니다. 창 하나가 그것을 머리글 아래 오른쪽
가장자리에 붙여 보여 주고, 예전에 저마다 작은 코드 상자를 그리던 자리는 이제
모두 이 창을 엽니다. Explore 의 statement 나 메서드 행, Flow 와 Impact 행
카드의 Source 버튼, 그래프 노드 카드의 같은 버튼, 그리고 Transactions 의
경계입니다. GET /api/source 로 디스크의 파일을 읽으므로 pack 에 구워 넣은
사본이 아니라 지금 그 자리에 있는 내용을 보여 줍니다.
파일 자신의 줄 번호를 달고, 답이 가리키는 줄을 막대와 색조로 표시하며, 위로 세
줄의 맥락을 두고 그 위치로 스크롤합니다. 헤더는 노드와 경로와 줄을 이름으로
말하고(누르면 path:line 을 복사합니다), 언어와 범위를 밝힙니다. snippet 은
메서드나 statement 만 따로 보여 주고 whole file 은 그 주변 파일 전체를
가져오면서 같은 줄 표시를 유지합니다. f 가 키보드로 같은 일을 하고, j/k 와
방향키가 한 줄씩 스크롤하고, Escape 가 닫습니다. Open in editor 는 옆의
셀렉트가 지정한 편집기에서 그 줄로 파일을 엽니다. vscode://file/<path>:<line>:1
이나 idea://open?file=<path>&line=<line> 이며, none 이면 버튼이 절대 경로를
복사합니다. 창의 왼쪽 모서리를 끌어 420px 부터 창 너비의 90% 까지 크기를 바꿀 수
있고, 너비와 편집기는 기억됩니다.
배경 가림막은 일부러 없습니다. 이 창은 IDE 의 미리보기처럼 동작합니다. 여러분이 요청할 때만 열리고, 그다음부터는 여러분이 아래에서 계속 클릭하는 동안 제자리에서 고르는 행마다 따라옵니다. 한 번 닫으면 다시 요청할 때까지 닫혀 있습니다.
좁힐 수 있는 모든 탭은 툴바 오른쪽 끝에 Show all 을 답니다. 그 탭이 이미 처음 상태이면 비활성이므로, 버튼 자체가 무언가 좁혀져 있는지도 알려 줍니다. 누르면 필터와 선택이 지워지고, 레일이 그 탭이 처음 열렸던 종류로 돌아가고, 빠른 선택 카드가 돌아오고, Flow 와 Impact 의 그림이 지워지고, Graph 지도가 접히면서 화면에 맞춰지고, ERD 강조가 사라지고, 소스 창이 닫힙니다.
Escape 가 탭 안 어디서든 같은 일을 합니다. 커서가 입력창 안에 있으면 두 번 눌러야 합니다. 첫 번째가 입력창을 비우고 두 번째가 탭을 되돌립니다. 이미 보고 있는 탭의 이름을 누르는 것도 같은 초기화입니다.
레일에서 테이블, 컬럼, statement, 엔드포인트, 메서드를 고르거나 이름 일부로 검색합니다. 컬럼을 고르면 그것을 읽거나 쓰는 SQL statement 와 그 위의 HTTP 엔드포인트가 각각 등급과 함께 나옵니다. My edits 는 커밋하지 않은 git 변경에 대해 같은 질문을 던집니다.
Flow 는 API 호출 하나를 왼쪽에서 오른쪽으로 읽습니다. 엔드포인트, 그것이 지날 수 있는 서비스 메서드, 그것들이 닿는 매퍼 statement, 그리고 끝의 테이블입니다. Impact 는 같은 기계를 컬럼, 테이블, statement, 메서드에서 거꾸로 돌려 거기에 닿을 수 있는 엔드포인트까지 올라갑니다.
실선 연결자는 엔진이 증명할 수 있는 호출이고, 점선은 일어난다고 보지만 확인하지 못한 호출입니다. 작은 점들이 걷기가 실제로 진행된 방향으로 각 연결자를 타고 흐릅니다. Flow 에서는 왼쪽에서 오른쪽, Impact 에서는 오른쪽에서 왼쪽입니다. 프레임 루프가 아니라 경로를 따라가는 SVG 모션이므로 탭이 숨어 있을 때 비용이 없습니다. 동작을 줄여 달라고 시스템에 설정한 독자에게는 정지한 화살촉만 보이고 애니메이션은 전혀 없습니다.
툴바에는 두 개의 보기가 있습니다. chain 은 경로 전체를 왼쪽에서 오른쪽으로 그리고, by hop 은 같은 행을 한 단계씩 묶어 홉마다 집계를 붙입니다.
두 API 그룹은 서로 호출하지 않고도 서로에게 의존할 수 있습니다. 한쪽이 컬럼을 쓰고 다른 쪽이 그것을 읽습니다. 행렬은 그 쌍을 보여 줍니다. 세로가 쓰는 쪽, 가로가 읽는 쪽입니다. 칸을 누르면 두 그룹이 공유하는 컬럼이나 테이블과, 그것을 나르는 statement 가 나옵니다.
Graph 탭은 프로젝트 전체 지도로 열립니다. 가만히 있을 때는 API 그룹과 테이블만 그리고, 그룹과 테이블을 잇는 선 하나가 그 그룹에서 그 테이블을 건드리는 모든 엔드포인트를 대표합니다. 그룹을 누르면 그 엔드포인트들이 위성처럼 펼쳐지고, 개수 줄이 아직 몇 개가 접혀 있는지 말해 줍니다. Find 는 찾아낸 것이 속한 그룹을 펼칩니다.
읽히게 만드는 규칙이 셋 있습니다. 노드 반지름은 차수의 제곱근을 따르므로 한 줄 짜리 테이블도 보이고 허브는 놓칠 수 없습니다. 라벨은 가장 바쁜 노드와 모든 그룹과 불이 켜진 것에 붙고, 1.6배를 넘겨 확대하면 전부에 붙습니다. 선은 체인에 불이 들어오기 전까지 조용합니다.
선 색은 그 엔드포인트가 테이블에 무엇을 하는지입니다. 읽기는 파랑, 쓰기와 삭제는 빨강입니다. 두께는 몇 개의 statement 가 그것을 나르는지이고, 2D 의 점선은 확인하지 못한 체인입니다. 칩은 종류 하나를 통째로 숨기면서 개수는 남깁니다. statement 칩은 엔진에 SQL 계층을 다시 묻습니다. 그 계층 없이는 엔진이 statement 를 하나도 보내지 않았기 때문입니다.
지도는 가만히 있을 때 움직이지 않습니다. 이 크기의 지도에서 모든 선 위의 점은 잡티이므로, 여러분이 무언가를 가리키기 전까지 선은 정지해 있습니다. 불을 켠 노드는 스스로 흐르고, Flow on 은 모든 선을 흐르게 합니다. 방향이 있는 링크가 2500 개를 넘으면 그마저도 불 켜진 체인으로 제한되며, 툴바가 그렇게 말합니다.
노드를 더블클릭하면 Around <node> 입니다. 가운데에 그 노드, 링 1 에 그것에 닿는 것, 링 2 에 다시 그것들에 닿는 것입니다. 가운데가 테이블이나 statement 일 때는 컬럼이 처음에 숨겨집니다. 그러지 않으면 그림의 대부분이 컬럼이 되기 때문입니다.
스키마 전체를 매퍼 SQL 이 테이블 사이에 만드는 조인으로 배치합니다. 외래 키는 읽지 않으므로, 여기의 관계는 어떤 statement 가 만드는 조인입니다. 테이블의 크기는 지도와 같은 제곱근 규칙으로 관계 수를 따르고, 라벨도 그에 맞춰 커집니다. 선이 두꺼우면 그 조인을 만드는 statement 가 더 많다는 뜻입니다. 어두운 테마에서는 이름 접두사를 공유하는 테이블들이 자기 종류 색조의 채도를 낮춘 색을 갖고 범례가 그것을 알려 줍니다. 밝은 테마는 잉크로 남습니다. 어떤 SQL 도 조인하지 않는 테이블은 버려지지 않고 지도 아래 띠에 그렇게 이름 붙여 놓입니다.
모든 @Transactional 메서드와, 그것을 통해 커밋 하나가 건드릴 수 있는
범위입니다.
서버는 여러분이 좁히지 않는 한 ~/.cascade/registry.json 의 모든 프로젝트를
서빙합니다. 페이지는 한 번에 한 프로젝트만 보여 줍니다. 어느 pack 에서 온
답인지 말하지 않는 답은 답이 없는 것보다 나쁘기 때문입니다.
<select>, 정확히
하나면 정적 라벨입니다. 고를 것이 없으니까요. 하나도 없으면 그렇다고 말하는
줄이 나오고 cascade init 과 cascade analyze 를 이름으로 알려 줍니다.Around <node> 와 ERD 렌더러가 해체되고, Graph 탭이 프로젝트 전체 지도로
돌아가고, Overview 를 다시 묻습니다. 프로젝트를 건너 재사용하는 것은
없습니다.GET /api/projects)은 지연 로딩입니다. 레지스트리만 읽고
그 밖에는 아무것도 읽지 않습니다. 프로젝트의 meta, 즉 다이제스트, 빌드
시각, 레인, 축, 최신성은 그 프로젝트가 실제로 무언가에 답하기 전까지 null
입니다. 거기의 null 은 “적재되지 않음”이지 “이 pack 은 할 말이 없음”이
아닙니다.페이지는 지금 보여 주는 것을 해시에 씁니다.
http://127.0.0.1:4319/#p=<project>&tab=<overview|explore|flow|impact|coupling|graph|erd|tx>
[&pick=<kind>:<id>][&src=<kind>:<id>]
새로 고치면 같은 프로젝트, 같은 탭, 같은 선택, 같은 소스 창으로 돌아오고, 그
링크를 다른 사람에게 보낼 수도 있습니다. 선택은 히스토리 항목을 쌓으므로 브라우저
뒤로 가기가 여러분이 그린 그림을 하나씩 되짚습니다. 메모리에 남아 있는 답은 서버에
다시 묻지 않고 다시 그립니다. 탭이나 프로젝트 변경은 항목을 쌓는 대신 바꿉니다.
둘 다 하나씩 되돌리고 싶은 단계가 아니기 때문입니다. 적재 시 프로젝트는 순서대로
해시, CLI 가 시작할 때 출력하는 ?project= 쿼리, 그다음 이 브라우저가 지난번에
고른 값(localStorage)에서 옵니다. 서버가 서빙하지 않는 프로젝트는 보내지 않고
무시하므로, 오류 대신 서빙 목록의 첫 프로젝트를 받게 됩니다.
모르는 프로젝트는 404, 여러 프로젝트를 서빙하는 서버에서 이름을 대지 않은
경우는 409 이며 둘 다 JSON 입니다. 페이지는 그것을 물어본 창 안의 배너로
그리며, 빈 패널을 남기지 않습니다. 메시지는 엔진 자신의 문장 그대로입니다.
머리글의 토글이 인터페이스 언어를 바꿉니다. 기본은 영어이고 선택은
localStorage 에 기억됩니다. 바꿔도 크롬만 다시 그리고 서버에는 아무것도 묻지
않습니다. 이미 화면에 있는 답은 움직이지 않습니다. 엔진의 말은 여러분의
인터페이스 언어에 따라 바뀌지 않기 때문입니다.
번역되는 것은 크롬, 즉 페이지가 스스로를 위해 쓴 모든 말입니다.
번역되지 않는 것은 엔진이 말한 모든 것입니다.
EXACT, SOUND_SET, HEURISTIC, RUNTIME_ONLY, UNRESOLVED)limits, 잘림 안내, empty 이유(not-shipped, not-in-this-axis)그 경계가 정직성 계약입니다. 번역된 등급은 이 프로젝트가 지어낸 등급입니다. 어떤 독자도 그것을 엔진의 답과 대조할 수 없고, 두 뷰어가 그 뜻에 합의할 수도 없습니다. 엔진의 말은 증거이고, 증거는 바꿔 쓰지 않고 인용합니다. 페이지가 그 말들 중 하나를 꺼내야 할 때는, 그것이 무엇을 뜻하는지 평범한 말로 한 번 설명한 다음 그대로 씁니다.
src/viewer/i18n.mjs 가 조회 함수(makeT, interpolate, richText)와
영어 카탈로그 VIEWER_STRINGS.en 을 들고 있습니다. 페이지는 그 블록을 그대로
복사해 들고 있습니다. 자기 완결적인 파일 하나라서 src/ 에서 import 할 수
없기 때문입니다. test/i18n.test.mjs 가 둘이 갈라지면 실패합니다.viewer/i18n/<lang>.json 이 다른 언어마다 하나씩입니다. /vendor 처럼
허용 목록 디렉터리에서 GET /i18n/<lang>.json 으로 나갑니다. .json 만,
그 디렉터리에서만, 빠져나가려는 모든 시도는 404 입니다.번역을 페이지 내용이 아니라 파일로 둔 것은 의도적입니다. 영어 전용 게이트
(test/gates.test.mjs)가 src, bin, adapters, scripts, viewer/index.html
에서 영어가 아닌 텍스트를 찾는데, viewer/i18n 이 그 유일한 예외 경로입니다.
영어 아닌 텍스트가 있어야 마땅한 단 하나의 자리입니다.
t(key, params) 는 절대 예외를 던지지 않습니다. 고른 언어에 없는 키는 영어로
떨어지고, 어느 카탈로그에도 없는 키는 키 자체로 그려지면서 t.missing 에
기록됩니다. 구멍이 조용히 비는 대신 화면에서 보이고 테스트에서 셀 수 있게
하려는 것입니다.
이 페이지의 모든 문장은, Spring 과 SQL 은 알지만 이 도구는 처음 보는 동료에게
경험 있는 개발자가 화면을 설명하는 목소리입니다. 실제로는 이런 뜻입니다. 어떤
것이 무엇인지보다 무엇을 위한 것인지를 먼저 말하고, 독자의 명사(API, 컨트롤러,
서비스, 매퍼, SQL, 테이블, 컬럼)를 쓰고, 한 문장에 하나의 생각만 담고, 숫자는
사실로 진술합니다. test/i18n_voice.test.mjs 가 기계로 확인할 수 있는 부분을
지킵니다. 카탈로그 문자열에 em dash 와 가운뎃점을 금지하고, 리드는 90 자 이하,
문단은 네 문장 이하이며, 모든 한국어 문장은 평서형 메모체가 아니라 합니다체여야
합니다.
viewer/i18n/ko.json 을 viewer/i18n/<lang>.json 으로 복사하고 값을
번역합니다. {placeholder} 는 모두 유지합니다. test/i18n.test.mjs 가 번역이
그것을 빠뜨리지 않았는지 확인합니다. {message} 는 엔진 자신의 문장이 들어갈
자리이기 때문입니다.lang.label 에 그 언어 자신의 말로 이름을 넣습니다. 토글이 각 언어를 그
언어로 보여 주기 때문입니다.viewer/index.html 의 LANGS 에 코드를 추가합니다.키 집합은 강제됩니다. 번역은 영어의 키를 정확히 그대로 가져야 합니다. 적으면 무언가 조용히 영어로 떨어지고, 많으면 낡은 키가 남기 때문입니다.
concepts.md 가 등급과 부분 pack, 그리고 빈 답의 뜻을 설명합니다. mcp.md 는 사람이 아니라 모델을 위한 같은 질문 표면입니다.