// 이 파일이 하는 일: "도커 입문" 코스 — "내 PC에선 되는데요"라는 오래된 비극을
// 컨테이너로 없애는 여정. 이미지/컨테이너 개념부터 기본 명령, 우리 docker-compose.yml
// 한 줄씩 해부, 볼륨·포트 매핑, 그리고 개발 DB를 직접 띄우는 실습까지 8개 섹션.
// 학습 포인트: API 호출이 없는 '내용 고정' 정적 페이지다. 스타일은 global.css의
// 가이드 전용 클래스(step-card, code-block, tip 등)를 재사용한다 — 색을 여기서 하드코딩하지 않는다.
// 명령어·YAML 예시는 JSX 중괄호/백틱 충돌을 피하려고 파일 상단의 백틱 문자열 상수로 정의한다.

import { Link } from 'react-router-dom';

// ── 텍스트 다이어그램 · 명령어 상수들 ──

const CODE_CONTAINER_SHIP = `옛날 항구: 쌀가마·목재·기계를 제각각 배에 실음
→ 싣고 내리는 데 며칠, 배마다 싣는 법이 다름, 자주 부서짐

컨테이너선의 발명: 뭘 넣든 겉은 똑같은 강철 상자
→ 어느 항구, 어느 배, 어느 트럭이든 똑같이 다룰 수 있음

개발도 똑같아요:

  [ 내 앱 + Java 21 + 라이브러리 + 설정 ]  ← 전부 한 상자에!
  ──────────────────────────────────────
   내 PC        동료 PC       AWS EC2 서버
   (Windows)    (Mac)         (Linux)

상자(컨테이너) 안이 똑같으니, 어디서 실행해도 똑같이 돕니다.
"내 PC에선 되는데요"의 원인 = PC마다 다른 '항구 사정'을
상자가 통째로 없애 버린 거예요.`;

const CODE_IMAGE_VS_CONTAINER = `이미지 vs 컨테이너 = 붕어빵틀 vs 붕어빵

이미지 (붕어빵틀)                컨테이너 (붕어빵)
──────────────────────      ──────────────────────
실행에 필요한 모든 것을          이미지를 '실행'한 실체
구워 놓은 설계도·틀              (진짜로 돌아가는 프로그램)
읽기 전용, 변하지 않음           만들고, 굽고, 먹고(삭제) 가능
하나만 있으면 됨                 틀 하나로 여러 개 찍어냄

postgres:17 이미지 하나로 →  개발용 DB 컨테이너 1개
                             테스트용 DB 컨테이너 1개
                             실험용 DB 컨테이너 1개 ... 무한 생산!

이미지는 Docker Hub 같은 창고에서 받아 옵니다:
docker pull postgres:17   ← "postgres 틀의 17번 버전 주세요"
(뒤의 :17을 '태그'라고 해요. 버전 표시 스티커!)`;

const CODE_VM_VS_DOCKER = `가상머신(VM)                     도커 컨테이너
──────────────────────       ──────────────────────
집 안에 '집을 통째로' 지음        집 안에 '방 하나'만 빌림
OS부터 전부 새로 설치             호스트 OS의 부엌·화장실(커널) 공유
부팅에 몇 분                     시작에 몇 초 (사실상 즉시)
수 GB~수십 GB                    수십 MB~수백 MB
한 PC에 몇 개 못 띄움             수십 개도 거뜬

공통점: 둘 다 '격리된 실행 환경'을 만든다
차이점: VM은 하드웨어부터 흉내(무겁고 확실),
        도커는 OS 위에 칸막이만(가볍고 빠름)

우리 서버(AWS EC2)도 사실 거대한 컴퓨터를 잘라 쓰는
가상머신이에요. 그 VM '안에서' 도커 컨테이너들이 돌아갑니다.
→ 집(EC2) 안에 방(컨테이너) 여러 개!`;

