// 이 파일이 하는 일: "CI/CD와 배포 자동화 입문" 코스 — 우리가 지금 손으로 하고 있는
// 배포의 고통에서 출발해, CI(자동 검사)와 CD(자동 배포)가 그 고통을 어떻게 없애는지
// 7개 섹션으로 안내하는 정적 학습 페이지.
// (수동 배포의 고통 → CI → CD → 파이프라인 그림 → 도구 소개 → 롤백 → 실습: 자동화 지도 그리기)
// 학습 포인트: API 호출이 없는 '내용 고정' 페이지다. 스타일은 global.css의
// 가이드 전용 클래스(step-card, code-block, tip 등)를 재사용한다 — 색을 여기서 하드코딩하지 않는다.
// 텍스트 다이어그램은 JSX 중괄호/백틱 충돌을 피하려고 파일 상단의 백틱 문자열 상수로 정의한다.

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

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

const CODE_MANUAL_DEPLOY = `우리 플랫폼의 실제 배포 과정 (솔직 공개 — 전부 사람 손입니다)

1) 내 PC에서 프론트 빌드          npm run build
2) 백엔드 빌드                    ./mvnw package  → .jar 파일 생성
3) 빌드 결과물을 서버로 복사       scp 로 EC2에 업로드
4) 서버에 SSH 접속                ssh ubuntu@서버주소
5) 돌고 있던 옛 버전 중지
6) 새 버전 실행 + Caddy 확인
7) 브라우저 열고 "잘 뜨나...?" 새로고침 연타

→ 잘 되면 15분. 한 단계라도 실수하면? 원인 찾느라 1시간.
→ 그리고 5)~6) 사이엔 사이트가 잠깐 죽어 있어요.`;

const CODE_HUMAN_ERROR = `사람 손 배포에서 실제로 일어나는 사고 유형

사고                          원인
──────────────────────────────────────────────
"어? 로컬에선 됐는데요"        빌드 안 하고 옛 파일을 scp함
서버에서 500 에러 폭발         테스트 없이 배포 → 버그 동승
새벽 배포 후 아침에 장애       졸린 사람이 6단계 중 5단계만 함
"누가 언제 뭘 배포했지?"       기록이 사람 기억 속에만 있음

→ 공통점: 도구가 아니라 '사람의 컨디션'에 품질이 달려 있음`;

const CODE_CI_FLOW = `CI (Continuous Integration, 지속적 통합)
= 코드를 합칠 때마다 로봇이 자동으로 검사

[내가 git push] ──> [CI 로봇이 깨어남]
                        │
                        ├─ ① 빌드가 되나?   npm run build / mvnw package
                        ├─ ② 테스트 통과?   자동 테스트 실행
                        └─ ③ 결과 통보      ✅ 초록불 / ❌ 빨간불 + 어디서 깨졌는지

핵심: 검사 기준이 '사람 기분'이 아니라 '기계의 체크리스트'.
매번, 모든 커밋에, 똑같은 잣대로.`;

const CODE_CD_FLOW = `CD (Continuous Deployment, 지속적 배포)
= CI 검사를 통과하면 서버 배포까지 자동으로

수동 시절:  push → (사람이 빌드) → (사람이 scp) → (사람이 재시작)
CD 이후:   push → CI ✅ ──────────> 로봇이 알아서 서버에 새 버전 반영

사람이 하는 일: git push 하나.
로봇이 하는 일: 빌드, 검사, 업로드, 교체, 확인 — 전부.

비유: 수동 배포 = 손빨래 (물 받고, 비비고, 헹구고, 널고...)
      CD       = 세탁기 버튼 (넣고 → 버튼 → 끝. 매번 같은 품질)`;

