diff --git a/imgs/term_build_bundling.png b/imgs/term_build_bundling.png new file mode 100644 index 0000000..ddab993 Binary files /dev/null and b/imgs/term_build_bundling.png differ diff --git a/imgs/term_cors.png b/imgs/term_cors.png new file mode 100644 index 0000000..4dd6ffc Binary files /dev/null and b/imgs/term_cors.png differ diff --git a/imgs/term_css_layout.png b/imgs/term_css_layout.png new file mode 100644 index 0000000..f776d46 Binary files /dev/null and b/imgs/term_css_layout.png differ diff --git a/imgs/term_deployment_hosting.png b/imgs/term_deployment_hosting.png new file mode 100644 index 0000000..b862889 Binary files /dev/null and b/imgs/term_deployment_hosting.png differ diff --git a/imgs/term_devtools.png b/imgs/term_devtools.png new file mode 100644 index 0000000..8d19a95 Binary files /dev/null and b/imgs/term_devtools.png differ diff --git a/imgs/term_env_vars.png b/imgs/term_env_vars.png new file mode 100644 index 0000000..9ecff1c Binary files /dev/null and b/imgs/term_env_vars.png differ diff --git a/imgs/term_git_version_control.png b/imgs/term_git_version_control.png new file mode 100644 index 0000000..960618c Binary files /dev/null and b/imgs/term_git_version_control.png differ diff --git a/imgs/term_https_tls.png b/imgs/term_https_tls.png new file mode 100644 index 0000000..ccbec20 Binary files /dev/null and b/imgs/term_https_tls.png differ diff --git a/imgs/term_nginx_reverse_proxy.png b/imgs/term_nginx_reverse_proxy.png new file mode 100644 index 0000000..797bf7e Binary files /dev/null and b/imgs/term_nginx_reverse_proxy.png differ diff --git a/imgs/term_npm_package.png b/imgs/term_npm_package.png new file mode 100644 index 0000000..1a9c35b Binary files /dev/null and b/imgs/term_npm_package.png differ diff --git a/imgs/term_orm_migration.png b/imgs/term_orm_migration.png new file mode 100644 index 0000000..19a1729 Binary files /dev/null and b/imgs/term_orm_migration.png differ diff --git a/imgs/term_rest_crud.png b/imgs/term_rest_crud.png new file mode 100644 index 0000000..a3090bd Binary files /dev/null and b/imgs/term_rest_crud.png differ diff --git a/imgs/term_testing.png b/imgs/term_testing.png new file mode 100644 index 0000000..f6be968 Binary files /dev/null and b/imgs/term_testing.png differ diff --git a/imgs/term_typescript.png b/imgs/term_typescript.png new file mode 100644 index 0000000..adf6dd8 Binary files /dev/null and b/imgs/term_typescript.png differ diff --git a/imgs/term_url_dns.png b/imgs/term_url_dns.png new file mode 100644 index 0000000..66d8a58 Binary files /dev/null and b/imgs/term_url_dns.png differ diff --git a/imgs/term_web_storage.png b/imgs/term_web_storage.png new file mode 100644 index 0000000..adf1b2b Binary files /dev/null and b/imgs/term_web_storage.png differ diff --git a/imgs/term_xss_csrf.png b/imgs/term_xss_csrf.png new file mode 100644 index 0000000..06867aa Binary files /dev/null and b/imgs/term_xss_csrf.png differ diff --git a/script.js b/script.js index 881f4ef..e74275a 100644 --- a/script.js +++ b/script.js @@ -21,7 +21,7 @@ const nodes = [ focus: "HTML, CSS, 브라우저, DOM이 화면을 구성하는 기본 흐름을 봅니다.", x: 1020, y: 420, - children: ["browser", "html-css", "dom"], + children: ["url-dns", "browser", "html-css", "css-layout", "dom", "devtools"], }, { id: "frontend", @@ -33,7 +33,7 @@ const nodes = [ focus: "사용자가 보는 화면과 백엔드가 만나는 경계를 먼저 파악합니다.", x: 1360, y: 560, - children: ["javascript", "react", "front-back"], + children: ["javascript", "typescript", "react", "front-back", "web-storage"], }, { id: "network", @@ -45,7 +45,7 @@ const nodes = [ focus: "요청과 응답, 상태 코드, 헤더, 바디가 웹 통신에서 맡는 역할을 봅니다.", x: 1320, y: 900, - children: ["auth", "cookie", "api", "http", "request-response"], + children: ["auth", "cookie", "api", "http", "request-response", "cors", "xss-csrf"], }, { id: "backend", @@ -57,7 +57,7 @@ const nodes = [ focus: "서버가 요청을 처리하고 데이터를 저장·조회하는 큰 흐름을 봅니다.", x: 1020, y: 1030, - children: ["web-server", "database", "json"], + children: ["web-server", "database", "json", "env-vars"], }, { id: "workflow", @@ -69,7 +69,19 @@ const nodes = [ focus: "Next.js 같은 프레임워크가 라우팅, 렌더링, 개발 흐름을 어떻게 묶는지 봅니다.", x: 660, y: 900, - children: ["next", "next-structure"], + children: ["next", "next-structure", "npm-package", "git-version-control", "build-bundling", "deployment-hosting", "testing"], + }, + { + id: "url-dns", + parent: "structure", + type: "term", + title: "URL · 도메인 · DNS", + subtitle: "웹의 뼈대", + image: "imgs/term_url_dns.png", + category: "웹의 뼈대", + focus: "주소창의 도메인이 DNS를 통해 IP로 바뀌고 서버에 연결되는 흐름을 봅니다.", + x: 650, + y: 170, }, { id: "browser", @@ -107,6 +119,30 @@ const nodes = [ x: 1320, y: 330, }, + { + id: "css-layout", + parent: "structure", + type: "term", + title: "CSS 레이아웃", + subtitle: "웹의 뼈대", + image: "imgs/term_css_layout.png", + category: "웹의 뼈대", + focus: "Box Model, Flexbox, Grid, 반응형 규칙으로 화면을 배치하는 방법을 봅니다.", + x: 910, + y: 110, + }, + { + id: "devtools", + parent: "structure", + type: "term", + title: "DevTools", + subtitle: "웹의 뼈대", + image: "imgs/term_devtools.png", + category: "웹의 뼈대", + focus: "Elements, Console, Network, Application 패널로 브라우저 안의 상태를 확인합니다.", + x: 1290, + y: 150, + }, { id: "javascript", parent: "frontend", @@ -131,6 +167,18 @@ const nodes = [ x: 1640, y: 560, }, + { + id: "typescript", + parent: "frontend", + type: "term", + title: "TypeScript", + subtitle: "프론트엔드", + image: "imgs/term_typescript.png", + category: "프론트엔드", + focus: "JavaScript에 타입 검사를 더해 런타임 전에 오류를 줄이는 방법을 봅니다.", + x: 1720, + y: 410, + }, { id: "front-back", parent: "frontend", @@ -143,6 +191,18 @@ const nodes = [ x: 1530, y: 740, }, + { + id: "web-storage", + parent: "frontend", + type: "term", + title: "localStorage · sessionStorage", + subtitle: "프론트엔드", + image: "imgs/term_web_storage.png", + category: "프론트엔드", + focus: "브라우저에 문자열 데이터를 저장하는 방식과 쿠키와의 차이를 봅니다.", + x: 1740, + y: 760, + }, { id: "auth", parent: "network", @@ -170,7 +230,7 @@ const nodes = [ { id: "api", parent: "network", - type: "term", + type: "category", title: "API", subtitle: "통신", image: "imgs/term_api.png", @@ -178,11 +238,12 @@ const nodes = [ focus: "프론트엔드와 백엔드가 약속된 주소와 데이터 형식으로 대화하는 개념입니다.", x: 1460, y: 1080, + children: ["rest-crud"], }, { id: "http", parent: "network", - type: "term", + type: "category", title: "HTTP 프로토콜", subtitle: "통신", image: "imgs/http_protocol.png", @@ -190,6 +251,7 @@ const nodes = [ focus: "웹에서 클라이언트와 서버가 약속된 방식으로 통신하는 규칙입니다.", x: 1190, y: 1160, + children: ["https-tls"], }, { id: "request-response", @@ -203,6 +265,54 @@ const nodes = [ x: 930, y: 1180, }, + { + id: "https-tls", + parent: "http", + type: "term", + title: "HTTPS · TLS", + subtitle: "통신", + image: "imgs/term_https_tls.png", + category: "통신", + focus: "TLS 암호화와 인증서로 HTTP 통신을 안전하게 보호하는 원리를 봅니다.", + x: 1120, + y: 1370, + }, + { + id: "rest-crud", + parent: "api", + type: "term", + title: "REST · CRUD", + subtitle: "통신", + image: "imgs/term_rest_crud.png", + category: "통신", + focus: "리소스 중심 API와 생성/조회/수정/삭제 흐름을 HTTP 메서드와 연결합니다.", + x: 1620, + y: 1220, + }, + { + id: "cors", + parent: "network", + type: "term", + title: "CORS", + subtitle: "통신", + image: "imgs/term_cors.png", + category: "통신", + focus: "다른 출처의 API 요청이 브라우저 보안 정책과 서버 헤더로 허용되는 방식을 봅니다.", + x: 1740, + y: 1040, + }, + { + id: "xss-csrf", + parent: "network", + type: "term", + title: "XSS · CSRF", + subtitle: "통신", + image: "imgs/term_xss_csrf.png", + category: "통신", + focus: "스크립트 주입과 위조 요청을 구분하고 입력 검증, 토큰, 쿠키 옵션을 봅니다.", + x: 1790, + y: 1370, + }, { id: "web-server", parent: "backend", @@ -226,7 +336,7 @@ const nodes = [ focus: "애플리케이션 데이터가 테이블, 문서, 키-값 등으로 저장되는 방식을 봅니다.", x: 880, y: 1280, - children: ["postgres"], + children: ["postgres", "orm-migration"], }, { id: "postgres", @@ -240,6 +350,18 @@ const nodes = [ x: 1180, y: 1300, }, + { + id: "orm-migration", + parent: "database", + type: "term", + title: "ORM · Migration", + subtitle: "백엔드·데이터", + image: "imgs/term_orm_migration.png", + category: "백엔드·데이터", + focus: "코드 모델과 DB 테이블을 연결하고 스키마 변경을 버전으로 관리하는 방법을 봅니다.", + x: 810, + y: 1500, + }, { id: "json", parent: "backend", @@ -252,6 +374,18 @@ const nodes = [ x: 1420, y: 1210, }, + { + id: "env-vars", + parent: "backend", + type: "term", + title: "환경 변수(.env)", + subtitle: "백엔드·데이터", + image: "imgs/term_env_vars.png", + category: "백엔드·데이터", + focus: "API Key, DB URL 같은 설정을 코드와 분리하고 Git에 올리지 않는 이유를 봅니다.", + x: 650, + y: 1210, + }, { id: "next", parent: "workflow", @@ -276,6 +410,79 @@ const nodes = [ x: 420, y: 1080, }, + { + id: "npm-package", + parent: "workflow", + type: "term", + title: "npm · package.json", + subtitle: "프레임워크·도구", + image: "imgs/term_npm_package.png", + category: "프레임워크·도구", + focus: "패키지 설치, scripts, dependencies가 프로젝트 실행 흐름을 잡는 방식을 봅니다.", + x: 260, + y: 940, + }, + { + id: "git-version-control", + parent: "workflow", + type: "term", + title: "Git · 버전 관리", + subtitle: "프레임워크·도구", + image: "imgs/term_git_version_control.png", + category: "프레임워크·도구", + focus: "commit, branch, merge, remote를 통해 변경 이력과 협업을 관리하는 방법을 봅니다.", + x: 200, + y: 1190, + }, + { + id: "build-bundling", + parent: "workflow", + type: "term", + title: "빌드 · 번들링", + subtitle: "프레임워크·도구", + image: "imgs/term_build_bundling.png", + category: "프레임워크·도구", + focus: "소스 코드를 배포 가능한 정적 파일로 최적화하는 과정을 봅니다.", + x: 610, + y: 1190, + }, + { + id: "deployment-hosting", + parent: "workflow", + type: "category", + title: "배포 · 호스팅", + subtitle: "프레임워크·도구", + image: "imgs/term_deployment_hosting.png", + category: "프레임워크·도구", + focus: "빌드 결과물을 서버나 CDN에 올려 외부 사용자가 접근하게 만드는 흐름을 봅니다.", + x: 560, + y: 1410, + children: ["nginx-reverse-proxy"], + }, + { + id: "nginx-reverse-proxy", + parent: "deployment-hosting", + type: "term", + title: "Nginx · Reverse Proxy", + subtitle: "프레임워크·도구", + image: "imgs/term_nginx_reverse_proxy.png", + category: "프레임워크·도구", + focus: "공개 요청을 받아 정적 파일과 API 서버로 나누어 전달하는 프록시 역할을 봅니다.", + x: 350, + y: 1620, + }, + { + id: "testing", + parent: "workflow", + type: "term", + title: "테스트", + subtitle: "프레임워크·도구", + image: "imgs/term_testing.png", + category: "프레임워크·도구", + focus: "Unit, Integration, E2E, Smoke 테스트로 변경이 실제로 동작하는지 확인합니다.", + x: 190, + y: 1450, + }, ]; const viewport = document.querySelector("#viewport"); @@ -301,9 +508,9 @@ let pan = { x: window.innerWidth / 2 - 1136, y: window.innerHeight / 2 - 764 }; let activePointer = null; let zoomState = { scale: 1, x: 0, y: 0, dragging: false, pointerId: null, startX: 0, startY: 0, startOffsetX: 0, startOffsetY: 0 }; -connectorLayer.setAttribute("viewBox", "0 0 2400 1600"); +connectorLayer.setAttribute("viewBox", "0 0 2400 1900"); connectorLayer.setAttribute("width", "2400"); -connectorLayer.setAttribute("height", "1600"); +connectorLayer.setAttribute("height", "1900"); function visibleNodeIds() { const visible = ["root"]; diff --git a/styles.css b/styles.css index d3e2695..c2e3e5b 100644 --- a/styles.css +++ b/styles.css @@ -129,7 +129,7 @@ h1 { left: 0; top: 0; width: 2400px; - height: 1600px; + height: 1900px; transform-origin: 0 0; will-change: transform; } @@ -143,7 +143,7 @@ h1 { .connector-layer { pointer-events: none; width: 2400px; - height: 1600px; + height: 1900px; overflow: visible; }