const CODE_BASIC_COMMANDS = `# 도커 5대 기본기 — 이것만 알면 팀에서 대화가 됩니다

docker run hello-world      # 이미지를 받아서 컨테이너로 실행
docker ps                   # 지금 돌아가는 컨테이너 목록 (작업 관리자)
docker ps -a                # 멈춘 것까지 전부
docker logs <이름>          # 그 컨테이너가 찍은 로그 보기
docker logs -f <이름>       # 실시간으로 따라가며 보기 (f = follow)
docker exec -it <이름> bash # 돌아가는 컨테이너 '안으로' 들어가기
docker stop <이름>          # 정중하게 멈추기

# 자주 쓰는 조합:
docker run -d --name my-db postgres:17
#          │  │
#          │  └ 컨테이너에 붙일 이름 (없으면 랜덤 이름이 생겨요)
#          └ detached: 백그라운드 실행 (터미널을 안 잡아먹음)`;

const CODE_COMPOSE_FILE = `# 우리 mirim-app의 docker-compose.yml — 진짜 교재!

services:                       # ① "이 앱은 이런 부품들로 되어 있다" 선언
  db:                           # ② 부품 1: 데이터베이스
    image: postgres:17          # ③ 어떤 틀(이미지)로 만들지
    environment:                # ④ 컨테이너 안에 넣어줄 설정값
      POSTGRES_DB: mirim
      POSTGRES_PASSWORD: \${DB_PASSWORD}   # ⑤ 진짜 비번은 .env 파일에서!
    volumes:
      - db-data:/var/lib/postgresql/data  # ⑥ 데이터 보존 (섹션 6에서!)
    ports:
      - "5432:5432"             # ⑦ 포트 매핑 (섹션 7에서!)

  backend:                      # ⑧ 부품 2: Spring Boot 서버
    build: ./backend            # ⑨ 남의 이미지가 아니라 우리 코드로 직접 구움
    depends_on:
      - db                      # ⑩ "db 먼저 켜고 나 켜줘" 순서 약속
    environment:
      DB_URL: jdbc:postgresql://db:5432/mirim   # ⑪ 주소가 'db'?!

  frontend:                     # ⑫ 부품 3: React 앱
    build: ./frontend
    ports:
      - "3000:3000"

volumes:
  db-data:                      # ⑬ ⑥에서 쓴 데이터 창고를 등록`;

const CODE_COMPOSE_NOTES = `⑪이 제일 신기한 부분이에요. DB 주소가 IP가 아니라 그냥 'db'!

compose로 띄운 컨테이너들은 같은 가상 네트워크에 들어가고,
서비스 이름(db, backend...)이 그대로 '도메인 이름'이 됩니다.
네트워크 코스에서 배운 DNS가 컨테이너 세계 안에도 있는 거예요.

⑤의 \${DB_PASSWORD}도 중요: 비밀번호를 파일에 직접 쓰면
Gitea에 올라가는 순간 전 직원에게 공개되는 셈이라,
같은 폴더의 .env 파일(git에 안 올림!)에서 주입받습니다.`;

const CODE_VOLUME = `컨테이너는 '지우면 안이 통째로 사라지는' 일회용 도시락통이에요.

docker rm my-db  →  그 안에 쌓은 DB 데이터도 함께 증발! 😱

그래서 볼륨(volume) = 컨테이너 밖에 두는 외장하드가 있습니다.

  [ db 컨테이너 ]                [ db-data 볼륨 ]
   /var/lib/postgresql/data ───→  (호스트 PC 어딘가에 안전 보관)
   ↑ 컨테이너 안에서 이 폴더에        컨테이너가 죽어도
     쓰는 척하지만, 실제 저장은 →     여기 데이터는 그대로!

- db-data:/var/lib/postgresql/data
  │        └ 컨테이너 안의 경로 (포스트그레스가 데이터 쓰는 곳)
  └ 볼륨 이름 (외장하드 라벨)

컨테이너를 지우고 새로 띄워도 볼륨만 다시 꽂으면
어제 만든 테이블과 데이터가 그대로 살아 있어요.`;