const CODE_PIPELINE = `파이프라인 = 컨베이어 벨트. 한 정거장이라도 실패하면 그 자리에서 멈춥니다.

[git push]
    │
    ▼
[① 빌드]  React·Spring Boot 컴파일 — "일단 조립은 되니?"
    │ 통과
    ▼
[② 테스트]  자동 테스트 실행 — "조립품이 제대로 작동하니?"
    │ 통과
    ▼
[③ 배포]  Docker 이미지 → EC2 서버에 새 버전 교체
    │ 완료
    ▼
[④ 확인]  "사이트 살아 있니?" 헬스체크

❌ 어디서든 실패하면 → 배포 안 함 + 개발자에게 알림
   불량품이 손님(사용자)에게 도착하기 전에 벨트가 멈추는 것!`;

const CODE_TOOLS = `파이프라인을 굴려 주는 도구들 (개념만 알아 두면 충분!)

도구            특징
────────────────────────────────────────────────────
Gitea Actions   우리 Gitea에 내장. 저장소에 워크플로 파일을
                넣으면 push 때마다 실행. 가장 우리랑 가까움
Jenkins         역사 깊은 자동화 서버. 대기업에 아직 많음.
                뭐든 시킬 수 있지만 직접 설치·관리 필요
GitHub Actions  GitHub 내장판. Gitea Actions가 이걸 본떠
                만들어서 사용법이 거의 같음

공통 원리: "이 저장소에 push가 오면 → 이 명령들을 순서대로 실행해"
라는 각본(워크플로)을 파일로 적어 저장소에 같이 넣는다.
→ 배포 방법 자체가 코드가 되고, 기록이 남고, 리뷰도 받는다!`;

const CODE_WORKFLOW_TASTE = `워크플로 파일 맛보기 — 외울 필요 없어요, "아 이런 느낌"만!

# .gitea/workflows/deploy.yml (우리 Gitea 기준)
on: push            # push가 오면 깨어나라
jobs:
  build-and-test:
    steps:
      - run: npm ci             # 의존성 설치
      - run: npm run build      # ① 빌드 되나?
      - run: npm test           # ② 테스트 통과?

→ 우리가 터미널에 손으로 치던 명령을
  순서대로 받아 적은 것뿐이에요. 마법이 아닙니다!`;

const CODE_ROLLBACK = `롤백(Rollback) = 새 버전이 문제면 즉시 이전 버전으로 되돌리기

나쁜 시나리오 (롤백 준비 없음):
  새 버전 배포 → 장애! → "고칠 때까지 기다려 주세요" (사용자 이탈 중...)

좋은 시나리오 (롤백 준비 있음):
  새 버전 배포 → 장애! → 이전 버전으로 원복 (1분) → 사용자는 눈치 못 챔
                              └─> 원인은 그 다음에 차분히 조사

롤백이 가능하려면:
  ① 이전 버전 보관 — Docker 이미지에 v1.2, v1.3 같은 꼬리표(태그)
  ② 교체가 쉬운 구조 — "v1.3 실행" → "v1.2 실행"으로 명령만 바꾸면 끝
  ③ 배포 기록 — 언제 어떤 버전을 올렸는지 로그

게임의 세이브 포인트와 같아요. 보스전(새 배포) 전에 저장해 두면,
져도(장애가 나도) 마을부터 다시 시작하지 않죠.`;

const CODE_PRACTICE_MAP = `실습 양식 — 우리 플랫폼 배포 지도 그리기

1단계: 현재 배포 순서를 화살표로 그린다 (섹션 1 참고, 빠짐없이!)
  예) 코드 수정 → git push → ??? → ... → 사용자가 새 화면을 봄

2단계: 각 단계에 표시를 붙인다
  [사람] 사람 손이 필요한 단계
  [자동] 이미 자동인 단계
  [위험] 실수하면 사이트가 죽는 단계

3단계: [사람]+[위험]이 겹치는 단계에 ★을 친다
  → ★이 자동화 1순위! (실수 잦고 + 실수하면 아픈 곳부터)

4단계: ★ 단계마다 "로봇이라면 어떤 명령을 칠까?" 한 줄씩 적는다
  → 축하합니다. 방금 여러분이 적은 것이 워크플로 파일의 초안입니다.`;