const CODE_PORT_MAPPING = `컨테이너는 기본적으로 '방음 처리된 방'이라 밖에서 못 두드려요.
포트 매핑 = 방문에 구멍(문구멍)을 뚫어 바깥 세계와 연결하는 것.

  ports:
    - "5432:5432"
       │     └ 컨테이너 안쪽 포트 (포스트그레스가 듣고 있는 문)
       └ 내 PC(호스트) 쪽 포트 (내가 두드릴 문)

  내 PC의 localhost:5432 를 두드리면
  → 도커가 컨테이너 안 5432번으로 그대로 전달!

숫자를 다르게 쓸 수도 있어요:
  - "15432:5432"   ← 내 PC의 15432 → 컨테이너의 5432
  (내 PC에 이미 다른 프로그램이 5432를 쓰고 있을 때의 회피 기술)

네트워크 코스의 "IP=건물, 포트=방 번호" 기억나죠?
포트 매핑은 '건물 정문의 우편함 번호'와 '실제 방 번호'를
연결해 주는 안내판이에요.`;

const CODE_PRACTICE = `# 실습: docker compose로 개발용 PostgreSQL 띄우기 (5분 완성)

# 0) Docker Desktop이 켜져 있는지 확인 (고래 아이콘!)

# 1) 아무 데나 연습 폴더를 만들고 docker-compose.yml 파일 작성:
services:
  db:
    image: postgres:17
    environment:
      POSTGRES_DB: practice
      POSTGRES_PASSWORD: devonly
    ports:
      - "5432:5432"
    volumes:
      - practice-data:/var/lib/postgresql/data
volumes:
  practice-data:

# 2) 그 폴더에서 터미널을 열고:
docker compose up -d      # 부품 전체 기동! (처음엔 이미지 다운로드로 1~2분)
docker ps                 # postgres:17 컨테이너가 보이면 성공
docker logs <컨테이너이름> # "ready to accept connections" 찾기

# 3) 진짜 DB인지 확인 — 컨테이너 안으로 들어가서 SQL 치기:
docker exec -it <컨테이너이름> psql -U postgres -d practice
practice=# CREATE TABLE hello (msg TEXT);
practice=# INSERT INTO hello VALUES ('나의 첫 컨테이너 DB!');
practice=# SELECT * FROM hello;
practice=# \\q            # psql 나가기

# 4) 볼륨의 마법 확인 — 컨테이너를 없앴다가 다시:
docker compose down       # 컨테이너 삭제! (볼륨은 남음)
docker compose up -d      # 새 컨테이너로 부활
docker exec -it <컨테이너이름> psql -U postgres -d practice -c "SELECT * FROM hello;"
# → 아까 넣은 데이터가 그대로! 이게 볼륨입니다.

# 5) 다 놀았으면 정리:
docker compose down -v    # -v: 볼륨까지 삭제 (연습용이니까)`;

// ── 이 페이지 안에서만 쓰는 작은 부품들 ──
// 학습 포인트: 같은 모양이 반복되면 컴포넌트로 뽑는다. props만 바꿔 재사용.
function Section({ n, title, sub, children }) {
  return (
    <section className="step-card" id={`sec-${n}`}>
      <div className="step-head">
        <span className="step-num">{n}</span>
        <div>
          <h3>{title}</h3>
          {sub && <span className="step-sub">{sub}</span>}
        </div>
      </div>
      <div className="step-body">{children}</div>
    </section>
  );
}

function Code({ children }) {
  return <pre className="code-block"><code>{children}</code></pre>;
}

const SECTIONS = [
  { n: 1, label: '왜 컨테이너인가' },
  { n: 2, label: '이미지 vs 컨테이너' },
  { n: 3, label: '가상머신과의 차이' },
  { n: 4, label: '기본 명령 5가지' },
  { n: 5, label: 'compose 해부' },
  { n: 6, label: '볼륨 = 데이터 보존' },
  { n: 7, label: '포트 매핑' },
  { n: 8, label: '실습: DB 띄우기' },
];