// ── 이 페이지 안에서만 쓰는 작은 부품들 ──
// 학습 포인트: 같은 모양이 반복되면 컴포넌트로 뽑는다. 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: 'CI — 자동 검사' },
  { n: 3, label: 'CD — 자동 배포' },
  { n: 4, label: '파이프라인 그림' },
  { n: 5, label: '도구들' },
  { n: 6, label: '롤백 한 입' },
  { n: 7, label: '실습: 자동화 지도' },
];

export default function CicdPage() {
  return (
    <div>
      {/* 히어로: 이 코스가 어디서 출발해 어디까지 가는지 */}
      <div className="hero">
        <div className="eyebrow">Course · 서버와 데이터</div>
        <h1>CI/CD와 배포 자동화 입문</h1>
        <p>
          지금 우리 팀은 코드를 고칠 때마다 손으로 빌드하고, <strong>scp</strong>로 서버에
          올리고, 접속해서 재시작합니다 — 이 코스는 그 반복 노동을 <strong>로봇(파이프라인)</strong>에게
          넘기는 방법을 다뤄요. 개념이 낯설어도 괜찮아요. 우리가 매주 겪는 배포 과정이
          그대로 교재라서, 읽다 보면 "아 그거!" 하게 됩니다.
        </p>
        <div className="chip-row">
          <span className="chip">예상 소요 50분</span>
          <span className="chip">손 실습 2개</span>
          <span className="chip">준비물: 종이와 펜, Gitea 계정</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="우리가 지금 하는 일, 솔직하게 공개">
        <p>
          "배포"란 완성한 코드를 <strong>실제 서버에 올려 사용자가 쓸 수 있게 만드는 일</strong>이에요.
          그리고 지금 우리 플랫폼(AWESOMEDEV의 이 학습 사이트!)은 그 일을 100% 사람 손으로 합니다.
          숨기지 않고 전 과정을 공개할게요.
        </p>
        <Code>{CODE_MANUAL_DEPLOY}</Code>
        <p>
          한두 번은 할 만해요. 문제는 <strong>반복</strong>입니다. 급식실에서 배식을 매번
          다른 사람이, 매번 다른 국자로, 매번 기억에 의존해서 한다고 상상해 보세요.
          어떤 날은 양이 다르고, 어떤 날은 반찬 하나를 빼먹겠죠. 배포도 똑같아요 —
          <strong> 사람이 반복하면 반드시 어딘가에서 실수가 납니다.</strong>
        </p>
        <Code>{CODE_HUMAN_ERROR}</Code>
        <div className="warn">
          <b>진짜 비용은 시간이 아니라 두려움</b> — 배포가 무서우면 개발자는 배포를
          미루게 되고, 미룰수록 한 번에 나가는 변경이 커져서 더 위험해지는 악순환에 빠져요.
          자동화의 목표는 "배포가 <strong>지루할 만큼 안전한</strong> 일"이 되게 하는 겁니다.
        </div>
      </Section>

      <Section n={2} title="CI — 합칠 때마다 자동 검사" sub="Continuous Integration, 지속적 통합">
        <p>
          <strong>CI</strong>는 코드가 저장소에 합쳐질 때마다(= push될 때마다) 로봇이
          <strong> 자동으로 빌드하고 테스트</strong>하는 거예요. 공장 컨베이어 벨트 끝의
          품질 검사 기계를 떠올리면 됩니다 — 제품이 지나갈 때마다 예외 없이, 같은 기준으로 검사하죠.
        </p>
        <Code>{CODE_CI_FLOW}</Code>
        <p>
          왜 "합칠 때마다"가 중요할까요? 버그는 <strong>일찍 잡을수록 싸게</strong> 고쳐져요.
          방금 push한 코드가 빨간불이면 "아, 내가 아까 고친 그 부분이구나" 하고 바로 찾지만,
          한 달 치 코드를 몰아서 검사하면 어디가 범인인지 수사부터 해야 하거든요.
          시험 공부도 매일 조금씩 확인하는 쪽이 벼락치기보다 구멍을 빨리 찾는 것과 같아요.
        </p>
        <div className="tip">
          <b>용어 정리</b> <span className="icode">Integration(통합)</span>은 여러 사람의
          코드를 한 저장소에 합치는 일, <span className="icode">Continuous(지속적)</span>는
          "가끔 크게"가 아니라 "자주 조금씩"이라는 뜻이에요. 합칠 때마다 검사하니까
          <strong> 지속적 통합</strong>.
        </div>
      </Section>

      <Section n={3} title="CD — 통과하면 자동 배포" sub="Continuous Deployment, 지속적 배포">
        <p>
          CI가 초록불을 켰다면, 그 다음은요? 검사까지 로봇이 해 놓고 배포는 다시 사람이
          scp를 친다면 반쪽짜리죠. <strong>CD</strong>는 검사를 통과한 코드를
          <strong> 서버에 올리는 것까지 자동</strong>으로 이어 주는 겁니다.
        </p>
        <Code>{CODE_CD_FLOW}</Code>
        <p>
          섹션 1의 7단계 수동 배포와 비교해 보세요. 사람이 하던 빌드·복사·재시작이 전부
          로봇 몫이 되고, 사람에게 남는 일은 <span className="icode">git push</span> 하나예요.
          더 좋은 건 <strong>기록</strong>이에요. 로봇은 언제, 누구의 커밋을, 어떤 검사를 거쳐
          배포했는지 전부 로그로 남깁니다. "누가 언제 배포했지?"라는 질문이 사라져요.
        </p>
        <div className="tip">
          <b>비슷한 말 구분</b> CD는 두 가지로 불려요.
          <span className="icode">Continuous Delivery</span>(자동으로 배포 준비까지, 마지막
          버튼은 사람이) vs <span className="icode">Continuous Deployment</span>(버튼까지 자동).
          입문 단계에선 "통과하면 알아서 나간다"로 묶어 이해해도 충분합니다.
        </div>
      </Section>

      <Section n={4} title="파이프라인 — 푸시에서 배포까지 한 장의 그림" sub="push → 빌드 → 테스트 → 배포">
        <p>
          CI와 CD를 이어 붙인 전체 흐름을 <strong>파이프라인</strong>이라고 불러요.
          말 그대로 파이프(관)예요 — 코드가 한쪽 끝(push)으로 들어가면 정해진 정거장들을
          차례로 지나 반대쪽 끝(서비스 중인 서버)으로 나옵니다.
        </p>
        <Code>{CODE_PIPELINE}</Code>
        <p>
          가장 중요한 성질은 <strong>"실패하면 멈춘다"</strong>예요. 테스트가 깨진 코드는
          배포 단계에 절대 도착하지 못합니다. 섹션 1의 "테스트 없이 배포 → 서버에서 500 에러
          폭발" 사고가 <strong>구조적으로 불가능</strong>해지는 거죠. 사람의 꼼꼼함을 믿는 게
          아니라, 벨트의 구조가 불량품을 걸러내는 겁니다.
        </p>
        <svg className="diagram" viewBox="0 0 640 250" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="파이프라인 도해: git push가 빌드, 테스트, 배포, 확인 정거장을 순서대로 지나고, 어느 정거장에서든 실패하면 벨트가 멈추고 개발자에게 알림이 간다">
          <text x="258" y="32" textAnchor="middle" fontSize="12" fill="var(--teal)">통과</text>
          <text x="383" y="32" textAnchor="middle" fontSize="12" fill="var(--teal)">통과</text>
          <text x="508" y="32" textAnchor="middle" fontSize="12" fill="var(--teal)">통과</text>
          <rect x="20" y="40" width="100" height="56" rx="8" fill="var(--card)" stroke="var(--primary)" strokeWidth="1.5" />
          <text x="70" y="72" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">git push</text>
          <rect x="145" y="40" width="100" height="56" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="195" y="64" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">① 빌드</text>
          <text x="195" y="82" textAnchor="middle" fontSize="12" fill="var(--muted)">조립이 되나?</text>
          <rect x="270" y="40" width="100" height="56" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="320" y="64" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">② 테스트</text>
          <text x="320" y="82" textAnchor="middle" fontSize="12" fill="var(--muted)">작동하나?</text>
          <rect x="395" y="40" width="100" height="56" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="445" y="64" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">③ 배포</text>
          <text x="445" y="82" textAnchor="middle" fontSize="12" fill="var(--muted)">새 버전 교체</text>
          <rect x="520" y="40" width="100" height="56" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="570" y="64" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">④ 확인</text>
          <text x="570" y="82" textAnchor="middle" fontSize="12" fill="var(--muted)">헬스체크</text>
          <line x1="122" y1="68" x2="137" y2="68" stroke="var(--muted)" strokeWidth="1.5" />
          <path d="M136 63 L143 68 L136 73 Z" fill="var(--muted)" />
          <line x1="247" y1="68" x2="262" y2="68" stroke="var(--muted)" strokeWidth="1.5" />
          <path d="M261 63 L268 68 L261 73 Z" fill="var(--muted)" />
          <line x1="372" y1="68" x2="387" y2="68" stroke="var(--muted)" strokeWidth="1.5" />
          <path d="M386 63 L393 68 L386 73 Z" fill="var(--muted)" />
          <line x1="497" y1="68" x2="512" y2="68" stroke="var(--muted)" strokeWidth="1.5" />
          <path d="M511 63 L518 68 L511 73 Z" fill="var(--muted)" />
          <line x1="195" y1="96" x2="240" y2="180" stroke="var(--rose)" strokeDasharray="4 4" />
          <line x1="320" y1="96" x2="310" y2="180" stroke="var(--rose)" strokeDasharray="4 4" />
          <line x1="445" y1="96" x2="380" y2="180" stroke="var(--rose)" strokeDasharray="4 4" />
          <line x1="570" y1="96" x2="450" y2="180" stroke="var(--rose)" strokeDasharray="4 4" />
          <text x="505" y="150" fontSize="12" fill="var(--rose)">어디서든 실패하면</text>
          <rect x="170" y="180" width="310" height="52" rx="8" fill="var(--card)" stroke="var(--rose)" strokeWidth="1.5" />
          <text x="325" y="202" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--rose)">실패 — 그 자리에서 벨트 정지</text>
          <text x="325" y="220" textAnchor="middle" fontSize="12" fill="var(--muted)">배포하지 않음 + 개발자에게 알림</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: 푸시 → 빌드 → 테스트 → 배포 → 확인 파이프라인 — 실패하면 즉시 멈추고 알림이 간다</p>
        <div className="tip">
          <b>직접 확인해 보기</b> 종이에 위 파이프라인 그림을 보지 않고 다시 그려 보세요.
          그리고 각 정거장 옆에 우리 스택의 실제 명령을 채워 넣어 보세요 — ①번 옆에
          <span className="icode">npm run build</span>와 <span className="icode">./mvnw package</span>,
          ③번 옆에 <span className="icode">docker</span>... 이 그림 한 장을 스스로 그릴 수 있으면
          이 코스의 절반은 끝난 거예요.
        </div>
      </Section>

      <Section n={5} title="도구들 — Gitea Actions와 Jenkins" sub="파이프라인을 굴려 주는 로봇들 (개념만!)">
        <p>
          파이프라인은 개념이고, 그걸 실제로 돌려 주는 <strong>도구</strong>가 따로 있어요.
          우리에게 제일 가까운 건 <strong>Gitea Actions</strong>입니다 — 매일 코드를 올리는
          우리 Gitea(<span className="icode">edu.awesomedevapp.com:3000</span>)에 이미 이 기능이
          들어 있거든요.
        </p>
        <Code>{CODE_TOOLS}</Code>
        <p>
          도구는 달라도 원리는 하나예요. <strong>"push가 오면 이 명령들을 실행해"라는 각본을
          파일로 써서 저장소에 넣는다.</strong> 그 각본을 워크플로(workflow)라고 불러요.
          어떻게 생겼는지만 살짝 구경해 볼까요?
        </p>
        <Code>{CODE_WORKFLOW_TASTE}</Code>
        <div className="tip">
          <b>직접 확인해 보기</b> Gitea(<span className="icode">edu.awesomedevapp.com:3000</span>)에
          로그인해서 우리 저장소를 열고, 파일 목록에서 <span className="icode">.gitea/workflows/</span>
          폴더가 있는지 찾아보세요. 있다면 안의 <span className="icode">.yml</span> 파일을 열어
          "on:"(언제 깨어나나)과 "run:"(무슨 명령을 치나) 줄을 소리 내어 읽어 보세요.
          아직 없다면? 그게 정상이에요 — 이 코스의 마지막 실습이 바로 그 첫 파일의 설계도니까요.
        </div>
      </Section>

      <Section n={6} title="배포 전략 한 입 — 롤백이 전부다" sub="새 버전이 망했을 때, 1분 안에 되돌리기">
        <p>
          자동 배포가 되면 끝일까요? 아니요 — 검사를 다 통과하고도 <strong>실제 서버에서만
          터지는 문제</strong>는 반드시 생겨요(진짜 사용자, 진짜 데이터, 진짜 트래픽은 테스트와
          다르니까요). 그래서 프로 팀의 질문은 "장애가 날까?"가 아니라
          <strong> "장애가 났을 때 얼마나 빨리 되돌릴 수 있나?"</strong>입니다.
        </p>
        <Code>{CODE_ROLLBACK}</Code>
        <p>
          우리 스택에서 롤백의 열쇠는 <strong>Docker</strong>예요. 버전마다 이미지를 태그로
          보관해 두면, 되돌리기는 "옛 이미지로 컨테이너 다시 실행" 한 줄이 됩니다. 서버에서
          코드를 다시 고치는 게 아니라, <strong>통째로 포장된 이전 버전을 꺼내 오는 것</strong> —
          이게 수동 시절엔 상상하기 어려웠던 속도의 비밀이에요.
        </p>
        <svg className="diagram" viewBox="0 0 640 250" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="롤백 도해: v1.3 배포 후 장애가 발생하면 보관해 둔 v1.2 도커 이미지를 꺼내 1분 만에 원복하고, 원인 조사는 그 다음에 한다">
          <rect x="20" y="36" width="130" height="56" rx="8" fill="var(--card)" stroke="var(--primary)" strokeWidth="1.5" />
          <text x="85" y="60" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">v1.3 배포</text>
          <text x="85" y="78" textAnchor="middle" fontSize="12" fill="var(--muted)">새 버전이 나감</text>
          <rect x="170" y="36" width="130" height="56" rx="8" fill="var(--card)" stroke="var(--rose)" strokeWidth="1.5" />
          <text x="235" y="60" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--rose)">장애 발생!</text>
          <text x="235" y="78" textAnchor="middle" fontSize="12" fill="var(--muted)">실서버에서만 터짐</text>
          <rect x="320" y="36" width="130" height="56" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="385" y="60" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">v1.2로 원복</text>
          <text x="385" y="78" textAnchor="middle" fontSize="12" fill="var(--muted)">1분 만에 되돌림</text>
          <rect x="470" y="36" width="130" height="56" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="535" y="60" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">원인 조사</text>
          <text x="535" y="78" textAnchor="middle" fontSize="12" fill="var(--muted)">차분히, 그 다음에</text>
          <line x1="152" y1="64" x2="162" y2="64" stroke="var(--muted)" strokeWidth="1.5" />
          <path d="M161 59 L168 64 L161 69 Z" fill="var(--muted)" />
          <line x1="302" y1="64" x2="312" y2="64" stroke="var(--muted)" strokeWidth="1.5" />
          <path d="M311 59 L318 64 L311 69 Z" fill="var(--muted)" />
          <line x1="452" y1="64" x2="462" y2="64" stroke="var(--muted)" strokeWidth="1.5" />
          <path d="M461 59 L468 64 L461 69 Z" fill="var(--muted)" />
          <rect x="20" y="160" width="280" height="56" rx="8" fill="var(--card)" stroke="var(--line)" />
          <rect x="40" y="172" width="70" height="32" rx="6" fill="var(--card)" stroke="var(--line)" />
          <text x="75" y="192" textAnchor="middle" fontSize="12" fill="var(--muted)">v1.1</text>
          <rect x="125" y="172" width="70" height="32" rx="6" fill="var(--card)" stroke="var(--teal)" strokeWidth="2" />
          <text x="160" y="192" textAnchor="middle" fontSize="12" fontWeight="600" fill="var(--ink)">v1.2</text>
          <rect x="210" y="172" width="70" height="32" rx="6" fill="var(--card)" stroke="var(--line)" />
          <text x="245" y="192" textAnchor="middle" fontSize="12" fill="var(--muted)">v1.3</text>
          <text x="160" y="236" textAnchor="middle" fontSize="12" fill="var(--muted)">버전마다 태그로 보관 (Docker 이미지)</text>
          <polyline points="160,172 160,128 385,128 385,99" fill="none" stroke="var(--teal)" strokeWidth="1.5" strokeDasharray="5 4" strokeLinecap="round" />
          <path d="M380 104 L385 97 L390 104 Z" fill="var(--teal)" />
          <text x="272" y="120" textAnchor="middle" fontSize="12" fill="var(--teal)">보관해 둔 v1.2를 꺼내 재실행</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: 롤백 — 태그로 보관한 이전 이미지(v1.2)를 꺼내 1분 만에 원복한다</p>
        <div className="warn">
          <b>롤백 없는 자동 배포는 더 위험할 수도</b> — 사람 손 배포는 느려서라도 조심하는데,
          자동 배포는 잘못된 버전도 빛의 속도로 나갑니다. 그래서 자동화를 설계할 땐
          <strong> 나가는 길(배포)과 돌아오는 길(롤백)을 반드시 세트로</strong> 만들어야 해요.
        </div>
      </Section>

      <Section n={7} title="실습 — 우리 플랫폼의 자동화 지도 그리기" sub="손으로 그려야 진짜 내 것이 됩니다">
        <p>
          이제 배운 걸 전부 모아 <strong>진짜 설계</strong>를 해볼 시간이에요. 도구 설치도,
          코드 작성도 없어요. 필요한 건 종이와 펜, 그리고 섹션 1의 우리 배포 과정입니다.
        </p>
        <Code>{CODE_PRACTICE_MAP}</Code>
        <p>
          이 실습이 중요한 이유: 현업에서 자동화가 실패하는 가장 큰 원인은 도구를 몰라서가
          아니라, <strong>자기 팀의 현재 과정을 정확히 모르는 채</strong> 도구부터 붙이기
          때문이에요. 지도를 먼저 그리는 사람이 길을 냅니다.
        </p>
        <div className="tip">
          <b>다 그렸다면</b> 완성한 지도를 멘토에게 보여 주고 두 가지를 물어보세요 —
          "제가 그린 ★ 순서에 동의하시나요?", "제가 빠뜨린 단계가 있나요?"
          멘토가 추가하는 단계(환경 변수 설정, DB 마이그레이션 같은)가
          바로 여러분이 아직 못 본 <strong>배포의 빙산 아랫부분</strong>입니다.
        </div>
      </Section>

      <div className="step-card">
        <div className="step-body">
          <h3 style={{ marginBottom: 6 }}>🤖 여기까지 왔다면</h3>
          <p className="muted">
            이제 여러분은 <strong>수동 배포의 고통 → CI(자동 검사) → CD(자동 배포) →
            파이프라인 → 롤백</strong>까지, 배포 자동화의 뼈대를 전부 갖췄어요. 파이프라인이
            올라탈 무대가 궁금하다면 <Link to="/learn/network"><strong>네트워크의 이해</strong></Link> 코스에서
            서버까지 데이터가 가는 길을, 파이프라인이 실어 나르는 상자가 궁금하다면
            Docker 관련 코스에서 컨테이너를 이어서 배워 보세요. 그리고 실습에서 그린
            자동화 지도는 버리지 마세요 — 우리 플랫폼에 Gitea Actions를 실제로 붙이는 날,
            그 종이가 첫 워크플로 파일의 설계도가 됩니다.
          </p>
        </div>
      </div>
    </div>
  );
}