export default function DockerIntroPage() {
  return (
    <div>
      {/* 히어로: 이 코스가 무엇을 없애 주는지 */}
      <div className="hero">
        <div className="eyebrow">Course · 서버와 데이터</div>
        <h1>도커 입문<br />— "내 PC에선 되는데요"를 없애는 마법 상자</h1>
        <p>
          내 PC에선 잘 되는데 동료 PC나 서버에선 안 되는 이유는, 코드가 아니라
          <strong> 환경</strong>이 다르기 때문이에요. 도커는 앱과 환경을 통째로 상자에 담아
          어디서든 똑같이 실행하는 도구 — 우리 회사 서비스도 전부 이 상자로 배달됩니다.
        </p>
        <div className="chip-row">
          <span className="chip">예상 소요 70분</span>
          <span className="chip">실습 2개 포함</span>
          <span className="chip">준비물: Docker Desktop</span>
        </div>
      </div>

      {/* 섹션 바로가기 */}
      <nav className="pill-nav">
        {SECTIONS.map((s) => (
          <a key={s.n} href={`#sec-${s.n}`}>
            <b>{s.n}</b>
            {s.label}
          </a>
        ))}
      </nav>

      <Section n={1} title="왜 컨테이너인가" sub={'"내 PC에선 되는데요"라는 오래된 비극'}>
        <p>
          이런 상황을 상상해 보세요. 내 PC에서 완벽하게 돌던 Spring Boot 프로젝트를 동료에게
          보냈더니 "안 돌아가는데?"라는 답이 옵니다. 알고 보니 동료 PC엔 Java 버전이 다르고,
          환경변수 하나가 빠져 있고, PostgreSQL 설정도 달랐던 거죠. 코드는 같은데
          <strong> 코드가 밟고 선 땅</strong>이 달랐던 겁니다.
        </p>
        <p>
          이 문제를 해운업계가 먼저 풀었어요. 바로 <strong>컨테이너선</strong>입니다.
        </p>
        <Code>{CODE_CONTAINER_SHIP}</Code>
        <p>
          도커의 컨테이너도 똑같은 발상이에요. 앱뿐 아니라 <strong>앱이 필요로 하는 모든 것</strong>
          — 언어 런타임, 라이브러리, 설정 — 을 한 상자에 담습니다. 상자 안이 똑같으니
          내 PC든, 동료의 Mac이든, 서울 리전의 AWS EC2든 <strong>똑같이 돌아요</strong>.
          우리 학습 플랫폼(React + Spring Boot + PostgreSQL)이 서버에서 돌아가는 방식이
          정확히 이겁니다.
        </p>
      </Section>

      <Section n={2} title="이미지 vs 컨테이너" sub="붕어빵틀과 붕어빵">
        <p>
          도커 대화의 90%에 나오는 두 단어가 <strong>이미지</strong>와
          <strong> 컨테이너</strong>인데, 처음엔 헷갈려요. 붕어빵을 떠올리면 절대 안 헷갈립니다.
        </p>
        <Code>{CODE_IMAGE_VS_CONTAINER}</Code>
        <p>
          <strong>틀(이미지)은 하나, 붕어빵(컨테이너)은 여러 개</strong> — 이게 핵심이에요.
          <span className="icode">postgres:17</span> 이미지를 한 번만 받아 두면, 프로젝트마다
          독립된 DB 컨테이너를 몇 개든 찍어낼 수 있어요. 하나를 실험하다 망가뜨려도
          지우고 틀에서 새로 구우면 그만입니다.
        </p>
        <svg className="diagram" viewBox="0 0 640 312" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="이미지와 컨테이너의 관계 도해: Docker Hub에서 docker pull로 postgres:17 이미지(붕어빵틀)를 받아 오고, docker run으로 그 틀 하나에서 개발용·테스트용·실험용 DB 컨테이너(붕어빵) 여러 개를 찍어낸다">
          <rect x="40" y="28" width="180" height="52" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="130" y="50" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--ink)">Docker Hub</text>
          <text x="130" y="68" textAnchor="middle" fontSize="12" fill="var(--muted)">이미지 창고</text>
          <line x1="130" y1="80" x2="130" y2="129" stroke="var(--muted)" strokeWidth="1.5" />
          <path d="M130 138 l-5 -9 h10 z" fill="var(--muted)" />
          <text x="140" y="112" fontSize="12" fontWeight="600" fill="var(--primary)">docker pull</text>
          <rect x="40" y="140" width="180" height="110" rx="8" fill="var(--card)" stroke="var(--primary)" strokeWidth="2" />
          <text x="130" y="168" textAnchor="middle" fontSize="15" fontWeight="600" fill="var(--ink)">이미지</text>
          <text x="130" y="190" textAnchor="middle" fontSize="13" fill="var(--primary)">postgres:17</text>
          <text x="130" y="212" textAnchor="middle" fontSize="12" fill="var(--muted)">붕어빵틀 = 설계도</text>
          <text x="130" y="232" textAnchor="middle" fontSize="12" fill="var(--muted)">읽기 전용 · 하나면 충분</text>
          <line x1="225" y1="195" x2="405" y2="72" stroke="var(--teal)" strokeWidth="1.5" />
          <line x1="225" y1="195" x2="405" y2="170" stroke="var(--teal)" strokeWidth="1.5" />
          <line x1="225" y1="195" x2="405" y2="268" stroke="var(--teal)" strokeWidth="1.5" />
          <path d="M418 72 l-11 -5 v10 z" fill="var(--teal)" />
          <path d="M418 170 l-11 -5 v10 z" fill="var(--teal)" />
          <path d="M418 268 l-11 -5 v10 z" fill="var(--teal)" />
          <text x="312" y="206" textAnchor="middle" fontSize="12" fontWeight="600" fill="var(--teal)">docker run</text>
          <text x="512" y="24" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--ink)">컨테이너 = 실행 중인 붕어빵</text>
          <rect x="420" y="40" width="185" height="64" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="512" y="66" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">개발용 DB</text>
          <text x="512" y="88" textAnchor="middle" fontSize="12" fill="var(--muted)">실행 중</text>
          <rect x="420" y="138" width="185" height="64" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="512" y="164" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">테스트용 DB</text>
          <text x="512" y="186" textAnchor="middle" fontSize="12" fill="var(--muted)">실행 중</text>
          <rect x="420" y="236" width="185" height="64" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="512" y="262" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">실험용 DB</text>
          <text x="512" y="284" textAnchor="middle" fontSize="12" fill="var(--muted)">망가지면 지우고 새로 굽기</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: 틀(이미지)은 하나, 붕어빵(컨테이너)은 몇 개든 — pull로 받고 run으로 굽는다</p>
        <div className="tip">
          <b>직접 확인해 보기</b> Docker Desktop을 켜고 터미널에서{' '}
          <span className="icode">docker pull hello-world</span> →{' '}
          <span className="icode">docker images</span>를 쳐 보세요. 방금 받은 '틀' 목록이 보이면,
          이어서 <span className="icode">docker run hello-world</span>로 붕어빵을 하나 구워 보세요.
          환영 메시지가 나오면 도커 입문 성공!
        </div>
      </Section>

      <Section n={3} title="가상머신과 뭐가 달라요?" sub="집을 통째로 짓기 vs 방 하나 빌리기">
        <p>
          "격리된 환경"이라는 말만 들으면 <strong>가상머신(VM)</strong>과 비슷해 보여요.
          맞아요, 목적은 비슷합니다. 하지만 방법이 완전히 달라서 무게가 하늘과 땅 차이예요.
        </p>
        <Code>{CODE_VM_VS_DOCKER}</Code>
        <p>
          VM은 집 안에 <strong>집을 통째로 새로 짓는</strong> 방식이라 OS까지 전부 새로 설치해요.
          도커는 이미 있는 집(호스트 OS)의 부엌과 수도(커널)를 같이 쓰면서
          <strong> 방에 칸막이만 치는</strong> 방식이라, 몇 초 만에 뜨고 용량도 몇십 배 가볍습니다.
          우리 EC2 서버 한 대에 프론트·백엔드·DB·Caddy 컨테이너를 전부 띄울 수 있는 이유가
          바로 이 가벼움이에요.
        </p>
        <svg className="diagram" viewBox="0 0 640 324" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="가상머신과 도커 컨테이너의 계층 비교 도해: 가상머신은 하드웨어·호스트 OS·하이퍼바이저 위에 게스트 OS를 통째로 복제해 무겁고, 도커는 호스트 OS의 커널을 공유하는 도커 엔진 위에 앱 컨테이너만 얹어 가볍다">
          <text x="160" y="26" textAnchor="middle" fontSize="15" fontWeight="600" fill="var(--ink)">가상머신 (VM)</text>
          <text x="160" y="46" textAnchor="middle" fontSize="12" fill="var(--muted)">집 안에 집을 통째로</text>
          <text x="160" y="68" textAnchor="middle" fontSize="12" fontWeight="600" fill="var(--rose)">부팅 몇 분 · 수 GB</text>
          <rect x="20" y="84" width="136" height="36" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="88" y="106" textAnchor="middle" fontSize="12" fill="var(--ink)">앱 A + 라이브러리</text>
          <rect x="164" y="84" width="136" height="36" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="232" y="106" textAnchor="middle" fontSize="12" fill="var(--ink)">앱 B + 라이브러리</text>
          <rect x="20" y="126" width="136" height="36" rx="8" fill="var(--card)" stroke="var(--rose)" strokeWidth="1.5" />
          <text x="88" y="148" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--rose)">게스트 OS</text>
          <rect x="164" y="126" width="136" height="36" rx="8" fill="var(--card)" stroke="var(--rose)" strokeWidth="1.5" />
          <text x="232" y="148" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--rose)">게스트 OS</text>
          <rect x="20" y="168" width="280" height="36" rx="8" fill="var(--card)" stroke="var(--amber)" strokeWidth="1.5" />
          <text x="160" y="190" textAnchor="middle" fontSize="13" fill="var(--ink)">하이퍼바이저 (하드웨어 흉내)</text>
          <rect x="20" y="210" width="280" height="36" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="160" y="232" textAnchor="middle" fontSize="13" fill="var(--ink)">호스트 OS</text>
          <rect x="20" y="252" width="280" height="36" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="160" y="274" textAnchor="middle" fontSize="13" fill="var(--muted)">하드웨어 (예: AWS EC2)</text>
          <text x="160" y="310" textAnchor="middle" fontSize="12" fill="var(--muted)">게스트 OS를 통째로 복제 → 무겁다</text>
          <text x="480" y="26" textAnchor="middle" fontSize="15" fontWeight="600" fill="var(--ink)">도커 컨테이너</text>
          <text x="480" y="46" textAnchor="middle" fontSize="12" fill="var(--muted)">집 안에 방 하나만</text>
          <text x="480" y="68" textAnchor="middle" fontSize="12" fontWeight="600" fill="var(--teal)">시작 몇 초 · 수십~수백 MB</text>
          <rect x="340" y="84" width="88" height="78" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="384" y="104" textAnchor="middle" fontSize="12" fill="var(--muted)">컨테이너</text>
          <text x="384" y="124" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--ink)">앱 A</text>
          <text x="384" y="144" textAnchor="middle" fontSize="12" fill="var(--muted)">라이브러리</text>
          <rect x="436" y="84" width="88" height="78" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="480" y="104" textAnchor="middle" fontSize="12" fill="var(--muted)">컨테이너</text>
          <text x="480" y="124" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--ink)">앱 B</text>
          <text x="480" y="144" textAnchor="middle" fontSize="12" fill="var(--muted)">라이브러리</text>
          <rect x="532" y="84" width="88" height="78" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="576" y="104" textAnchor="middle" fontSize="12" fill="var(--muted)">컨테이너</text>
          <text x="576" y="124" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--ink)">앱 C</text>
          <text x="576" y="144" textAnchor="middle" fontSize="12" fill="var(--muted)">라이브러리</text>
          <rect x="340" y="168" width="280" height="36" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="480" y="190" textAnchor="middle" fontSize="13" fill="var(--ink)">도커 엔진</text>
          <rect x="340" y="210" width="280" height="36" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="480" y="232" textAnchor="middle" fontSize="13" fill="var(--ink)">호스트 OS (커널은 모두가 공유)</text>
          <rect x="340" y="252" width="280" height="36" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="480" y="274" textAnchor="middle" fontSize="13" fill="var(--muted)">하드웨어 (예: AWS EC2)</text>
          <text x="480" y="310" textAnchor="middle" fontSize="12" fill="var(--muted)">OS 없이 칸막이만 → 가볍고 빠르다</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: VM은 게스트 OS까지 층층이, 도커는 호스트 OS 위에 칸막이(컨테이너)만</p>
        <div className="warn">
          <b>가볍다 ≠ 항상 정답</b> — 커널을 공유하니까, 호스트와 완전히 다른 OS가 필요하거나
          더 강한 격리가 필요하면 여전히 VM을 씁니다. 도구엔 각자의 자리가 있어요.
        </div>
      </Section>

      <Section n={4} title="기본 명령 5가지" sub="run · ps · logs · exec · stop — 이것만 있으면 대화 가능">
        <p>
          도커 명령은 수십 개지만, 실무에서 매일 쓰는 건 다섯 개예요. 각각을 한 문장으로
          기억해 두세요 — <strong>run은 굽기, ps는 작업 관리자, logs는 일기장, exec은 문 열고
          들어가기, stop은 정지</strong>.
        </p>
        <Code>{CODE_BASIC_COMMANDS}</Code>
        <p>
          특히 <span className="icode">docker logs</span>와{' '}
          <span className="icode">docker exec</span>은 문제가 생겼을 때의 생명줄이에요.
          "서버가 왜 죽었지?" → 먼저 <span className="icode">logs</span>로 일기장을 읽고,
          더 파야 하면 <span className="icode">exec</span>으로 컨테이너 안에 직접 들어가 봅니다.
          우리 서버에서 장애를 잡을 때도 이 순서 그대로예요.
        </p>
        <div className="tip">
          <b>직접 확인해 보기</b> 섹션 2에서 실행한 컨테이너들의 흔적을 추적해 보세요.{' '}
          <span className="icode">docker ps -a</span>를 치면 이미 종료된{' '}
          <span className="icode">hello-world</span> 컨테이너가 STATUS "Exited"로 남아 있어요.
          그 이름으로 <span className="icode">docker logs 이름</span>을 치면 아까 봤던
          환영 메시지가 다시 나옵니다 — 컨테이너가 죽어도 일기장은 남는다!
        </div>
      </Section>

      <Section n={5} title="우리 docker-compose.yml 한 줄씩 해부" sub="플랫폼 그 자체가 교재입니다">
        <p>
          컨테이너가 하나면 <span className="icode">docker run</span>으로 충분한데, 우리 앱처럼
          <strong> 프론트 + 백엔드 + DB</strong>가 한 팀으로 움직이면 매번 셋을 순서 맞춰 켜는 게
          고역이에요. 그래서 <strong>docker compose</strong> — 부품 목록과 연결 방법을 파일 하나에
          적어 두고 <span className="icode">docker compose up</span> 한 방으로 전체를 켜는
          도구가 있습니다. 여러분이 지금 보고 있는 이 플랫폼의 설계도를 같이 읽어 봐요.
        </p>
        <Code>{CODE_COMPOSE_FILE}</Code>
        <Code>{CODE_COMPOSE_NOTES}</Code>
        <p>
          ⑨의 <span className="icode">build</span>와 ③의 <span className="icode">image</span>{' '}
          차이도 짚고 갈게요. PostgreSQL은 남이 잘 만들어 둔 틀을 그대로 쓰면 되니까{' '}
          <span className="icode">image:</span>로 받아 오고, 우리 백엔드·프론트는 세상에 없는
          우리 코드니까 <span className="icode">build:</span>로 <strong>직접 틀을 굽습니다</strong>
          (그 굽는 레시피가 각 폴더의 Dockerfile이에요 — 다음 코스에서 자세히!).
        </p>
      </Section>

      <Section n={6} title="볼륨 — 컨테이너가 죽어도 데이터는 산다" sub="일회용 도시락통과 외장하드">
        <p>
          컨테이너의 가장 큰 장점은 "지우고 새로 만들면 그만"인 일회용성이에요. 그런데
          DB 컨테이너를 지우면? <strong>안에 쌓은 데이터도 같이 사라집니다.</strong>
          한 달 치 학습 기록이 증발하는 대참사죠. 그래서 데이터는 컨테이너 <strong>밖</strong>에
          둡니다 — 그게 <strong>볼륨</strong>이에요.
        </p>
        <Code>{CODE_VOLUME}</Code>
        <p>
          섹션 5의 ⑥번 줄이 바로 이거였어요. 우리 플랫폼의 DB 컨테이너는 업데이트 때마다
          지워지고 새로 만들어지지만, 여러분의 계정·진도·과제 데이터는{' '}
          <span className="icode">db-data</span> 볼륨에 있어서 멀쩡합니다.
          <strong> 컨테이너는 갈아 끼우는 부품, 볼륨은 소중한 금고</strong> — 이 감각이 중요해요.
        </p>
      </Section>

      <Section n={7} title="포트 매핑 — 상자에 문구멍 뚫기" sub="호스트 포트 : 컨테이너 포트">
        <p>
          컨테이너는 격리된 상자라서, 안에서 PostgreSQL이 아무리 열심히 돌아도 밖(내 PC)에서는
          기본적으로 접근할 수 없어요. 그래서 <strong>포트 매핑</strong>으로 내 PC의 문과
          컨테이너 안의 문을 연결해 줍니다.
        </p>
        <Code>{CODE_PORT_MAPPING}</Code>
        <p>
          왼쪽이 <strong>내 PC(호스트)</strong>, 오른쪽이 <strong>컨테이너 안</strong> —
          "<strong>바깥:안쪽</strong>" 순서만 외우면 됩니다. 헷갈리면 항상 이렇게 읽으세요:
          "내 PC의 <span className="icode">5432</span>를 두드리면, 컨테이너의{' '}
          <span className="icode">5432</span>로 통한다." 네트워크 코스(
          <Link to="/learn/network">네트워크의 이해</Link>)에서 배운 포트 개념이 여기서
          그대로 다시 나오죠 — 그 코스를 아직 안 들었다면 잠깐 다녀오는 것도 좋아요.
        </p>
      </Section>

      <Section n={8} title="실습 — compose로 개발 DB 띄우기" sub="오늘 배운 전부를 5분 안에">
        <p>
          이제 손으로 마무리합시다. 아래 실습은 <strong>이미지 받기(2) → compose로 켜기(5) →
          exec으로 들어가기(4) → 볼륨으로 데이터 살리기(6) → 포트(7)</strong>까지 오늘 배운 걸
          전부 한 번씩 통과해요. 실제로 백엔드 개발자들이 새 프로젝트를 시작할 때 개발용 DB를
          준비하는 방법 그대로입니다.
        </p>
        <div className="tip">
          <b>직접 확인해 보기</b> 아래를 순서대로 따라 하세요. 특히 <strong>4번 단계</strong> —
          컨테이너를 지웠다 다시 만들었는데 데이터가 살아 있는 순간이 이 코스의 하이라이트예요.
          꼭 눈으로 확인하세요.
        </div>
        <Code>{CODE_PRACTICE}</Code>
        <div className="warn">
          <b>흔한 막힘 포인트</b> — <span className="icode">port is already allocated</span>{' '}
          에러가 나면 내 PC의 5432번 방을 다른 프로그램(예: 로컬에 설치한 PostgreSQL)이 이미
          쓰고 있는 거예요. 섹션 7에서 배운 회피 기술로{' '}
          <span className="icode">"15432:5432"</span>처럼 바깥 번호만 바꿔 보세요.
          그리고 실습용 비밀번호 <span className="icode">devonly</span>는 연습 전용 —
          진짜 프로젝트에선 반드시 <span className="icode">.env</span>로 관리합니다(섹션 5의 ⑤!).
        </div>
      </Section>

      <div className="step-card">
        <div className="step-body">
          <h3 style={{ marginBottom: 6 }}>🐳 여기까지 왔다면</h3>
          <p className="muted">
            이제 여러분은 <strong>이미지와 컨테이너를 구분</strong>하고, <strong>기본 명령 5가지</strong>로
            컨테이너를 다루고, 우리 <strong>docker-compose.yml을 읽을 줄</strong> 알고,
            <strong> 볼륨과 포트 매핑</strong>의 이유를 설명할 수 있어요. 방금 띄운 개발 DB는
            다음 과제에서 진짜로 씁니다 — <Link to="/learn/network"><strong>네트워크의 이해</strong></Link>에서
            배운 포트 개념이 흐릿하면 복습하고, 준비가 됐다면 멘토에게 다음 과제
            (Spring Boot를 방금 띄운 DB에 연결하기)를 요청해 보세요. 컨테이너선은 이미 출항했습니다!
          </p>
        </div>
      </div>
    </div>
  );
}
