<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>write31991 님의 블로그</title>
    <link>https://write31991.tistory.com/</link>
    <description>write31991 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Wed, 28 Oct 2026 11:46:38 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>write31991</managingEditor>
    <item>
      <title>FastAPI 4일차</title>
      <link>https://write31991.tistory.com/37</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h1&gt;⚡ FastAPI &amp;amp; asyncio 비동기 프로그래밍, 의존성 주입(DI) &amp;amp; 스레드 풀 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content--fastapi--asyncio-비동기-프로그래밍-의존성-주입di--스레드-풀-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#-fastapi--asyncio-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85di--%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI의 핵심 아키텍처인 **자원 관리(try-finally ➔ Context Manager ➔ Depends 의존성 주입)**부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;클라이언트 요청-응답 4단계 라이프사이클&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;응답 속도를 극대화하는 Background Tasks&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;비동기(asyncio)의 본질과 컴퓨터 하드웨어(RAM vs Disk I/O) 속도 차이&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;코루틴(Coroutine)과 '세 쌍둥이 밥 먹이기' 이벤트 루프(Event Loop)의 원리&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;await를 쓰는 2대 필수 조건과 체이닝 실습&lt;/b&gt;, 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;FastAPI가 동기 함수(def)를 이벤트 루프 블로킹 없이 처리하는 비밀인 스레드 풀(Thread Pool)과 Lifespan 제어&lt;/b&gt;까지 총정리한 실무 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#1-%EC%9E%90%EC%9B%90-%EA%B4%80%EB%A6%AC%EC%9D%98-%EC%A7%84%ED%99%94-try-finally%EC%97%90%EC%84%9C-context-manager%EA%B9%8C%EC%A7%80&quot;&gt;자원 관리의 진화: try-finally에서 Context Manager까지&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#1-1-try-except-finally-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC-3%EB%8C%80-%EB%B8%94%EB%A1%9D%EC%9D%98-%EC%97%AD%ED%95%A0&quot;&gt;1-1. try-except-finally 예외 처리 3대 블록의 역할&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#1-2-db-%EC%84%B8%EC%85%98%EC%97%90%EC%84%9C-finally%EA%B0%80-%ED%95%84%EC%88%98%EC%A0%81%EC%9D%B8-%EC%9D%B4%EC%9C%A0-return%EB%B3%B4%EB%8B%A4-%EB%8A%A6%EA%B2%8C-%EB%8B%AB%ED%9E%88%EB%8A%94-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0&quot;&gt;1-2. DB 세션에서 finally가 필수적인 이유 (return보다 늦게 닫히는 문제 해결)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#1-3-context-manager-with-sessionfactory-as-session%EC%9D%98-%EC%9E%90%EB%8F%99-%EB%92%B7%EC%A0%95%EB%A6%AC-%EB%A7%88%EB%B2%95&quot;&gt;1-3. Context Manager (with SessionFactory() as session:)의 자동 뒷정리 마법&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#2-fastapi-%EB%9D%BC%EC%9A%B0%ED%8C%85%EA%B3%BC-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%9A%94%EC%B2%AD-%EC%9D%91%EB%8B%B5-4%EB%8B%A8%EA%B3%84-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4&quot;&gt;FastAPI 라우팅과 클라이언트 요청-응답 4단계 라이프사이클&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#2-1-%EB%9D%BC%EC%9A%B0%ED%8C%85routing%EC%9D%98-%EB%B3%B8%EC%A7%88-%EB%8F%84%EB%A1%9C-%ED%91%9C%EC%A7%80%ED%8C%90%EA%B3%BC-http-method--url-%EB%A7%A4%ED%95%91&quot;&gt;2-1. 라우팅(Routing)의 본질: 도로 표지판과 HTTP Method + URL 매핑&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#2-2--%EC%9A%94%EC%B2%AD%EB%B6%80%ED%84%B0-%EC%9D%91%EB%8B%B5%EA%B9%8C%EC%A7%80%EC%9D%98-4%EB%8B%A8%EA%B3%84-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-%EC%A0%84%EC%B2%B4-%ED%9D%90%EB%A6%84%EB%8F%84&quot;&gt;2-2.   요청부터 응답까지의 4단계 라이프사이클 전체 흐름도&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#3-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-dependency-injection-di-with-%EA%B5%AC%EB%AC%B8%EB%A7%88%EC%A0%80-%EC%A7%80%EC%9A%B0%EB%8A%94-%EB%B9%84%EA%B2%B0&quot;&gt;의존성 주입 (Dependency Injection, DI): with 구문마저 지우는 비결&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#3-1-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85di%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-%EC%9E%90%EC%9B%90-%EC%83%9D%EC%84%B1%EA%B3%BC-%EB%A0%8C%ED%83%88-%EA%B0%9C%EB%85%90&quot;&gt;3-1. 의존성 주입(DI)이란 무엇인가? (자원 생성과 렌탈 개념)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#3-2-yield-%ED%82%A4%EC%9B%8C%EB%93%9C%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%84%B8%EC%85%98-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0-get_session&quot;&gt;3-2.&amp;nbsp;yield&amp;nbsp;키워드를 활용한 세션 팩토리 제너레이터 (get_session())&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#3-3-dependsget_session-%EC%8B%A4%EC%A0%84-%EC%A0%81%EC%9A%A9%EA%B3%BC-%EC%97%94%EB%93%9C%ED%8F%AC%EC%9D%B8%ED%8A%B8-%EA%B7%B9%EB%8B%A8%EC%A0%81-%EB%8B%A8%EC%88%9C%ED%99%94&quot;&gt;3-3.&amp;nbsp;Depends(get_session)&amp;nbsp;실전 적용과 엔드포인트 극단적 단순화&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#4-background-tasks-%EB%B0%B1%EA%B7%B8%EB%9D%BC%EC%9A%B4%EB%93%9C-%ED%83%9C%EC%8A%A4%ED%81%AC&quot;&gt;Background Tasks (백그라운드 태스크)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#4-1-%EC%9A%94%EC%B2%AD-%EC%9D%91%EB%8B%B5-%EC%9D%B4%ED%9B%84-%EC%8B%A4%ED%96%89%EC%9D%98-%EC%9D%98%EB%AF%B8%EC%99%80-%EC%B2%B4%EA%B0%90-%EC%9D%91%EB%8B%B5-%EC%86%8D%EB%8F%84-%EA%B7%B9%EB%8C%80%ED%99%94&quot;&gt;4-1. 요청-응답 이후 실행의 의미와 체감 응답 속도 극대화&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#4-2-%EC%8B%A4%EC%A0%84-%EC%BD%94%EB%93%9C-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%ED%9B%84-5%EC%B4%88-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EB%B0%9C%EC%86%A1-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC&quot;&gt;4-2. 실전 코드: 회원가입 후 5초 이메일 발송 비동기 처리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#4-3-background-tasks-%EC%82%AC%EC%9A%A9-%EC%8B%9C-%EC%A3%BC%EC%9D%98%EC%A0%90-%EB%AC%B4%EA%B1%B0%EC%9A%B4-%EC%9E%91%EC%97%85%EA%B3%BC-celeryredis-%EB%B9%84%EA%B5%90&quot;&gt;4-3. Background Tasks 사용 시 주의점 (무거운 작업과 Celery/Redis 비교)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-asyncio%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0&quot;&gt;비동기 프로그래밍 (asyncio)의 본질과 컴퓨터 구조&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-1-%EB%8F%99%EA%B8%B0synchronous%EC%9D%98-%ED%95%9C%EA%B3%84%EC%99%80-io-bound-%EC%9E%91%EC%97%85%EC%9D%98-%EB%B9%84%ED%9A%A8%EC%9C%A8&quot;&gt;5-1. 동기(Synchronous)의 한계와 I/O Bound 작업의 비효율&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-2-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EB%A1%9C-%EB%B3%B4%EB%8A%94-%EC%86%8D%EB%8F%84-%EC%B0%A8%EC%9D%B4-%EB%B9%9B%EC%B2%98%EB%9F%BC-%EB%B9%A0%EB%A5%B8-cpuram-vs-%EB%AA%A9-%EB%B9%A0%EC%A7%80%EB%8A%94-disknetwork-io&quot;&gt;5-2. 컴퓨터 구조로 보는 속도 차이 (빛처럼 빠른 CPU/RAM vs 목 빠지는 Disk/Network I/O)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-3-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%9D%98-%EC%9D%BC%EC%83%81-%EB%B9%84%EC%9C%A0-%EB%9D%BC%EB%A9%B4-%EB%81%93%EC%9D%B4%EA%B8%B0%EC%99%80-%EC%A3%BC%EB%AC%B8-%EC%A0%91%EC%88%98&quot;&gt;5-3. 비동기의 일상 비유: 라면 끓이기와 주문 접수&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-4-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%91%9C%EC%A4%80-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-asyncio&quot;&gt;5-4. 파이썬 표준 라이브러리&amp;nbsp;asyncio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-%EC%BD%94%EB%A3%A8%ED%8B%B4coroutine%EA%B3%BC-%ED%98%91%EB%A0%A5%EC%A0%81-%EB%A9%80%ED%8B%B0%ED%83%9C%EC%8A%A4%ED%82%B9&quot;&gt;코루틴(Coroutine)과 협력적 멀티태스킹&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-1-%EC%BD%94%EB%A3%A8%ED%8B%B4%EC%9D%98-%EC%A0%95%EC%9D%98-%EB%84%88-%ED%95%9C-%EB%B2%88-%EB%82%98-%ED%95%9C-%EB%B2%88-%ED%98%91%EB%A0%A5co-routine%ED%95%98%EB%8A%94-%ED%95%A8%EC%88%98&quot;&gt;6-1. 코루틴의 정의: &quot;너 한 번, 나 한 번&quot; 협력(co-routine)하는 함수&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-2-%EC%BD%94%EB%A3%A8%ED%8B%B4-%ED%95%A8%EC%88%98async-def-vs-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EA%B0%9D%EC%B2%B4-%EC%99%9C-%EB%B0%94%EB%A1%9C-%EC%8B%A4%ED%96%89%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94%EA%B0%80&quot;&gt;6-2. 코루틴 함수(async def) vs 코루틴 객체 (왜 바로 실행되지 않는가?)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-3-asynciorun%EA%B3%BC-asynciogather%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%8F%99%EC%8B%9C-%EC%8B%A4%ED%96%89-%ED%8C%A8%ED%82%A4%EC%A7%95&quot;&gt;6-3.&amp;nbsp;asyncio.run()과&amp;nbsp;asyncio.gather()를 통한 동시 실행 패키징&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-4-%EB%8F%99%EA%B8%B0-vs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%8B%A4%ED%96%89-%EC%8B%9C%EA%B0%84-%EB%B2%A4%EC%B9%98%EB%A7%88%ED%81%AC-4%EC%B4%88--2%EC%B4%88-%EB%8B%A8%EC%B6%95&quot;&gt;6-4. 동기 vs 비동기 실행 시간 벤치마크 (4초 ➔ 2초 단축)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-await-%ED%82%A4%EC%9B%8C%EB%93%9C%EC%99%80-%EC%96%91%EB%B3%B4yield-control%EC%9D%98-%EB%AF%B8%ED%95%99&quot;&gt;await&amp;nbsp;키워드와 양보(Yield Control)의 미학&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-1-await-%EC%97%AC%EA%B8%B0%EC%84%9C-%EC%9E%A0%EA%B9%90-%EB%A9%88%EC%B6%94%EA%B3%A0-%EC%A0%9C%EC%96%B4%EA%B6%8C%EC%9D%84-%EB%84%98%EA%B2%A8%EB%9D%BC&quot;&gt;7-1.&amp;nbsp;await: &quot;여기서 잠깐 멈추고 제어권을 넘겨라!&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-2--await%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-2%EA%B0%80%EC%A7%80-%EC%A0%88%EB%8C%80-%EC%A1%B0%EA%B1%B4&quot;&gt;7-2. ⭐ await를 사용하는 2가지 절대 조건&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-3-%EC%96%B4%EB%96%A4-%EC%9E%91%EC%97%85%EC%9D%B4-awaitable%ED%95%9C%EA%B0%80-%ED%8C%90%EB%8B%A8-3%EB%8B%A8%EA%B3%84-%EA%B3%B5%EC%8B%9D&quot;&gt;7-3. 어떤 작업이 Awaitable한가? (판단 3단계 공식)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-4-%EC%8B%A4%EC%8A%B5-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EC%B2%B4%EC%9D%B4%EB%8B%9D-%ED%8D%BC%EC%A6%90-%EC%B6%9C%EB%A0%A5-%EC%88%9C%EC%84%9C-%EC%A0%9C%EC%96%B4-%EC%99%84%EC%84%B1&quot;&gt;7-4. [실습] 코루틴 체이닝 퍼즐 (출력 순서 제어 완성)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#8-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84event-loop%EC%99%80-%EB%B8%94%EB%A1%9C%ED%82%B9blocking-%EA%B8%88%EC%A7%80%EC%9D%98-%EB%B2%95%EC%B9%99&quot;&gt;이벤트 루프(Event Loop)와 블로킹(Blocking) 금지의 법칙&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#8-1-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84%EB%9E%80-%EC%84%B8-%EC%8C%8D%EB%91%A5%EC%9D%B4-%EB%B0%A5-%EB%A8%B9%EC%9D%B4%EA%B8%B0-%EC%99%84%EB%B2%BD-%EB%B9%84%EC%9C%A0&quot;&gt;8-1. 이벤트 루프란? (&quot;세 쌍둥이 밥 먹이기&quot; 완벽 비유)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#8-2--%EC%A0%88%EB%8C%80-%EA%B7%9C%EC%B9%99-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84%EB%A5%BC-%EB%B8%94%EB%A1%9C%ED%82%B9%ED%95%98%EB%A9%B4-%EC%84%9C%EB%B2%84-%EC%A0%84%EC%B2%B4%EA%B0%80-%EC%96%BC%EC%96%B4%EB%B6%99%EB%8A%94%EB%8B%A4&quot;&gt;8-2.   절대 규칙: 이벤트 루프를 블로킹하면 서버 전체가 얼어붙는다!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#9-fastapi-%EB%82%B4%EB%B6%80-%EB%8F%99%EC%9E%91%EC%9D%98-%EB%B9%84%EB%B0%80-%EB%8F%99%EA%B8%B0-%ED%95%A8%EC%88%98def%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80thread-pool&quot;&gt;FastAPI 내부 동작의 비밀: 동기 함수(def)와 스레드 풀(Thread Pool)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#9-1-fastapi%EB%8A%94-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%9D%B8%EB%8D%B0-%EC%99%9C-%EC%9A%B0%EB%A6%B0-%EC%A7%80%EA%B8%88%EA%B9%8C%EC%A7%80-def-%EC%9D%BC%EB%B0%98-%ED%95%A8%EC%88%98%EB%A5%BC-%EC%8D%BC%EC%9D%84%EA%B9%8C&quot;&gt;9-1. &quot;FastAPI는 비동기인데 왜 우린 지금까지&amp;nbsp;def&amp;nbsp;일반 함수를 썼을까?&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#9-2-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80thread-pool%EC%9D%98-%EB%8C%80%EB%A6%AC-%EC%8B%A4%ED%96%89-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98-run_endpoint_function&quot;&gt;9-2. 스레드 풀(Thread Pool)의 대리 실행 메커니즘 (run_endpoint_function)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#9-3-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80-%ED%81%AC%EA%B8%B0-%EC%A1%B0%EC%A0%88%EA%B3%BC-lifespan-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%A7%A4%EB%8B%88%EC%A0%80-%EA%B8%B0%EB%B3%B8-40%EA%B0%9C--200%EA%B0%9C-%EC%83%81%ED%96%A5&quot;&gt;9-3. 스레드 풀 크기 조절과 Lifespan 컨텍스트 매니저 (기본 40개 ➔ 200개 상향)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#10--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 자원 관리의 진화: try-finally에서 Context Manager까지&lt;/h2&gt;
&lt;a id=&quot;user-content-1-자원-관리의-진화-try-finally에서-context-manager까지&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#1-%EC%9E%90%EC%9B%90-%EA%B4%80%EB%A6%AC%EC%9D%98-%EC%A7%84%ED%99%94-try-finally%EC%97%90%EC%84%9C-context-manager%EA%B9%8C%EC%A7%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. try-except-finally 예외 처리 3대 블록의 역할&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-try-except-finally-예외-처리-3대-블록의-역할&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#1-1-try-except-finally-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC-3%EB%8C%80-%EB%B8%94%EB%A1%9D%EC%9D%98-%EC%97%AD%ED%95%A0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;파이썬의 예외 처리는 프로그램이 예기치 못한 에러로 강제 종료(크래시)되는 것을 막고, 사용한 시스템 자원을 안전하게 반납하기 위한 핵심 문법입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;1164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJBFHY/dJMcab7hD3W/D3BUWOXoL5Q7RlKl8GGjK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJBFHY/dJMcab7hD3W/D3BUWOXoL5Q7RlKl8GGjK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJBFHY/dJMcab7hD3W/D3BUWOXoL5Q7RlKl8GGjK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJBFHY%2FdJMcab7hD3W%2FD3BUWOXoL5Q7RlKl8GGjK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;224&quot; height=&quot;425&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;1164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;try&lt;/b&gt;: 에러가 발생할 가능성이 있는 코드를 실행. 에러가 나면 즉시 실행을 멈추고&lt;span&gt;&amp;nbsp;&lt;/span&gt;except로 점프.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;except&lt;/b&gt;: 발생한 에러를 잡아내어 대처(로그 기록, 사용자 친화적 메시지 출력 등).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;finally&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;예외 발생 여부와 상관없이 무조건 마지막에 실행되는 구역&lt;/b&gt;. 파일 닫기(f.close()), 네트워크 연결 종료, 데이터베이스 세션 종료(session.close()) 등에 필수적입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;except&lt;span&gt;&amp;nbsp;&lt;/span&gt;생략 가능&lt;/b&gt;: 에러 처리는 상위로 넘기되 뒷정리만 확실히 하고 싶다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;try - finally&lt;span&gt;&amp;nbsp;&lt;/span&gt;구조로만 작성할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. DB 세션에서 finally가 필수적인 이유 (return보다 늦게 닫히는 문제 해결)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-2-db-세션에서-finally가-필수적인-이유-return보다-늦게-닫히는-문제-해결&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#1-2-db-%EC%84%B8%EC%85%98%EC%97%90%EC%84%9C-finally%EA%B0%80-%ED%95%84%EC%88%98%EC%A0%81%EC%9D%B8-%EC%9D%B4%EC%9C%A0-return%EB%B3%B4%EB%8B%A4-%EB%8A%A6%EA%B2%8C-%EB%8B%AB%ED%9E%88%EB%8A%94-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;livecodeserver&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;def get_items_handler():
    session = SessionFactory()
    try:
        stmt = select(Item)
        items = session.scalars(stmt).all()
        return items  # ⚠️ 여기서 함수가 즉시 종료됨!
        # session.close() 를 여기에 적으면 절대 도달할 수 없음(Dead Code)!
    finally:
        session.close()  # ✅ return이 실행되기 직전에 무조건 실행되어 세션을 안전하게 닫음!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 세션을 열었으면 데이터를 다 쓰고 난 뒤 반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.close()로 커넥션을 반납해야 커넥션 풀 누수(Memory Leak)가 발생하지 않습니다.&lt;/li&gt;
&lt;li&gt;하지만 함수 중간에&lt;span&gt;&amp;nbsp;&lt;/span&gt;return items를 만나면 함수가 그 즉시 끝나버립니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;finally&lt;span&gt;&amp;nbsp;&lt;/span&gt;블록을 사용하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;return&lt;span&gt;&amp;nbsp;&lt;/span&gt;문을 만나더라도 파이썬 엔진이 그 직전에&lt;span&gt;&amp;nbsp;&lt;/span&gt;finally&lt;span&gt;&amp;nbsp;&lt;/span&gt;내부 코드를 먼저 실행하고 함수를 빠져나갑니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3. Context Manager (with SessionFactory() as session:)의 자동 뒷정리 마법&lt;/h3&gt;
&lt;a id=&quot;user-content-1-3-context-manager-with-sessionfactory-as-session의-자동-뒷정리-마법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#1-3-context-manager-with-sessionfactory-as-session%EC%9D%98-%EC%9E%90%EB%8F%99-%EB%92%B7%EC%A0%95%EB%A6%AC-%EB%A7%88%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;매번 모든 API 엔드포인트마다&lt;span&gt;&amp;nbsp;&lt;/span&gt;session = SessionFactory(),&lt;span&gt;&amp;nbsp;&lt;/span&gt;try:,&lt;span&gt;&amp;nbsp;&lt;/span&gt;finally: session.close()를 반복해서 적는 것은 코드가 지저분해지고 번거롭습니다.&lt;br /&gt;파이썬의 **컨텍스트 매니저 (Context Manager,&lt;span&gt;&amp;nbsp;&lt;/span&gt;with&lt;span&gt;&amp;nbsp;&lt;/span&gt;문)**를 사용하면 이 모든 과정을 한 줄로 축약할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;crystal&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;def get_items_handler():
    # with 문 진입 시 자동으로 session이 열리고, 블록을 벗어날 때 자동으로 session.close() 호출!
    with SessionFactory() as session:
        stmt = select(Item)
        items = session.scalars(stmt).all()
        return items&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;⚙ with 문 동작 메커니즘:&lt;/h4&gt;
&lt;a id=&quot;user-content--with-문-동작-메커니즘&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#-with-%EB%AC%B8-%EB%8F%99%EC%9E%91-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;with SessionFactory() as session:에 진입하는 순간 세션 인스턴스가 생성됩니다 (__enter__).&lt;/li&gt;
&lt;li&gt;블록 내부 코드가 정상적으로 끝나든, 중간에&lt;span&gt;&amp;nbsp;&lt;/span&gt;return을 만나든, 에러가 발생해 튕겨 나가든 상관없이,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;들여쓰기가 끝나는 순간 컨텍스트 매니저가 내부적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.close()를 100% 보장하며 안전하게 호출&lt;/b&gt;합니다 (__exit__).&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. FastAPI 라우팅과 클라이언트 요청-응답 4단계 라이프사이클&lt;/h2&gt;
&lt;a id=&quot;user-content-2-fastapi-라우팅과-클라이언트-요청-응답-4단계-라이프사이클&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#2-fastapi-%EB%9D%BC%EC%9A%B0%ED%8C%85%EA%B3%BC-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%9A%94%EC%B2%AD-%EC%9D%91%EB%8B%B5-4%EB%8B%A8%EA%B3%84-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 라우팅(Routing)의 본질: 도로 표지판과 HTTP Method + URL 매핑&lt;/h3&gt;
&lt;a id=&quot;user-content-2-1-라우팅routing의-본질-도로-표지판과-http-method--url-매핑&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#2-1-%EB%9D%BC%EC%9A%B0%ED%8C%85routing%EC%9D%98-%EB%B3%B8%EC%A7%88-%EB%8F%84%EB%A1%9C-%ED%91%9C%EC%A7%80%ED%8C%90%EA%B3%BC-http-method--url-%EB%A7%A4%ED%95%91&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;**라우팅(Routing)**이란:&lt;br /&gt;클라이언트(웹 브라우저, 모바일 앱)가 보낸 요청의 **HTTP 메서드(GET, POST, PUT, DELETE)**와 **URL 경로(/items, /users)**를 조합하여, 서버 내부의 어떤 담당 함수(핸들러)를 실행시킬지 길을 안내하고 연결해 주는 과정입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도로 표지판 비유&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GET /items&lt;span&gt;&amp;nbsp;&lt;/span&gt;표지판 ➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;list_items()&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수로 안내 (데이터 조회)&lt;/li&gt;
&lt;li&gt;POST /items&lt;span&gt;&amp;nbsp;&lt;/span&gt;표지판 ➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;create_item()&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수로 안내 (데이터 생성)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주소가 같아도 메서드가 다르면 완전히 다른 함수가 실행&lt;/b&gt;됩니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2.   요청부터 응답까지의 4단계 라이프사이클 전체 흐름도&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2--요청부터-응답까지의-4단계-라이프사이클-전체-흐름도&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#2-2--%EC%9A%94%EC%B2%AD%EB%B6%80%ED%84%B0-%EC%9D%91%EB%8B%B5%EA%B9%8C%EC%A7%80%EC%9D%98-4%EB%8B%A8%EA%B3%84-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-%EC%A0%84%EC%B2%B4-%ED%9D%90%EB%A6%84%EB%8F%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;클라이언트가 버튼을 클릭한 순간부터 화면에 데이터가 렌더링될 때까지 FastAPI 내부에서 일어나는 일입니다:&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1792995114641&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to render rich display

Parse error on line 11:
...m); session.commit() Handler--&amp;gt;&amp;gt;Form
-----------------------^
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'SOLID_ARROW_TOP', 'SOLID_ARROW_BOTTOM', 'STICK_ARROW_TOP', 'STICK_ARROW_BOTTOM', 'SOLID_ARROW_TOP_DOTTED', 'SOLID_ARROW_BOTTOM_DOTTED', 'STICK_ARROW_TOP_DOTTED', 'STICK_ARROW_BOTTOM_DOTTED', 'SOLID_ARROW_TOP_REVERSE', 'SOLID_ARROW_BOTTOM_REVERSE', 'STICK_ARROW_TOP_REVERSE', 'STICK_ARROW_BOTTOM_REVERSE', 'SOLID_ARROW_TOP_REVERSE_DOTTED', 'SOLID_ARROW_BOTTOM_REVERSE_DOTTED', 'STICK_ARROW_TOP_REVERSE_DOTTED', 'STICK_ARROW_BOTTOM_REVERSE_DOTTED', 'BIDIRECTIONAL_SOLID_ARROW', 'DOTTED_ARROW', 'BIDIRECTIONAL_DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'NEWLINE'

For more information, see https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;sequenceDiagram
    autonumber
    actor Client as   클라이언트 (Chrome)
    participant FastAPI as ⚡ FastAPI 라우팅 &amp;amp; 사전 검증
    participant Handler as ⚙ 비즈니스 핸들러 &amp;amp; DB
    participant Formatter as   응답 직렬화기

    Client-&amp;gt;&amp;gt;FastAPI: 1단계: HTTP 요청 (예: POST /items {&quot;name&quot;: &quot;apple&quot;, &quot;price&quot;: 1000})
    Note over FastAPI: 2단계: 사전 검증&amp;lt;br/&amp;gt;a) 라우팅: URL+Method로 함수 탐색&amp;lt;br/&amp;gt;b) 데이터 유효성 검사: Pydantic 타입/길이 검증&amp;lt;br/&amp;gt;c) 검증 통과 시 핸들러 호출
    FastAPI-&amp;gt;&amp;gt;Handler: 3단계: 함수 코드 실행 &amp;amp; DB 세션 관리
    Note over Handler: with SessionFactory() as session:&amp;lt;br/&amp;gt;session.add(new_item); session.commit()
    Handler--&amp;gt;&amp;gt;Formatter: 파이썬 Item ORM 객체 반환
    Note over Formatter: 4단계: 최종 응답 조립&amp;lt;br/&amp;gt;a) Python ➔ JSON 직렬화&amp;lt;br/&amp;gt;b) 상태 코드(201 Created) 부여
    Formatter--&amp;gt;&amp;gt;Client: HTTP 201 응답 전송 (JSON 본문)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;1단계: 클라이언트의 HTTP 요청 전송&lt;/b&gt;: 웹/앱에서 주소를 호출 (localhost:8000은 외부망으로 나가지 않고 내 컴퓨터 내부에서 루프백 통신).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2단계: FastAPI 사전 검증 및 라우팅&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URL과 Method로 대상 함수 매핑&lt;/li&gt;
&lt;li&gt;Path, Query, Request Body 데이터 형식 사전 검사 (실패 시 즉시 422 반환)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3단계: 함수 실행 및 DB 세션 관리&lt;/b&gt;: 비즈니스 로직 수행 및 안전한 세션 자원 해제.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;4단계: 최종 응답 처리&lt;/b&gt;: 파이썬 데이터를 표준 JSON 텍스트로 자동 직렬화하고 HTTP 상태 코드와 함께 클라이언트로 회신.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 의존성 주입 (Dependency Injection, DI): with 구문마저 지우는 비결&lt;/h2&gt;
&lt;a id=&quot;user-content-3-의존성-주입-dependency-injection-di-with-구문마저-지우는-비결&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#3-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-dependency-injection-di-with-%EA%B5%AC%EB%AC%B8%EB%A7%88%EC%A0%80-%EC%A7%80%EC%9A%B0%EB%8A%94-%EB%B9%84%EA%B2%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. 의존성 주입(DI)이란 무엇인가? (자원 생성과 렌탈 개념)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1-의존성-주입di이란-무엇인가-자원-생성과-렌탈-개념&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#3-1-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85di%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-%EC%9E%90%EC%9B%90-%EC%83%9D%EC%84%B1%EA%B3%BC-%EB%A0%8C%ED%83%88-%EA%B0%9C%EB%85%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;의존성 주입(Dependency Injection)&lt;/b&gt;:&lt;br /&gt;함수 내부에서 필요한 공통 자원(DB 세션, 인증 유저 정보, 외부 API 클라이언트 등)을 함수가 직접 만들지 않고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;FastAPI 프레임워크가 외부에서 대신 만들어 파라미터로 주입(Inject)해 주는 아키텍처&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;렌탈(대여) 개념&lt;/b&gt;:&lt;br /&gt;자동차를 매번 내가 직접 사서 타고 폐차하는 것이 아니라, 렌터카 업체(FastAPI)에서 차를 빌려 타고 반납하면 뒷정리는 업체가 알아서 해주는 것과 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;yield&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드를 활용한 세션 팩토리 제너레이터 (get_session())&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2-yield-키워드를-활용한-세션-팩토리-제너레이터-get_session&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#3-2-yield-%ED%82%A4%EC%9B%8C%EB%93%9C%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%84%B8%EC%85%98-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0-get_session&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# connection.py
from sqlalchemy.orm import Session
from connection import SessionFactory

def get_session():
    # 1. 요청이 들어오면 DB 세션을 열고
    session = SessionFactory()
    try:
        # 2. yield로 핸들러 함수에게 세션을 대여(전달)해 줌!
        # (함수가 종료될 때까지 get_session은 여기서 일시정지 상태 유지)
        yield session
    finally:
        # 3. 핸들러 함수가 return을 마치는 순간 일시정지가 풀리고 세션을 안전하게 닫음!
        session.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;yield의 작동 원리&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;return은 값을 돌려주고 함수를 완전히 종료시킵니다.&lt;/li&gt;
&lt;li&gt;반면&lt;span&gt;&amp;nbsp;&lt;/span&gt;yield는 **값을 반환한 뒤 그 자리에서 일시정지(Pause)**합니다.&lt;/li&gt;
&lt;li&gt;FastAPI 핸들러 함수가 DB 작업을 모두 마치고 나면, 멈춰있던&lt;span&gt;&amp;nbsp;&lt;/span&gt;yield&lt;span&gt;&amp;nbsp;&lt;/span&gt;다음 줄(finally: session.close())이 실행되면서 자원을 완벽하게 회수합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Depends(get_session)&lt;span&gt;&amp;nbsp;&lt;/span&gt;실전 적용과 엔드포인트 극단적 단순화&lt;/h3&gt;
&lt;a id=&quot;user-content-3-3-dependsget_session-실전-적용과-엔드포인트-극단적-단순화&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#3-3-dependsget_session-%EC%8B%A4%EC%A0%84-%EC%A0%81%EC%9A%A9%EA%B3%BC-%EC%97%94%EB%93%9C%ED%8F%AC%EC%9D%B8%ED%8A%B8-%EA%B7%B9%EB%8B%A8%EC%A0%81-%EB%8B%A8%EC%88%9C%ED%99%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이제 엔드포인트 함수에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;with&lt;span&gt;&amp;nbsp;&lt;/span&gt;문조차 쓸 필요가 없습니다!&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
from sqlalchemy import select
from connection import get_session

app = FastAPI()

@app.get(&quot;/items&quot;, response_model=list[ItemResponse])
def list_items(session: Session = Depends(get_session)):
    #   with SessionFactory() as session: 을 작성할 필요가 전혀 없음!
    stmt = select(Item)
    items = session.scalars(stmt).all()
    return items&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #1a7f37;&quot; data-ke-size=&quot;size16&quot;&gt;Tip&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;의존성 주입(DI)의 압도적인 장점&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;비즈니스 로직에만 집중&lt;/b&gt;: 세션을 열고 닫는 반복적인 보일러플레이트 코드가 완전히 사라집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테스트 용이성 (Mocking)&lt;/b&gt;: 테스트 코드 작성 시 실제 DB 세션 대신 가짜(Mock) 세션으로 손쉽게 교체할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Background Tasks (백그라운드 태스크)&lt;/h2&gt;
&lt;a id=&quot;user-content-4-background-tasks-백그라운드-태스크&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#4-background-tasks-%EB%B0%B1%EA%B7%B8%EB%9D%BC%EC%9A%B4%EB%93%9C-%ED%83%9C%EC%8A%A4%ED%81%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 요청-응답 이후 실행의 의미와 체감 응답 속도 극대화&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-요청-응답-이후-실행의-의미와-체감-응답-속도-극대화&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#4-1-%EC%9A%94%EC%B2%AD-%EC%9D%91%EB%8B%B5-%EC%9D%B4%ED%9B%84-%EC%8B%A4%ED%96%89%EC%9D%98-%EC%9D%98%EB%AF%B8%EC%99%80-%EC%B2%B4%EA%B0%90-%EC%9D%91%EB%8B%B5-%EC%86%8D%EB%8F%84-%EA%B7%B9%EB%8C%80%ED%99%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트에게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTTP 응답 메시지를 먼저 초고속으로 반환한 뒤, 시간이 걸리는 부가 작업을 백그라운드에서 실행&lt;/b&gt;하는 FastAPI 내장 기능입니다.&lt;/li&gt;
&lt;li&gt;사용자는 화면에서 로딩 스피너를 오래 보지 않고 즉시 &quot;완료되었습니다&quot; 응답을 받으므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서비스의 체감 속도가 비약적으로 향상&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. 실전 코드: 회원가입 후 5초 이메일 발송 비동기 처리&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-실전-코드-회원가입-후-5초-이메일-발송-비동기-처리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#4-2-%EC%8B%A4%EC%A0%84-%EC%BD%94%EB%93%9C-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%ED%9B%84-5%EC%B4%88-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EB%B0%9C%EC%86%A1-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;import time
from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

# 5초가 걸리는 무거운 이메일 발송 함수
def send_email(email: str):
    time.sleep(5)  # 실제 이메일 SMTP 서버 통신 시뮬레이션
    print(f&quot;  [발송 완료] {email} 님에게 환영 메일을 성공적으로 보냈습니다!&quot;)

@app.post(&quot;/sign-up&quot;)
def sign_up(email: str, background_tasks: BackgroundTasks):
    # 1. 백그라운드 태스크 큐에 작업 등록 (함수명, 인자)
    background_tasks.add_task(send_email, email)
    
    # 2. 이메일이 다 보내질 때까지 기다리지 않고 0.01초 만에 즉시 클라이언트에 응답!
    return {&quot;message&quot;: &quot;User SignUp Completed&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3. Background Tasks 사용 시 주의점 (무거운 작업과 Celery/Redis 비교)&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-background-tasks-사용-시-주의점-무거운-작업과-celeryredis-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#4-3-background-tasks-%EC%82%AC%EC%9A%A9-%EC%8B%9C-%EC%A3%BC%EC%9D%98%EC%A0%90-%EB%AC%B4%EA%B1%B0%EC%9A%B4-%EC%9E%91%EC%97%85%EA%B3%BC-celeryredis-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;적합한 작업&lt;/b&gt;: 이메일 발송, 푸시 알림 전송, 간단한 통계 로깅, 캐시 갱신 등 1~5초 내외의 가벼운 후처리.&lt;/li&gt;
&lt;li&gt;❌&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부적합한 작업 (주의!)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수 분 이상 걸리는 대용량 동영상 인코딩, 대규모 데이터셋 머신러닝 학습 등.&lt;/li&gt;
&lt;li&gt;FastAPI의 Background Tasks는 동일한 서버 프로세스 안에서 실행되므로, 너무 무거운 CPU 작업을 넣으면 메인 웹 서버의 전체 성능이 떨어집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;초대형 작업은 Celery + Redis / RabbitMQ 같은 분산 작업 큐 시스템을 사용하는 것이 정석&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 비동기 프로그래밍 (asyncio)의 본질과 컴퓨터 구조&lt;/h2&gt;
&lt;a id=&quot;user-content-5-비동기-프로그래밍-asyncio의-본질과-컴퓨터-구조&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-asyncio%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. 동기(Synchronous)의 한계와 I/O Bound 작업의 비효율&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-동기synchronous의-한계와-io-bound-작업의-비효율&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-1-%EB%8F%99%EA%B8%B0synchronous%EC%9D%98-%ED%95%9C%EA%B3%84%EC%99%80-io-bound-%EC%9E%91%EC%97%85%EC%9D%98-%EB%B9%84%ED%9A%A8%EC%9C%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동기(Synchronous) 방식&lt;/b&gt;:&lt;br /&gt;호출자(Caller)가 피호출자(Callee)의 작업이 완전히 끝날 때까지 아무것도 하지 않고 가만히 멈춰서 기다리는 방식.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;import time

def hello():
    time.sleep(2)  # 2초 동안 CPU가 멍하니 대기 (Blocking)
    print(&quot;hello&quot;)

hello()
print(&quot;end&quot;)
# 총 2초 동안 프로그램 전체가 멈춤!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. 컴퓨터 구조로 보는 속도 차이 (빛처럼 빠른 CPU/RAM vs 목 빠지는 Disk/Network I/O)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-컴퓨터-구조로-보는-속도-차이-빛처럼-빠른-cpuram-vs-목-빠지는-disknetwork-io&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-2-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EB%A1%9C-%EB%B3%B4%EB%8A%94-%EC%86%8D%EB%8F%84-%EC%B0%A8%EC%9D%B4-%EB%B9%9B%EC%B2%98%EB%9F%BC-%EB%B9%A0%EB%A5%B8-cpuram-vs-%EB%AA%A9-%EB%B9%A0%EC%A7%80%EB%8A%94-disknetwork-io&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;왜 웹 서버에서는 동기 방식이 치명적일까요? 컴퓨터 하드웨어의 영역 차이를 이해해야 합니다.&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1792995143853&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to render rich display

Parse error on line 12:
... &amp;lt;--&amp;gt;|물리적 I/O 대기 발생 (Blocking!)| SlowZon
-----------------------^
Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'

For more information, see https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;prolog&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;graph LR
    subgraph FastZone[&quot;⚡ 빛의 속도 (나노초 단위)&quot;]
        CPU[&quot;CPU (연산 장치)&amp;lt;br/&amp;gt;1 + 1 = 2 계산&quot;]
        RAM[&quot;RAM (주기억장치)&amp;lt;br/&amp;gt;FastAPI 파이썬 메모리&quot;]
    end

    subgraph SlowZone[&quot;  달팽이 속도 (밀리초~초 단위)&quot;]
        DISK[&quot;SSD / HDD (보조기억장치)&amp;lt;br/&amp;gt;SQLite test.db 파일&quot;]
        NET[&quot;외부 네트워크 / DB 서버&amp;lt;br/&amp;gt;API 통신 패킷&quot;]
    end

    FastZone &amp;lt;--&amp;gt;|물리적 I/O 대기 발생 (Blocking!)| SlowZone
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU와 RAM의 연산&lt;/b&gt;: 빛처럼 빠릅니다 (나노초 단위로 수억 번 계산).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디스크(SSD/HDD)와 네트워크 I/O&lt;/b&gt;: 물리적으로 모터가 돌거나 광케이블을 타야 하므로 상대적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;수백만 배 느립니다&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결론&lt;/b&gt;:&lt;br /&gt;FastAPI가 DB 조회를 요청할 때, CPU는 0.0001초 만에 요청 명령을 내렸지만 디스크에서 데이터가 RAM으로 올라올 때까지 **수 밀리초 동안 손을 놓고 멍하니 대기(Blocking)**하게 됩니다.&lt;br /&gt;이 아까운 대기 시간 동안 다른 사용자의 요청을 처리하자는 것이 **비동기 프로그래밍(asyncio)**의 핵심입니다!&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 비동기의 일상 비유: 라면 끓이기와 주문 접수&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3-비동기의-일상-비유-라면-끓이기와-주문-접수&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-3-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%9D%98-%EC%9D%BC%EC%83%81-%EB%B9%84%EC%9C%A0-%EB%9D%BC%EB%A9%B4-%EB%81%93%EC%9D%B4%EA%B8%B0%EC%99%80-%EC%A3%BC%EB%AC%B8-%EC%A0%91%EC%88%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;상황&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   동기 (Synchronous)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ⚡ 비동기 (Asynchronous)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;라면 끓이기&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;냄비에 물을 올리고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;물이 끓을 때까지 3분 동안 가스레인지 앞에 가만히 차렷 자세로 서 있기&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;물을 올려두고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;물이 끓는 동안(I/O 대기) 설거지를 하거나 테이블을 닦고 돌아오기&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;식당 운영&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;1번 손님의 스테이크 요리가 다 완성되어 서빙될 때까지&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;2번 손님의 주문 접수를 일절 거부하고 문을 닫아두기&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;1번 손님 주문을 주방에 넘겨두고(조리 대기),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;카운터에서 2번, 3번 손님의 주문을 쉬지 않고 연속해서 접수하기&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-4. 파이썬 표준 라이브러리&lt;span&gt;&amp;nbsp;&lt;/span&gt;asyncio&lt;/h3&gt;
&lt;a id=&quot;user-content-5-4-파이썬-표준-라이브러리-asyncio&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#5-4-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%91%9C%EC%A4%80-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-asyncio&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬에서 비동기 I/O 프로그래밍을 공식 지원하는 내장 라이브러리입니다 (import asyncio).&lt;/li&gt;
&lt;li&gt;외부 라이브러리(numpy, pytorch 등)와 달리 별도&lt;span&gt;&amp;nbsp;&lt;/span&gt;pip install&lt;span&gt;&amp;nbsp;&lt;/span&gt;없이 즉시 사용 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU를 쓰지 않고 쉬는 I/O 대기 시간(네트워크 요청, DB 쿼리, sleep)에 다른 작업을 교대로 처리&lt;/b&gt;하게 해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 코루틴(Coroutine)과 협력적 멀티태스킹&lt;/h2&gt;
&lt;a id=&quot;user-content-6-코루틴coroutine과-협력적-멀티태스킹&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-%EC%BD%94%EB%A3%A8%ED%8B%B4coroutine%EA%B3%BC-%ED%98%91%EB%A0%A5%EC%A0%81-%EB%A9%80%ED%8B%B0%ED%83%9C%EC%8A%A4%ED%82%B9&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. 코루틴의 정의: &quot;너 한 번, 나 한 번&quot; 협력(co-routine)하는 함수&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-코루틴의-정의-너-한-번-나-한-번-협력co-routine하는-함수&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-1-%EC%BD%94%EB%A3%A8%ED%8B%B4%EC%9D%98-%EC%A0%95%EC%9D%98-%EB%84%88-%ED%95%9C-%EB%B2%88-%EB%82%98-%ED%95%9C-%EB%B2%88-%ED%98%91%EB%A0%A5co-routine%ED%95%98%EB%8A%94-%ED%95%A8%EC%88%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;코루틴(Coroutine)&lt;/b&gt;:&lt;br /&gt;co-(함께, 협력하다) +&lt;span&gt;&amp;nbsp;&lt;/span&gt;routine(함수, 절차)의 합성어로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실행 도중에 멈췄다가(양보) 나중에 그 자리에서 다시 이어서 실행할 수 있는 협력적인 함수&lt;/b&gt;를 말합니다.&lt;/li&gt;
&lt;li&gt;특정 함수가 CPU를 혼자 독점하지 않고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;나 지금 DB 기다려야 하니까 다른 함수 먼저 일해!&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하고 서로 양보하며 번갈아 실행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2. 코루틴 함수(async def) vs 코루틴 객체 (왜 바로 실행되지 않는가?)&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-코루틴-함수async-def-vs-코루틴-객체-왜-바로-실행되지-않는가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-2-%EC%BD%94%EB%A3%A8%ED%8B%B4-%ED%95%A8%EC%88%98async-def-vs-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EA%B0%9D%EC%B2%B4-%EC%99%9C-%EB%B0%94%EB%A1%9C-%EC%8B%A4%ED%96%89%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;flix&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 1. async def로 정의된 함수 -&amp;gt; 코루틴 함수 (Coroutine Function)
async def hello():
    print(&quot;hello&quot;)

# 2. 코루틴 함수 호출
coro = hello()
print(coro)
# 출력: &amp;lt;coroutine object hello at 0x1056f3580&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. 왜 일반 함수처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;hello()를 부르면 바로 실행되지 않고 객체만 튀어나올까요?&lt;/b&gt;&lt;br /&gt;&lt;b&gt;A. 코루틴은 단독으로 혼자 실행되려고 태어난 것이 아니기 때문입니다!&lt;/b&gt;&lt;br /&gt;코루틴의 전제는 **&quot;동시에 진행해야 할 여러 작업들이 있을 때, 대기 시간에 서로 양보하며 협력하는 것&quot;**입니다.&lt;br /&gt;따라서 실행하기 전에 먼저 **작업 지시서(코루틴 객체)**를 만들어 두고, 이벤트 루프에 한꺼번에 올려서 실행해야 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;asyncio.run()과&lt;span&gt;&amp;nbsp;&lt;/span&gt;asyncio.gather()를 통한 동시 실행 패키징&lt;/h3&gt;
&lt;a id=&quot;user-content-6-3-asynciorun과-asynciogather를-통한-동시-실행-패키징&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-3-asynciorun%EA%B3%BC-asynciogather%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%8F%99%EC%8B%9C-%EC%8B%A4%ED%96%89-%ED%8C%A8%ED%82%A4%EC%A7%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;import asyncio

async def task_a():
    print(&quot;A 시작&quot;)
    await asyncio.sleep(2)  # 2초 동안 양보하며 대기
    print(&quot;A 끝&quot;)

async def task_b():
    print(&quot;B 시작&quot;)
    await asyncio.sleep(2)  # 2초 동안 양보하며 대기
    print(&quot;B 끝&quot;)

async def main():
    # 1. 코루틴 객체들을 생성하여 asyncio.gather로 한 바구니에 묶음
    coro_a = task_a()
    coro_b = task_b()
    await asyncio.gather(coro_a, coro_b)

# 2. 메인 진입점에서 이벤트 루프 가동
asyncio.run(main())&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-4. 동기 vs 비동기 실행 시간 벤치마크 (4초 ➔ 2초 단축)&lt;/h3&gt;
&lt;a id=&quot;user-content-6-4-동기-vs-비동기-실행-시간-벤치마크-4초--2초-단축&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#6-4-%EB%8F%99%EA%B8%B0-vs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%8B%A4%ED%96%89-%EC%8B%9C%EA%B0%84-%EB%B2%A4%EC%B9%98%EB%A7%88%ED%81%AC-4%EC%B4%88--2%EC%B4%88-%EB%8B%A8%EC%B6%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div data-plain=&quot;gantt
    title 동기 vs 비동기 실행 타임라인 비교
    dateFormat X
    axisFormat %s초

    section 동기 (4초 소요)
    task_a 실행 (2초 대기) : 0, 2
    task_b 실행 (2초 대기) : 2, 4

    section 비동기 (2초 소요!)
    task_a 실행 및 양보 : 0, 2
    task_b 실행 및 양보 (동시 대기) : 0, 2&quot; data-json=&quot;{&amp;quot;data&amp;quot;:&amp;quot;gantt\n    title 동기 vs 비동기 실행 타임라인 비교\n    dateFormat X\n    axisFormat %s초\n\n    section 동기 (4초 소요)\n    task_a 실행 (2초 대기) : 0, 2\n    task_b 실행 (2초 대기) : 2, 4\n\n    section 비동기 (2초 소요!)\n    task_a 실행 및 양보 : 0, 2\n    task_b 실행 및 양보 (동시 대기) : 0, 2\n&amp;quot;}&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2422&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhqB8A/dJMcafhyLf2/BXyaXBphtgJkkkVjyPV901/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhqB8A/dJMcafhyLf2/BXyaXBphtgJkkkVjyPV901/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhqB8A/dJMcafhyLf2/BXyaXBphtgJkkkVjyPV901/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhqB8A%2FdJMcafhyLf2%2FBXyaXBphtgJkkkVjyPV901%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2422&quot; height=&quot;354&quot; data-origin-width=&quot;2422&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동기 방식 (time.sleep)&lt;/b&gt;: A가 2초 멈추고 끝난 뒤 B가 2초 멈춤 ➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;총 4초 소요!&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비동기 방식 (asyncio.sleep)&lt;/b&gt;: A가 2초 대기에 들어가며 양보하자마자 B가 즉시 시작되어 함께 2초를 대기 ➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;총 2초 만에 두 작업 동시 완료!&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작업이 5개, 10개로 늘어나도 I/O 대기 시간은 여전히 2초로 수렴&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7.&lt;span&gt;&amp;nbsp;&lt;/span&gt;await&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드와 양보(Yield Control)의 미학&lt;/h2&gt;
&lt;a id=&quot;user-content-7-await-키워드와-양보yield-control의-미학&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-await-%ED%82%A4%EC%9B%8C%EB%93%9C%EC%99%80-%EC%96%91%EB%B3%B4yield-control%EC%9D%98-%EB%AF%B8%ED%95%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;await: &quot;여기서 잠깐 멈추고 제어권을 넘겨라!&quot;&lt;/h3&gt;
&lt;a id=&quot;user-content-7-1-await-여기서-잠깐-멈추고-제어권을-넘겨라&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-1-await-%EC%97%AC%EA%B8%B0%EC%84%9C-%EC%9E%A0%EA%B9%90-%EB%A9%88%EC%B6%94%EA%B3%A0-%EC%A0%9C%EC%96%B4%EA%B6%8C%EC%9D%84-%EB%84%98%EA%B2%A8%EB%9D%BC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코루틴은 I/O를 기다릴 때 양보하지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴퓨터는 언제 I/O 대기가 발생할지 스스로 예측할 수 없습니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;따라서 개발자가 코드에 **await**라는 키워드를 붙여서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;여기가 바로 오래 걸리는 지점이니까, 결과가 올 때까지 다른 코루틴에게 CPU 제어권을 넘겨라!&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하고 명시해 주어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-2. ⭐ await를 사용하는 2가지 절대 조건&lt;/h3&gt;
&lt;a id=&quot;user-content-7-2--await를-사용하는-2가지-절대-조건&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-2--await%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-2%EA%B0%80%EC%A7%80-%EC%A0%88%EB%8C%80-%EC%A1%B0%EA%B1%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;async def로 선언된 비동기 함수(코루틴) 내부에서만 사용 가능!&lt;/b&gt;&lt;br /&gt;일반 동기 함수(def)나 파이썬 파일 최상단에서 단독으로 쓰면 문법 에러(SyntaxError: 'await' outside function)가 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기다릴 수 있는 대상(Awaitable&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체) 앞에만 사용 가능!&lt;/b&gt;&lt;br /&gt;아무 함수에나 붙일 수 없으며, 반드시 비동기 작업을 지원하는 대상이어야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# ❌ 일반 동기 함수에 await를 붙인 잘못된 코드 (에러 발생!)
async def wrong():
    await time.sleep(3)  # TypeError: object NoneType can't be used in 'await' expression

# ✅ 비동기 전용 함수에 await를 붙인 올바른 코드
async def correct():
    await asyncio.sleep(3)  # 정상 동작&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-3. 어떤 작업이 Awaitable한가? (판단 3단계 공식)&lt;/h3&gt;
&lt;a id=&quot;user-content-7-3-어떤-작업이-awaitable한가-판단-3단계-공식&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-3-%EC%96%B4%EB%96%A4-%EC%9E%91%EC%97%85%EC%9D%B4-awaitable%ED%95%9C%EA%B0%80-%ED%8C%90%EB%8B%A8-3%EB%8B%A8%EA%B3%84-%EA%B3%B5%EC%8B%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;async def로 정의된 함수인가? ➔ 호출 시 코루틴 객체를 반환하므로 100%&lt;span&gt;&amp;nbsp;&lt;/span&gt;await&lt;span&gt;&amp;nbsp;&lt;/span&gt;가능.&lt;/li&gt;
&lt;li&gt;비동기 라이브러리(aiohttp,&lt;span&gt;&amp;nbsp;&lt;/span&gt;asyncpg,&lt;span&gt;&amp;nbsp;&lt;/span&gt;aiofiles,&lt;span&gt;&amp;nbsp;&lt;/span&gt;asyncio&lt;span&gt;&amp;nbsp;&lt;/span&gt;등) 출신인가? ➔ 대부분&lt;span&gt;&amp;nbsp;&lt;/span&gt;await&lt;span&gt;&amp;nbsp;&lt;/span&gt;가능.&lt;/li&gt;
&lt;li&gt;I/O 대기가 발생하는 작업인가? ➔ 비동기 버전 함수라면&lt;span&gt;&amp;nbsp;&lt;/span&gt;await를 붙여야 함.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-4. [실습] 코루틴 체이닝 퍼즐 (출력 순서 제어 완성)&lt;/h3&gt;
&lt;a id=&quot;user-content-7-4-실습-코루틴-체이닝-퍼즐-출력-순서-제어-완성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#7-4-%EC%8B%A4%EC%8A%B5-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EC%B2%B4%EC%9D%B4%EB%8B%9D-%ED%8D%BC%EC%A6%90-%EC%B6%9C%EB%A0%A5-%EC%88%9C%EC%84%9C-%EC%A0%9C%EC%96%B4-%EC%99%84%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;슬라이드 31~34페이지의 실전 퍼즐 문제입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;목표 출력 순서&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;C 시작&lt;/li&gt;
&lt;li&gt;A 시작&lt;/li&gt;
&lt;li&gt;A 끝&lt;/li&gt;
&lt;li&gt;B 시작&lt;/li&gt;
&lt;li&gt;C 끝&lt;/li&gt;
&lt;li&gt;B 끝&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;풀이 분석 및 완성 코드:&lt;/h4&gt;
&lt;a id=&quot;user-content-풀이-분석-및-완성-코드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#%ED%92%80%EC%9D%B4-%EB%B6%84%EC%84%9D-%EB%B0%8F-%EC%99%84%EC%84%B1-%EC%BD%94%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;각 코루틴의&lt;span&gt;&amp;nbsp;&lt;/span&gt;await asyncio.sleep()&lt;span&gt;&amp;nbsp;&lt;/span&gt;시간을 세밀하게 조율하여 타임라인을 맞춥니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;import asyncio

async def a():
    await asyncio.sleep(0.1)  # 0.1초 후 A 시작
    print(&quot;A 시작&quot;)
    await asyncio.sleep(0.0)  # 대기 없이 즉시 A 끝
    print(&quot;A 끝&quot;)

async def b():
    await asyncio.sleep(0.2)  # 0.2초 후 B 시작
    print(&quot;B 시작&quot;)
    await asyncio.sleep(0.2)  # 추가 0.2초(누적 0.4초) 후 B 끝
    print(&quot;B 끝&quot;)

async def c():
    await asyncio.sleep(0.0)  # 0.0초! 가장 먼저 C 시작
    print(&quot;C 시작&quot;)
    await asyncio.sleep(0.3)  # 추가 0.3초 후 C 끝
    print(&quot;C 끝&quot;)

async def main():
    await asyncio.gather(a(), b(), c())

asyncio.run(main())&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 이벤트 루프(Event Loop)와 블로킹(Blocking) 금지의 법칙&lt;/h2&gt;
&lt;a id=&quot;user-content-8-이벤트-루프event-loop와-블로킹blocking-금지의-법칙&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#8-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84event-loop%EC%99%80-%EB%B8%94%EB%A1%9C%ED%82%B9blocking-%EA%B8%88%EC%A7%80%EC%9D%98-%EB%B2%95%EC%B9%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-1. 이벤트 루프란? (&quot;세 쌍둥이 밥 먹이기&quot; 완벽 비유)&lt;/h3&gt;
&lt;a id=&quot;user-content-8-1-이벤트-루프란-세-쌍둥이-밥-먹이기-완벽-비유&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#8-1-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84%EB%9E%80-%EC%84%B8-%EC%8C%8D%EB%91%A5%EC%9D%B4-%EB%B0%A5-%EB%A8%B9%EC%9D%B4%EA%B8%B0-%EC%99%84%EB%B2%BD-%EB%B9%84%EC%9C%A0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;**이벤트 루프(Event Loop)**는 수많은 코루틴들의 양보와 대기, 실행 재개를 쉴 새 없이 조율하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중간 총괄 관리자&lt;/b&gt;입니다.&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1792995215159&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to render rich display

Parse error on line 8:
...D1 --&amp;gt;|2. 오물오물 씹는 중 (await)| PARENT
-----------------------^
Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'

For more information, see https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;coq&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;graph TD
    PARENT[&quot; &amp;zwj; &amp;zwj;  이벤트 루프 (부모)&quot;]
    KID1[&quot;  코루틴 A (첫째)&quot;]
    KID2[&quot;  코루틴 B (둘째)&quot;]
    KID3[&quot;  코루틴 C (셋째)&quot;]

    PARENT --&amp;gt;|1. 한 숟갈 먹임| KID1
    KID1 --&amp;gt;|2. 오물오물 씹는 중 (await)| PARENT
    PARENT --&amp;gt;|3. 씹는 동안 둘째 먹임| KID2
    KID2 --&amp;gt;|4. 오물오물 씹는 중 (await)| PARENT
    PARENT --&amp;gt;|5. 셋째 먹임| KID3
    PARENT --&amp;gt;|6. 첫째가 다 씹었으면 다음 숟갈!| KID1
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비유 분석&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;부모 = 이벤트 루프&lt;/b&gt;: 단 한 명의 부모(싱글 스레드)가 숟가락을 들고 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;아이들 = 코루틴&lt;/b&gt;: 아이가 밥을 씹는 시간은 **I/O 대기 시간(await)**입니다.&lt;/li&gt;
&lt;li&gt;부모는 한 아이가 씹는 동안 멍하니 기다리지 않고 바로 옆 아이에게 숟가락을 가져갑니다.&lt;/li&gt;
&lt;li&gt;밖에서 보면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;세 아이가 동시에 밥을 먹는 것처럼(동시성 / Concurrency)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;보입니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-2.   절대 규칙: 이벤트 루프를 블로킹하면 서버 전체가 얼어붙는다!&lt;/h3&gt;
&lt;a id=&quot;user-content-8-2--절대-규칙-이벤트-루프를-블로킹하면-서버-전체가-얼어붙는다&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#8-2--%EC%A0%88%EB%8C%80-%EA%B7%9C%EC%B9%99-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84%EB%A5%BC-%EB%B8%94%EB%A1%9C%ED%82%B9%ED%95%98%EB%A9%B4-%EC%84%9C%EB%B2%84-%EC%A0%84%EC%B2%B4%EA%B0%80-%EC%96%BC%EC%96%B4%EB%B6%99%EB%8A%94%EB%8B%A4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;⚠️&lt;span&gt;&amp;nbsp;&lt;/span&gt;비동기 세상의 대역죄: Blocking the Event Loop!&lt;/b&gt;&lt;br /&gt;만약 코루틴 내부에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;await&lt;span&gt;&amp;nbsp;&lt;/span&gt;없이&lt;span&gt;&amp;nbsp;&lt;/span&gt;time.sleep(10)이나 거대한&lt;span&gt;&amp;nbsp;&lt;/span&gt;while True&lt;span&gt;&amp;nbsp;&lt;/span&gt;연산을 돌려버리면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트 루프(부모)의 손발이 통째로 묶여버립니다.&lt;/b&gt;&lt;br /&gt;그 순간 다른 모든 코루틴의 실행이 정지되어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;접속해 있는 모든 클라이언트의 웹 페이지가 동시에 멈추게 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. FastAPI 내부 동작의 비밀: 동기 함수(def)와 스레드 풀(Thread Pool)&lt;/h2&gt;
&lt;a id=&quot;user-content-9-fastapi-내부-동작의-비밀-동기-함수def와-스레드-풀thread-pool&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#9-fastapi-%EB%82%B4%EB%B6%80-%EB%8F%99%EC%9E%91%EC%9D%98-%EB%B9%84%EB%B0%80-%EB%8F%99%EA%B8%B0-%ED%95%A8%EC%88%98def%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80thread-pool&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-1. &quot;FastAPI는 비동기인데 왜 우린 지금까지&lt;span&gt;&amp;nbsp;&lt;/span&gt;def&lt;span&gt;&amp;nbsp;&lt;/span&gt;일반 함수를 썼을까?&quot;&lt;/h3&gt;
&lt;a id=&quot;user-content-9-1-fastapi는-비동기인데-왜-우린-지금까지-def-일반-함수를-썼을까&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#9-1-fastapi%EB%8A%94-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%9D%B8%EB%8D%B0-%EC%99%9C-%EC%9A%B0%EB%A6%B0-%EC%A7%80%EA%B8%88%EA%B9%8C%EC%A7%80-def-%EC%9D%BC%EB%B0%98-%ED%95%A8%EC%88%98%EB%A5%BC-%EC%8D%BC%EC%9D%84%EA%B9%8C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;미스터리&lt;/b&gt;:&lt;br /&gt;&quot;FastAPI는 비동기(Async) 기반 프레임워크라고 배웠는데, 왜 이전 실습에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;@app.get(&quot;/items&quot;)&lt;span&gt;&amp;nbsp;&lt;/span&gt;밑에&lt;span&gt;&amp;nbsp;&lt;/span&gt;async def가 아니라 그냥&lt;span&gt;&amp;nbsp;&lt;/span&gt;def list_items():를 썼을까요? 동기 함수를 쓰면 이벤트 루프가 블로킹되어 서버가 멈춰야 정상 아닌가요?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-2. 스레드 풀(Thread Pool)의 대리 실행 메커니즘 (run_endpoint_function)&lt;/h3&gt;
&lt;a id=&quot;user-content-9-2-스레드-풀thread-pool의-대리-실행-메커니즘-run_endpoint_function&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#9-2-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80thread-pool%EC%9D%98-%EB%8C%80%EB%A6%AC-%EC%8B%A4%ED%96%89-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98-run_endpoint_function&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;비밀은 FastAPI 내부 소스코드(fastapi/routing.py의&lt;span&gt;&amp;nbsp;&lt;/span&gt;run_endpoint_function)에 숨어 있습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;1020&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/129Jn/dJMcah0BUL6/MQKoZCsbf5oTBOY452UbX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/129Jn/dJMcah0BUL6/MQKoZCsbf5oTBOY452UbX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/129Jn/dJMcah0BUL6/MQKoZCsbf5oTBOY452UbX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F129Jn%2FdJMcah0BUL6%2FMQKoZCsbf5oTBOY452UbX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;134&quot; height=&quot;419&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;1020&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;FastAPI의 천재적인 배려&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자가&lt;span&gt;&amp;nbsp;&lt;/span&gt;def로 동기 함수를 작성하면, FastAPI는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;아! 이 함수는 동기 함수니까 이벤트 루프에서 직접 돌리면 서버가 멈추겠구나!&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하고 판단합니다.&lt;/li&gt;
&lt;li&gt;그래서 이벤트 루프를 건드리지 않고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;외부의 별도 일꾼 모음인 스레드 풀(Thread Pool)의 작업자 스레드에게 작업을 대신 던져서 실행&lt;/b&gt;시킵니다.&lt;/li&gt;
&lt;li&gt;덕분에 개발자가 실수로 동기 코드를 작성해도 이벤트 루프가 얼어붙지 않는 것입니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-3. 스레드 풀 크기 조절과 Lifespan 컨텍스트 매니저 (기본 40개 ➔ 200개 상향)&lt;/h3&gt;
&lt;a id=&quot;user-content-9-3-스레드-풀-크기-조절과-lifespan-컨텍스트-매니저-기본-40개--200개-상향&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#9-3-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80-%ED%81%AC%EA%B8%B0-%EC%A1%B0%EC%A0%88%EA%B3%BC-lifespan-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%A7%A4%EB%8B%88%EC%A0%80-%EA%B8%B0%EB%B3%B8-40%EA%B0%9C--200%EA%B0%9C-%EC%83%81%ED%96%A5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스레드 풀의 한계&lt;/b&gt;:&lt;br /&gt;동기 엔드포인트는 **스레드 풀의 개수(기본값: 40개)**가 곧&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최대 동시 처리량&lt;/b&gt;입니다.&lt;br /&gt;동시 요청이 40개를 넘어가면 41번째 요청부터는 스레드가 날 때까지 대기 큐에서 지연(Lag)이 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해결책&lt;/b&gt;:&lt;br /&gt;최신 FastAPI 표준인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Lifespan 컨텍스트 매니저&lt;/b&gt;를 활용해 서버 기동 시 스레드 풀의 크기(total_tokens)를 상향 조정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from contextlib import asynccontextmanager
import anyio
from fastapi import FastAPI

@asynccontextmanager
async def lifespan(app: FastAPI):
    # 1. [서버 시작 직후 실행] AI 모델 로드, 스레드 풀 조정 등
    limiter = anyio.to_thread.current_default_thread_limiter()
    limiter.total_tokens = 200  # 기본 40개 ➔ 200개로 대폭 상향!
    print(&quot;  [서버 시작] 스레드 풀 200개 확장 완료&quot;)
    
    yield  # 서버가 돌아가는 동안 대기
    
    # 2. [서버 종료 직전 실행] DB 커넥션 풀 종료 등 마무리 코드
    print(&quot;  [서버 종료] 자원 정리 완료&quot;)

app = FastAPI(
    title=&quot;e-Commerce 상품 관리 서버&quot;,
    lifespan=lifespan
)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-10--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day4/fastapi-asyncio-dependency-injection-note.md#10--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;flix&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│         FastAPI 자원 관리 &amp;amp; 비동기(asyncio) &amp;amp; 스레드 풀 치트시트       │
├──────────────────────────────┬─────────────────────────────────────────┤
│ 문법 / 개념                  │ 핵심 요약 및 사용 공식                  │
├──────────────────────────────┼─────────────────────────────────────────┤
│ try - finally                │ return 직전에 session.close() 보장     │
├──────────────────────────────┼─────────────────────────────────────────┤
│ with SessionFactory() as s:  │ 들여쓰기 빠져나갈 때 자동 close()       │
├──────────────────────────────┼─────────────────────────────────────────┤
│ yield session                │ get_session() 제너레이터로 세션 렌탈    │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Depends(get_session)         │ FastAPI 의존성 주입 (with 문도 생략)    │
├──────────────────────────────┼─────────────────────────────────────────┤
│ BackgroundTasks.add_task()   │ 응답 반환 후 백그라운드에서 후처리 실행 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ async def                    │ 코루틴 함수 정의 (호출 시 코루틴 객체)  │
├──────────────────────────────┼─────────────────────────────────────────┤
│ await                        │ I/O 대기 시 CPU 제어권 양보 키워드      │
├──────────────────────────────┼─────────────────────────────────────────┤
│ await 사용 2대 조건          │ 1) async def 내부 2) Awaitable 객체     │
├──────────────────────────────┼─────────────────────────────────────────┤
│ asyncio.gather(c1, c2)       │ 여러 비동기 작업을 묶어 동시 실행       │
├──────────────────────────────┼─────────────────────────────────────────┤
│ 이벤트 루프 (Event Loop)     │ 코루틴들의 양보/대기/재개를 총괄 관리   │
├──────────────────────────────┼─────────────────────────────────────────┤
│ 블로킹 금지                  │ 이벤트 루프 멈추면 모든 비동기 작업 올스톱│
├──────────────────────────────┼─────────────────────────────────────────┤
│ def (동기 엔드포인트)        │ FastAPI가 스레드 풀(기본 40개)에서 실행 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ lifespan (스레드 풀 확장)    │ anyio limiter.total_tokens = 200        │
└──────────────────────────────┴─────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/37</guid>
      <comments>https://write31991.tistory.com/37#entry37comment</comments>
      <pubDate>Mon, 26 Oct 2026 15:19:34 +0900</pubDate>
    </item>
    <item>
      <title>FastAPI 3일차</title>
      <link>https://write31991.tistory.com/36</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h1&gt; ️ FastAPI &amp;amp; SQLAlchemy ORM 데이터베이스 연동과 실전 영속 CRUD 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content-️-fastapi--sqlalchemy-orm-데이터베이스-연동과-실전-영속-crud-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#%EF%B8%8F-fastapi--sqlalchemy-orm-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%97%B0%EB%8F%99%EA%B3%BC-%EC%8B%A4%EC%A0%84-%EC%98%81%EC%86%8D-crud-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리(list) 기반 CRUD의 한계와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터베이스(RDB) 도입 이유&lt;/b&gt;부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SQL 직접 작성의 한계와 ORM(Object-Relational Mapping)의 본질&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SQLAlchemy 2.0 모던 아키텍처(Engine, Session, Model)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Mapped&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;amp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;mapped_column&lt;span&gt;&amp;nbsp;&lt;/span&gt;모델링&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;세션의 생명주기와 영속성 컨텍스트(Staging ➔ Commit)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Result 커서의 원리와 3대 추출 메서드(mappings,&lt;span&gt;&amp;nbsp;&lt;/span&gt;all,&lt;span&gt;&amp;nbsp;&lt;/span&gt;scalars)&lt;/b&gt;, 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Context Manager(with)를 적용한 견고한 실전 DB CRUD 구현&lt;/b&gt;까지 총정리한 실무 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#1-%EC%99%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4db%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80-%EB%A9%94%EB%AA%A8%EB%A6%AC-crud%EC%9D%98-%ED%95%9C%EA%B3%84&quot;&gt;왜 데이터베이스(DB)가 필요한가? (메모리 CRUD의 한계)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#1-1-%EB%A9%94%EB%AA%A8%EB%A6%AClist-%EA%B8%B0%EB%B0%98-crud%EC%9D%98-2%EB%8C%80-%EC%B9%98%EB%AA%85%EC%A0%81-%ED%95%9C%EA%B3%84&quot;&gt;1-1. 메모리(list) 기반 CRUD의 2대 치명적 한계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#1-2-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%9D%98-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%EC%97%AD%ED%95%A0-%EC%98%81%EC%86%8D%EC%84%B1-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%8B%A0%EB%A2%B0%EC%84%B1&quot;&gt;1-2. 데이터베이스의 3대 핵심 역할 (영속성, 동시성, 신뢰성)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-sql-%EC%A7%81%EC%A0%91-%EC%9E%91%EC%84%B1raw-sql%EC%9D%98-%ED%95%9C%EA%B3%84%EC%99%80-orm%EC%9D%98-%ED%83%84%EC%83%9D&quot;&gt;SQL 직접 작성(Raw SQL)의 한계와 ORM의 탄생&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-1-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8---fastapi---sqlite-%EC%A0%84%EC%B2%B4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98&quot;&gt;2-1. 클라이언트 - FastAPI - SQLite 전체 아키텍처&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-2-sql%EC%9D%84-%EC%BD%94%EB%93%9C-%EC%95%88%EC%97%90-%EC%A7%81%EC%A0%91-%EC%A0%81%EC%97%88%EC%9D%84-%EB%95%8C%EC%9D%98-2%EB%8C%80-%EB%AC%B8%EC%A0%9C%EC%A0%90&quot;&gt;2-2. &quot;SQL을 코드 안에 직접 적었을 때&quot;의 2대 문제점&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-3-ormobject-relational-mapping%EC%9D%B4%EB%9E%80&quot;&gt;2-3. ORM(Object-Relational Mapping)이란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-4-orm-3%EB%8C%80-%EB%A7%A4%ED%95%91-%EA%B3%B5%EC%8B%9D-%ED%85%8C%EC%9D%B4%EB%B8%94%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%96%89%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EC%97%B4%EC%86%8D%EC%84%B1&quot;&gt;2-4. ORM 3대 매핑 공식 (테이블=클래스, 행=인스턴스, 열=속성)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#3-sqlalchemy-python-%ED%91%9C%EC%A4%80-orm-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC&quot;&gt;SQLAlchemy: Python 표준 ORM 라이브러리&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#3-1-sqlalchemy%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%99%80-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EB%B3%84-orm-%EB%B9%84%EA%B5%90&quot;&gt;3-1. SQLAlchemy를 사용하는 이유와 프레임워크별 ORM 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#3-2-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EC%B9%98-pip-install-sqlalchemy&quot;&gt;3-2. 패키지 설치 (pip install SQLAlchemy)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-sqlalchemy-%EA%B8%B0%EC%B4%88-3%EB%8C%80-%EC%9A%94%EC%86%8C-engine-session-model&quot;&gt;SQLAlchemy 기초 3대 요소 (Engine, Session, Model)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-1-engine-%EC%97%94%EC%A7%84-db-%EB%AC%BC%EB%A6%AC%EC%A0%81-%EC%97%B0%EA%B2%B0%EC%9D%98-%EA%B4%80%EB%AC%B8&quot;&gt;4-1. Engine (엔진): DB 물리적 연결의 관문&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-2-session-%EC%84%B8%EC%85%98-%EC%9E%91%EC%97%85-%EB%8B%A8%EC%9C%84%EC%99%80-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EA%B4%80%EB%A6%AC&quot;&gt;4-2. Session (세션): 작업 단위와 트랜잭션 관리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-3-model-%EB%AA%A8%EB%8D%B8-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A1%9C-%ED%91%9C%ED%98%84%ED%95%9C-%ED%85%8C%EC%9D%B4%EB%B8%94&quot;&gt;4-3. Model (모델): 파이썬 클래스로 표현한 테이블&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-4-%EC%97%94%EC%A7%84%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%9A%94%EC%B2%AD%EC%8B%A4%ED%96%89-%EC%A0%84%EC%B2%B4-%ED%9D%90%EB%A6%84&quot;&gt;4-4. 엔진을 통한 데이터베이스 요청/실행 전체 흐름&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-sqlalchemy-20-%EB%AA%A8%EB%8D%98-%EB%AA%A8%EB%8D%B8-%EC%A0%95%EC%9D%98%EC%99%80-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%9E%90%EB%8F%99-%EC%83%9D%EC%84%B1&quot;&gt;SQLAlchemy 2.0 모던 모델 정의와 테이블 자동 생성&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-1-declarativebase%EB%A5%BC-%EC%83%81%EC%86%8D%ED%95%9C-base-%EC%84%A0%EC%96%B8&quot;&gt;5-1.&amp;nbsp;DeclarativeBase를 상속한&amp;nbsp;Base&amp;nbsp;선언&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-2-mapped%EC%99%80-mapped_column%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-item-%EB%AA%A8%EB%8D%B8-%EC%A0%95%EC%9D%98&quot;&gt;5-2.&amp;nbsp;Mapped와&amp;nbsp;mapped_column을 활용한 Item 모델 정의&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-3-%EC%99%9C-db-%EC%BB%AC%EB%9F%BC%EC%9D%98-%ED%83%80%EC%9E%85%EC%9D%84-%EA%B3%A0%EC%A0%95%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80-%EC%9D%BC%EA%B4%80%EC%84%B1--%EC%A0%80%EC%9E%A5-%ED%9A%A8%EC%9C%A8%EC%84%B1&quot;&gt;5-3. 왜 DB 컬럼의 타입을 고정해야 하는가? (일관성 &amp;amp; 저장 효율성)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-4-basemetadatacreate_allbindengine-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%9E%90%EB%8F%99-%EC%83%9D%EC%84%B1&quot;&gt;5-4.&amp;nbsp;Base.metadata.create_all(bind=engine)&amp;nbsp;테이블 자동 생성&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#6-%EC%84%B8%EC%85%98%EC%9D%98-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4%EA%B3%BC-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%80%EC%9E%A5-staging--commit&quot;&gt;세션의 라이프사이클과 데이터 저장 (Staging ➔ Commit)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#6-1-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1-vs-sessionadd-staging-%EC%83%81%ED%83%9C%EC%9D%98-%EC%9D%98%EB%AF%B8&quot;&gt;6-1. 객체 생성 vs&amp;nbsp;session.add()&amp;nbsp;(Staging 상태의 의미)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#6-2-sessioncommit%EA%B3%BC-sessionclose&quot;&gt;6-2.&amp;nbsp;session.commit()과&amp;nbsp;session.close()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#6-3-%EB%8B%A4%EC%A4%91-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9D%BC%EA%B4%84-%EB%93%B1%EB%A1%9D%EA%B3%BC-returning-id%EC%9D%98-%EC%9B%90%EB%A6%AC&quot;&gt;6-3. 다중 데이터 일괄 등록과&amp;nbsp;RETURNING id의 원리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-sqlalchemy-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A1%B0%ED%9A%8Cselect%EC%99%80-result-%EA%B0%9D%EC%B2%B4%EC%9D%98-%EB%B9%84%EB%B0%80&quot;&gt;SQLAlchemy 데이터 조회(SELECT)와 Result 객체의 비밀&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-1-select-%EC%BF%BC%EB%A6%AC%EB%AC%B8-%EB%B9%8C%EB%93%9C%EC%99%80-sessionexecute&quot;&gt;7-1.&amp;nbsp;select()&amp;nbsp;쿼리문 빌드와&amp;nbsp;session.execute()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-2-%EC%99%9C-printresult-%ED%95%B4%EB%8F%84-%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-%EC%95%88-%EB%B3%B4%EC%9D%BC%EA%B9%8C-iteratorresult-%EC%BB%A4%EC%84%9C&quot;&gt;7-2. 왜&amp;nbsp;print(result)&amp;nbsp;해도 데이터가 안 보일까? (Iterator/Result 커서)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-3-3%EB%8C%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%94%EC%B6%9C-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%B9%84%EA%B5%90-mappings-all-scalars&quot;&gt;7-3. 3대 데이터 추출 메서드 비교 (mappings,&amp;nbsp;all,&amp;nbsp;scalars)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-4--%EC%B9%98%EB%AA%85%EC%A0%81-%EC%A3%BC%EC%9D%98%EC%A0%90-result-%EC%BB%A4%EC%84%9C%EC%9D%98-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%86%8C%EB%AA%A8consumption-%ED%8A%B9%EC%84%B1&quot;&gt;7-4.   치명적 주의점: Result 커서의 일회성 소모(Consumption) 특성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-5-%ED%8A%B9%EC%A0%95-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8B%A8%EC%9D%BC-%EC%A1%B0%ED%9A%8C-where%EC%99%80-sessionscalar&quot;&gt;7-5. 특정 데이터 단일 조회:&amp;nbsp;.where()와&amp;nbsp;session.scalar()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-fastapi--sqlalchemy-%EC%97%B0%EB%8F%99-%EC%8B%A4%EC%A0%84-%EC%98%81%EC%86%8D-crud-%EA%B5%AC%ED%98%84&quot;&gt;FastAPI + SQLAlchemy 연동 실전 영속 CRUD 구현&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-1-db-%EC%97%B0%EA%B2%B0-%EB%B0%8F-%EC%84%B8%EC%85%98-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EA%B3%B5%ED%86%B5-%EB%AA%A8%EB%93%88-connectionpy&quot;&gt;8-1. DB 연결 및 세션 팩토리 공통 모듈 (connection.py)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-2-create-%EC%83%81%ED%92%88-%EC%83%9D%EC%84%B1-post-items-try-finally-vs-context-manager&quot;&gt;8-2. [Create] 상품 생성 (POST /items, try-finally vs Context Manager)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-3-read-all-%EC%A0%84%EC%B2%B4-%EC%83%81%ED%92%88-%EC%A1%B0%ED%9A%8C-get-items-scalarsall&quot;&gt;8-3. [Read All] 전체 상품 조회 (GET /items,&amp;nbsp;scalars().all())&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-4-read-one-%EB%8B%A8%EC%9D%BC-%EC%83%81%ED%92%88-%EC%83%81%EC%84%B8-%EC%A1%B0%ED%9A%8C-get-itemsitem_id-404-%EC%98%88%EC%99%B8&quot;&gt;8-4. [Read One] 단일 상품 상세 조회 (GET /items/{item_id}, 404 예외)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-5-update-%EC%83%81%ED%92%88-%EB%B6%80%EB%B6%84-%EC%88%98%EC%A0%95-patch-itemsitem_id-db-%EB%B3%80%EA%B2%BD-%EB%B0%98%EC%98%81&quot;&gt;8-5. [Update] 상품 부분 수정 (PATCH /items/{item_id}, DB 변경 반영)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-6-delete-%EC%83%81%ED%92%88-%EC%82%AD%EC%A0%9C-delete-itemsitem_id-sessiondelete&quot;&gt;8-6. [Delete] 상품 삭제 (DELETE /items/{item_id},&amp;nbsp;session.delete)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#9--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 왜 데이터베이스(DB)가 필요한가? (메모리 CRUD의 한계)&lt;/h2&gt;
&lt;a id=&quot;user-content-1-왜-데이터베이스db가-필요한가-메모리-crud의-한계&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#1-%EC%99%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4db%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80-%EB%A9%94%EB%AA%A8%EB%A6%AC-crud%EC%9D%98-%ED%95%9C%EA%B3%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. 메모리(list) 기반 CRUD의 2대 치명적 한계&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-메모리list-기반-crud의-2대-치명적-한계&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#1-1-%EB%A9%94%EB%AA%A8%EB%A6%AClist-%EA%B8%B0%EB%B0%98-crud%EC%9D%98-2%EB%8C%80-%EC%B9%98%EB%AA%85%EC%A0%81-%ED%95%9C%EA%B3%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이전 장까지는 파이썬 코드 안의 리스트(ITEMS = [...])에 데이터를 담아 CRUD를 구현했습니다.&lt;br /&gt;하지만 메모리 기반 데이터 관리는 실제 상용 서비스에서는 절대 사용할 수 없는 치명적인 결함이 있습니다:&lt;/p&gt;
&lt;div data-plain=&quot;graph TD
    subgraph Memory[&amp;quot;❌ 파이썬 메모리 (RAM) 기반&amp;quot;]
        M1[&amp;quot;서버 재시작(Reload/배포) 시&amp;lt;br/&amp;gt;모든 데이터 즉시 증발!&amp;quot;]
        M2[&amp;quot;서버 인스턴스가 2개 이상일 때&amp;lt;br/&amp;gt;서버 간 데이터 동기화/공유 불가!&amp;quot;]
    end

    subgraph Database[&amp;quot;✅ 데이터베이스 (SSD/디스크) 기반&amp;quot;]
        D1[&amp;quot;영속성: 서버가 꺼져도 안전 보존&amp;quot;]
        D2[&amp;quot;중앙 집중: 모든 서버/사용자가 동일 데이터 공유&amp;quot;]
    end

    Memory -.-&amp;gt;|해결| Database&quot; data-json=&quot;{&amp;quot;data&amp;quot;:&amp;quot;graph TD\n    subgraph Memory[\&amp;quot;❌ 파이썬 메모리 (RAM) 기반\&amp;quot;]\n        M1[\&amp;quot;서버 재시작(Reload/배포) 시&amp;lt;br/&amp;gt;모든 데이터 즉시 증발!\&amp;quot;]\n        M2[\&amp;quot;서버 인스턴스가 2개 이상일 때&amp;lt;br/&amp;gt;서버 간 데이터 동기화/공유 불가!\&amp;quot;]\n    end\n\n    subgraph Database[\&amp;quot;✅ 데이터베이스 (SSD/디스크) 기반\&amp;quot;]\n        D1[\&amp;quot;영속성: 서버가 꺼져도 안전 보존\&amp;quot;]\n        D2[\&amp;quot;중앙 집중: 모든 서버/사용자가 동일 데이터 공유\&amp;quot;]\n    end\n\n    Memory -.-&amp;gt;|해결| Database\n&amp;quot;}&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;1020&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXZzII/dJMb99VRHEs/pDFuwgykfT1EGmICeVyqdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXZzII/dJMb99VRHEs/pDFuwgykfT1EGmICeVyqdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXZzII/dJMb99VRHEs/pDFuwgykfT1EGmICeVyqdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXZzII%2FdJMb99VRHEs%2FpDFuwgykfT1EGmICeVyqdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;329&quot; height=&quot;379&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;1020&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;휘발성 (서버 재시작 시 데이터 소멸)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RAM(메모리)에 상주하므로 코드를 수정해 서버가 리로드되거나, 배포, 서버 재부팅이 발생하는 순간&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기존에 저장된 모든 데이터가 영구적으로 날아갑니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동시 공유 불가 (다중 프로세스/서버 환경)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 서비스는 트래픽을 감당하기 위해 서버 프로세스를 여러 개(Uvicorn 워커 4개, 도커 컨테이너 여러 대) 띄웁니다.&lt;/li&gt;
&lt;li&gt;각 프로세스는 독립된 메모리를 가지므로, 1번 서버에서 등록한 상품을 2번 서버에서는 조회할 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. 데이터베이스의 3대 핵심 역할 (영속성, 동시성, 신뢰성)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-2-데이터베이스의-3대-핵심-역할-영속성-동시성-신뢰성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#1-2-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%9D%98-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%EC%97%AD%ED%95%A0-%EC%98%81%EC%86%8D%EC%84%B1-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%8B%A0%EB%A2%B0%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;1. 영속성 (Persistence)&lt;/b&gt;:&lt;br /&gt;서버가 다운되거나 재부팅되더라도 하드디스크/SSD의 물리적 파일이나 블록에 데이터가 영구적으로 안전하게 기록됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2. 동시성 (Concurrency)&lt;/b&gt;:&lt;br /&gt;수천, 수만 명의 사용자가 동시에 같은 상품을 조회하고 주문하더라도 락(Lock)과 격리 수준(Isolation)을 통해 데이터 충돌 없이 안전하게 조율합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3. 신뢰성 (Reliability / ACID)&lt;/b&gt;:&lt;br /&gt;트랜잭션(Transaction)을 지원하여, 작업 도중 에러가 발생하면 이전 상태로 완벽히 되돌리는 롤백(Rollback)을 보장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. SQL 직접 작성(Raw SQL)의 한계와 ORM의 탄생&lt;/h2&gt;
&lt;a id=&quot;user-content-2-sql-직접-작성raw-sql의-한계와-orm의-탄생&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-sql-%EC%A7%81%EC%A0%91-%EC%9E%91%EC%84%B1raw-sql%EC%9D%98-%ED%95%9C%EA%B3%84%EC%99%80-orm%EC%9D%98-%ED%83%84%EC%83%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 클라이언트 - FastAPI - SQLite 전체 아키텍처&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;color: #1f2328;&quot;&gt;
&lt;pre id=&quot;code_1792993249952&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to render rich display

Parse error on line 10:
...m); session.commit() ORM-&amp;gt;&amp;gt;DB: INSER
-----------------------^
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'SOLID_ARROW_TOP', 'SOLID_ARROW_BOTTOM', 'STICK_ARROW_TOP', 'STICK_ARROW_BOTTOM', 'SOLID_ARROW_TOP_DOTTED', 'SOLID_ARROW_BOTTOM_DOTTED', 'STICK_ARROW_TOP_DOTTED', 'STICK_ARROW_BOTTOM_DOTTED', 'SOLID_ARROW_TOP_REVERSE', 'SOLID_ARROW_BOTTOM_REVERSE', 'STICK_ARROW_TOP_REVERSE', 'STICK_ARROW_BOTTOM_REVERSE', 'SOLID_ARROW_TOP_REVERSE_DOTTED', 'SOLID_ARROW_BOTTOM_REVERSE_DOTTED', 'STICK_ARROW_TOP_REVERSE_DOTTED', 'STICK_ARROW_BOTTOM_REVERSE_DOTTED', 'BIDIRECTIONAL_SOLID_ARROW', 'DOTTED_ARROW', 'BIDIRECTIONAL_DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'NEWLINE'

For more information, see https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;sequenceDiagram
    autonumber
    actor Client as 클라이언트 (웹/앱)
    participant API as FastAPI 백엔드
    participant ORM as ORM (SQLAlchemy)
    participant DB as SQLite DB (test.db)

    Client-&amp;gt;&amp;gt;API: HTTP POST /items {&quot;name&quot;: &quot;apple&quot;, &quot;price&quot;: 1000}
    Note over API: Pydantic으로 Request Body 유효성 검증
    API-&amp;gt;&amp;gt;ORM: item = Item(name=..., price=...)&amp;lt;br/&amp;gt;session.add(item); session.commit()
    ORM-&amp;gt;&amp;gt;DB: INSERT INTO items (name, price) VALUES ('apple', 1000);
    DB--&amp;gt;&amp;gt;ORM: 1 Row Inserted (id=1 발급)
    ORM--&amp;gt;&amp;gt;API: Item ORM 객체 반환
    API--&amp;gt;&amp;gt;Client: HTTP 201 Created {&quot;id&quot;: 1, &quot;name&quot;: &quot;apple&quot;, &quot;price&quot;: 1000}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. &quot;SQL을 코드 안에 직접 적었을 때&quot;의 2대 문제점&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-sql을-코드-안에-직접-적었을-때의-2대-문제점&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-2-sql%EC%9D%84-%EC%BD%94%EB%93%9C-%EC%95%88%EC%97%90-%EC%A7%81%EC%A0%91-%EC%A0%81%EC%97%88%EC%9D%84-%EB%95%8C%EC%9D%98-2%EB%8C%80-%EB%AC%B8%EC%A0%9C%EC%A0%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터베이스와 통신할 때 과거처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;SELECT * FROM items WHERE id = ?&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 원시 SQL(Raw SQL) 쿼리문을 파이썬 문자열로 직접 하드코딩하면 다음과 같은 심각한 문제가 발생합니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;스키마 변경 시 연관된 쿼리를 직접 관리 (유지보수 지옥)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 테이블 구조(컬럼명 변경, 새 필드 추가 등)가 바뀌면, 파이썬 코드 전체에 흩어진 모든 SQL 문자열(SELECT,&lt;span&gt;&amp;nbsp;&lt;/span&gt;INSERT,&lt;span&gt;&amp;nbsp;&lt;/span&gt;UPDATE)을 개발자가 일일이 검색해서 수동으로 고쳐야 합니다.&lt;/li&gt;
&lt;li&gt;오타 하나로 런타임 SQL Syntax Error가 터지는 등 휴먼 에러가 빈번해집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SQL ➔ tuple ➔ 객체화 (데이터 변환의 극심한 번거로움)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL을 실행하면 DB 드라이버는 데이터를 순수한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;튜플((1, 'apple', 1000))이나 로우(Row)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;형태로 반환합니다.&lt;/li&gt;
&lt;li&gt;개발자가&lt;span&gt;&amp;nbsp;&lt;/span&gt;item_id = row[0],&lt;span&gt;&amp;nbsp;&lt;/span&gt;item_name = row[1]&lt;span&gt;&amp;nbsp;&lt;/span&gt;처럼 수동으로 인덱싱해서 파이썬 객체로 조립하는 노가다 코드를 수없이 작성해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. ORM(Object-Relational Mapping)이란?&lt;/h3&gt;
&lt;a id=&quot;user-content-2-3-ormobject-relational-mapping이란&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-3-ormobject-relational-mapping%EC%9D%B4%EB%9E%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ORM (객체 관계 매핑)&lt;/b&gt;:&lt;br /&gt;문자열 형태의 SQL 쿼리를 개발자가 직접 작성하는 대신,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;객체 지향 프로그래밍(OOP) 언어의 문법(파이썬 클래스와 인스턴스)으로 데이터베이스를 다룰 수 있게 해주는 중개 기술&lt;/b&gt;입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1110&quot; data-origin-height=&quot;1108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FZJn0/dJMcadcNpVq/C43UdCvmokLRqZ0DL2g2L0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FZJn0/dJMcadcNpVq/C43UdCvmokLRqZ0DL2g2L0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FZJn0/dJMcadcNpVq/C43UdCvmokLRqZ0DL2g2L0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFZJn0%2FdJMcadcNpVq%2FC43UdCvmokLRqZ0DL2g2L0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;410&quot; data-origin-width=&quot;1110&quot; data-origin-height=&quot;1108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-4. ORM 3대 매핑 공식 (테이블=클래스, 행=인스턴스, 열=속성)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-4-orm-3대-매핑-공식-테이블클래스-행인스턴스-열속성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#2-4-orm-3%EB%8C%80-%EB%A7%A4%ED%95%91-%EA%B3%B5%EC%8B%9D-%ED%85%8C%EC%9D%B4%EB%B8%94%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%96%89%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EC%97%B4%EC%86%8D%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;RDB (관계형 데이터베이스)&amp;nbsp; &amp;nbsp; &amp;nbsp; ➔ 매핑 ➔&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Python (객체 지향 언어)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 실전 코드 예시&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 23.6047%;&quot;&gt;&lt;b&gt;1개 테이블 (Table)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.2093%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 29.4185%;&quot;&gt;&lt;b&gt;1개 클래스 (Class)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 34.6512%;&quot;&gt;class Item(Base):&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;items&lt;span&gt;&amp;nbsp;&lt;/span&gt;테이블&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 23.6047%;&quot;&gt;&lt;b&gt;1개 행 (Row / 레코드)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.2093%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 29.4185%;&quot;&gt;&lt;b&gt;1개 인스턴스 (Object)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 34.6512%;&quot;&gt;item = Item(...)&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔ 테이블의 한 줄 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 23.6047%;&quot;&gt;&lt;b&gt;1개 열 (Column / 필드)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.2093%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 29.4185%;&quot;&gt;&lt;b&gt;1개 인스턴스 속성 (Attribute)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 34.6512%;&quot;&gt;item.name,&lt;span&gt;&amp;nbsp;&lt;/span&gt;item.price&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;name,&lt;span&gt;&amp;nbsp;&lt;/span&gt;price&lt;span&gt;&amp;nbsp;&lt;/span&gt;컬럼&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. SQLAlchemy: Python 표준 ORM 라이브러리&lt;/h2&gt;
&lt;a id=&quot;user-content-3-sqlalchemy-python-표준-orm-라이브러리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#3-sqlalchemy-python-%ED%91%9C%EC%A4%80-orm-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. SQLAlchemy를 사용하는 이유와 프레임워크별 ORM 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1-sqlalchemy를-사용하는-이유와-프레임워크별-orm-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#3-1-sqlalchemy%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%99%80-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EB%B3%84-orm-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SQLAlchemy&lt;/b&gt;는 파이썬 생태계에서 가장 강력하고 성숙하며, 널리 사용되는 사실상의 표준(Defacto Standard) ORM입니다.&lt;/li&gt;
&lt;li&gt;FastAPI와 설계 철학이 완벽하게 들어맞으며, 대규모 트래픽 환경에서도 안정적인 커넥션 풀링과 트랜잭션 관리를 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Python 웹 프레임워크별 ORM 스타일 비교:&lt;/h4&gt;
&lt;a id=&quot;user-content-python-웹-프레임워크별-orm-스타일-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#python-%EC%9B%B9-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EB%B3%84-orm-%EC%8A%A4%ED%83%80%EC%9D%BC-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Django&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;Django ORM&lt;span&gt;&amp;nbsp;&lt;/span&gt;내장 (Active Record 패턴: 모델 객체 자체가 DB 저장 메서드를 가짐&lt;span&gt;&amp;nbsp;&lt;/span&gt;item.save())&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FastAPI&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;SQLAlchemy,&lt;span&gt;&amp;nbsp;&lt;/span&gt;SQLModel,&lt;span&gt;&amp;nbsp;&lt;/span&gt;TortoiseORM&lt;span&gt;&amp;nbsp;&lt;/span&gt;자유 선택 (Data Mapper 패턴: 비즈니스 로직과 DB 영속성 레이어를 세션으로 명확히 분리)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. 패키지 설치 (pip install SQLAlchemy)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2-패키지-설치-pip-install-sqlalchemy&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#3-2-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EC%B9%98-pip-install-sqlalchemy&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가상환경(.venv)이 활성화된 상태에서 설치합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;cmake&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;pip install SQLAlchemy&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. SQLAlchemy 기초 3대 요소 (Engine, Session, Model)&lt;/h2&gt;
&lt;a id=&quot;user-content-4-sqlalchemy-기초-3대-요소-engine-session-model&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-sqlalchemy-%EA%B8%B0%EC%B4%88-3%EB%8C%80-%EC%9A%94%EC%86%8C-engine-session-model&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SQLAlchemy를 지탱하는 3개의 핵심 기둥입니다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;186&quot; data-origin-height=&quot;924&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tZlU0/dJMcahfsaKo/Z8rELLtihPOD0OiGxYRmtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tZlU0/dJMcahfsaKo/Z8rELLtihPOD0OiGxYRmtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tZlU0/dJMcahfsaKo/Z8rELLtihPOD0OiGxYRmtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtZlU0%2FdJMcahfsaKo%2FZ8rELLtihPOD0OiGxYRmtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;152&quot; height=&quot;755&quot; data-origin-width=&quot;186&quot; data-origin-height=&quot;924&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. Engine (엔진): DB 물리적 연결의 관문&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-engine-엔진-db-물리적-연결의-관문&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-1-engine-%EC%97%94%EC%A7%84-db-%EB%AC%BC%EB%A6%AC%EC%A0%81-%EC%97%B0%EA%B2%B0%EC%9D%98-%EA%B4%80%EB%AC%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬 애플리케이션과 실제 SQLite 데이터베이스 파일(test.db&lt;span&gt;&amp;nbsp;&lt;/span&gt;등) 사이의 **물리적인 연결 통로(Connection Pool)**를 쥐고 있는 핵심 객체입니다.&lt;/li&gt;
&lt;li&gt;개발자가 작성한 ORM 코드를 실제 SQL 문장으로 번역하여 DB에 전달하고 실행합니다.&lt;/li&gt;
&lt;li&gt;echo=True&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션을 주면 실행되는 원시 SQL 로그를 터미널에 실시간으로 출력해 주어 학습과 디버깅에 매우 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. Session (세션): 작업 단위와 트랜잭션 관리&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-session-세션-작업-단위와-트랜잭션-관리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-2-session-%EC%84%B8%EC%85%98-%EC%9E%91%EC%97%85-%EB%8B%A8%EC%9C%84%EC%99%80-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EA%B4%80%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제로 데이터를 추가(add), 조회(select), 수정, 삭제(delete)할 때 엔진 위에 띄우는 **작업 창구(단위)**입니다.&lt;/li&gt;
&lt;li&gt;트랜잭션(Transaction)을 시작하고, 변경 사항을 모아두었다가&lt;span&gt;&amp;nbsp;&lt;/span&gt;commit()&lt;span&gt;&amp;nbsp;&lt;/span&gt;시점에 한 번에 DB에 반영합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3. Model (모델): 파이썬 클래스로 표현한 테이블&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-model-모델-파이썬-클래스로-표현한-테이블&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-3-model-%EB%AA%A8%EB%8D%B8-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A1%9C-%ED%91%9C%ED%98%84%ED%95%9C-%ED%85%8C%EC%9D%B4%EB%B8%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스의 테이블 스키마를 파이썬 클래스로 정의한 청사진입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-4. 엔진을 통한 데이터베이스 요청/실행 전체 흐름&lt;/h3&gt;
&lt;a id=&quot;user-content-4-4-엔진을-통한-데이터베이스-요청실행-전체-흐름&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#4-4-%EC%97%94%EC%A7%84%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%9A%94%EC%B2%AD%EC%8B%A4%ED%96%89-%EC%A0%84%EC%B2%B4-%ED%9D%90%EB%A6%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;연결 생성 (Engine)&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;create_engine(DATABASE_URL)이 DB와의 통신 회선을 개설합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세션 생성 (Session)&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;session = SessionFactory()를 통해 실제 작업자가 창구(세션)를 엽니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;요청 전달 및 실행&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.add()&lt;span&gt;&amp;nbsp;&lt;/span&gt;또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.execute(stmt)를 호출하면 세션이 엔진에게 전달하고, 엔진이 실제 SQL을 실행한 뒤 결과를 파이썬 객체로 감싸서 돌려줍니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. SQLAlchemy 2.0 모던 모델 정의와 테이블 자동 생성&lt;/h2&gt;
&lt;a id=&quot;user-content-5-sqlalchemy-20-모던-모델-정의와-테이블-자동-생성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-sqlalchemy-20-%EB%AA%A8%EB%8D%98-%EB%AA%A8%EB%8D%B8-%EC%A0%95%EC%9D%98%EC%99%80-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%9E%90%EB%8F%99-%EC%83%9D%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;DeclarativeBase를 상속한&lt;span&gt;&amp;nbsp;&lt;/span&gt;Base&lt;span&gt;&amp;nbsp;&lt;/span&gt;선언&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-declarativebase를-상속한-base-선언&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-1-declarativebase%EB%A5%BC-%EC%83%81%EC%86%8D%ED%95%9C-base-%EC%84%A0%EC%96%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SQLAlchemy 2.0부터는&lt;span&gt;&amp;nbsp;&lt;/span&gt;declarative_base()&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수 대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DeclarativeBase&lt;span&gt;&amp;nbsp;&lt;/span&gt;클래스를 상속받는 깔끔한 클래스 선언 방식&lt;/b&gt;을 표준으로 권장합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from sqlalchemy.orm import DeclarativeBase

# 모든 ORM 모델들이 상속받을 최상위 부모 클래스
class Base(DeclarativeBase):
    pass&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Mapped와&lt;span&gt;&amp;nbsp;&lt;/span&gt;mapped_column을 활용한 Item 모델 정의&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-mapped와-mapped_column을-활용한-item-모델-정의&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-2-mapped%EC%99%80-mapped_column%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-item-%EB%AA%A8%EB%8D%B8-%EC%A0%95%EC%9D%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;파이썬의 표준 타입 힌트 시스템과 결합된 모던 문법입니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;haskell&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import Integer, String

class Item(Base):
    # 실제 생성될 데이터베이스 테이블 이름 지정
    __tablename__ = &quot;items&quot;

    # id: 정수형, 기본키(PK), 1부터 자동 증가(Auto-increment)
    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    
    # name: 문자열(최대 128자)
    name: Mapped[str] = mapped_column(String(128))
    
    # price: 정수형
    price: Mapped[int] = mapped_column(Integer)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 왜 DB 컬럼의 타입을 고정해야 하는가? (일관성 &amp;amp; 저장 효율성)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3-왜-db-컬럼의-타입을-고정해야-하는가-일관성--저장-효율성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-3-%EC%99%9C-db-%EC%BB%AC%EB%9F%BC%EC%9D%98-%ED%83%80%EC%9E%85%EC%9D%84-%EA%B3%A0%EC%A0%95%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80-%EC%9D%BC%EA%B4%80%EC%84%B1--%EC%A0%80%EC%9E%A5-%ED%9A%A8%EC%9C%A8%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;일관성 (Data Consistency)&lt;/b&gt;:&lt;br /&gt;가격(price) 컬럼에 어떤 사람은 문자열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;천원&quot;을 넣고 어떤 사람은 숫자&lt;span&gt;&amp;nbsp;&lt;/span&gt;1000을 넣으면 계산과 정렬이 불가능해집니다. 타입을 고정하여 데이터의 무결성을 지킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;저장 효율성 (Storage Efficiency)&lt;/b&gt;:&lt;br /&gt;정수형(Integer)은 4바이트 고정 메모리를 사용하므로 디스크 공간을 절약하고 검색 색인(인덱스) 속도를 극대화합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Base.metadata.create_all(bind=engine)&lt;span&gt;&amp;nbsp;&lt;/span&gt;테이블 자동 생성&lt;/h3&gt;
&lt;a id=&quot;user-content-5-4-basemetadatacreate_allbindengine-테이블-자동-생성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#5-4-basemetadatacreate_allbindengine-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%9E%90%EB%8F%99-%EC%83%9D%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정의한 파이썬 모델 클래스를 바탕으로 SQLite DB 파일에 실제 물리적 테이블을 한 줄로 생성합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from sqlalchemy import create_engine

DATABASE_URL = &quot;sqlite:///./test.db&quot;
engine = create_engine(DATABASE_URL, echo=True)

# Base를 상속받은 모든 모델(Item 등)의 CREATE TABLE 문을 자동 실행!
Base.metadata.create_all(bind=engine)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;터미널 출력 로그:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;sql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;CREATE TABLE items (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(128) NOT NULL,
    price INTEGER NOT NULL
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 세션의 라이프사이클과 데이터 저장 (Staging ➔ Commit)&lt;/h2&gt;
&lt;a id=&quot;user-content-6-세션의-라이프사이클과-데이터-저장-staging--commit&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#6-%EC%84%B8%EC%85%98%EC%9D%98-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4%EA%B3%BC-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%80%EC%9E%A5-staging--commit&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. 객체 생성 vs&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.add()&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Staging 상태의 의미)&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-객체-생성-vs-sessionadd-staging-상태의-의미&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#6-1-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1-vs-sessionadd-staging-%EC%83%81%ED%83%9C%EC%9D%98-%EC%9D%98%EB%AF%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 1단계: 순수 파이썬 객체 생성
item = Item(name=&quot;apple&quot;, price=100)
# ⚠️ 이 시점에는 파이썬 RAM 메모리에만 존재하며, SQLite DB 파일에는 전혀 기록되지 않음!

# 2단계: 세션에 등록 (Staging)
session.add(item)
# &quot;이 객체를 나중에 DB에 저장할 거니까 영속성 관리 영역(Persistence)에 등록해 둬!&quot;
# Git으로 치면 `git add`를 실행해 스테이징 영역에 올려둔 것과 동일합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.commit()과&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.close()&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-sessioncommit과-sessionclose&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#6-2-sessioncommit%EA%B3%BC-sessionclose&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 3단계: 변경 사항을 DB에 영구 확정 (Commit)
session.commit()
# Git의 `git commit`처럼 실제 DB 파일에 INSERT SQL 쿼리가 날아가 영구 기록됩니다.

# 4단계: 세션 종료 (Close)
session.close()
# 점유했던 DB 커넥션 자원을 깔끔하게 반납합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-3. 다중 데이터 일괄 등록과&lt;span&gt;&amp;nbsp;&lt;/span&gt;RETURNING id의 원리&lt;/h3&gt;
&lt;a id=&quot;user-content-6-3-다중-데이터-일괄-등록과-returning-id의-원리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#6-3-%EB%8B%A4%EC%A4%91-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9D%BC%EA%B4%84-%EB%93%B1%EB%A1%9D%EA%B3%BC-returning-id%EC%9D%98-%EC%9B%90%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여러 데이터를 한 번에 세션에 담고 커밋할 수 있습니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;item2 = Item(name=&quot;banana&quot;, price=200)
item3 = Item(name=&quot;cherry&quot;, price=300)

session.add(item2)
session.add(item3)
session.commit()

# DB 엔진 로그:
# INSERT INTO items (name, price) VALUES (?, ?) RETURNING id&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;Note&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;RETURNING id의 의미&lt;/b&gt;:&lt;br /&gt;우리가 코드로&lt;span&gt;&amp;nbsp;&lt;/span&gt;item2를 만들 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;id&lt;span&gt;&amp;nbsp;&lt;/span&gt;값을 지정하지 않았지만, 데이터베이스가 기본키 자동 증가를 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;id=2,&lt;span&gt;&amp;nbsp;&lt;/span&gt;id=3을 발급한 뒤&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;즉시 파이썬 객체의&lt;span&gt;&amp;nbsp;&lt;/span&gt;id&lt;span&gt;&amp;nbsp;&lt;/span&gt;속성에 자동으로 채워줍니다!&lt;/b&gt;&lt;br /&gt;print(item2.id)&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;2&lt;span&gt;&amp;nbsp;&lt;/span&gt;출력!&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. SQLAlchemy 데이터 조회(SELECT)와 Result 객체의 비밀&lt;/h2&gt;
&lt;a id=&quot;user-content-7-sqlalchemy-데이터-조회select와-result-객체의-비밀&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-sqlalchemy-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A1%B0%ED%9A%8Cselect%EC%99%80-result-%EA%B0%9D%EC%B2%B4%EC%9D%98-%EB%B9%84%EB%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;select()&lt;span&gt;&amp;nbsp;&lt;/span&gt;쿼리문 빌드와&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.execute()&lt;/h3&gt;
&lt;a id=&quot;user-content-7-1-select-쿼리문-빌드와-sessionexecute&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-1-select-%EC%BF%BC%EB%A6%AC%EB%AC%B8-%EB%B9%8C%EB%93%9C%EC%99%80-sessionexecute&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SQLAlchemy 2.0에서는 함수형 쿼리 빌더인&lt;span&gt;&amp;nbsp;&lt;/span&gt;select()를 사용합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;armasm&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from sqlalchemy import select

# 1. 쿼리문 객체 생성
stmt = select(Item)
print(stmt)  # 출력: SELECT items.id, items.name, items.price FROM items

# 2. 쿼리 실행
result = session.execute(stmt)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-2. 왜&lt;span&gt;&amp;nbsp;&lt;/span&gt;print(result)&lt;span&gt;&amp;nbsp;&lt;/span&gt;해도 데이터가 안 보일까? (Iterator/Result 커서)&lt;/h3&gt;
&lt;a id=&quot;user-content-7-2-왜-printresult-해도-데이터가-안-보일까-iteratorresult-커서&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-2-%EC%99%9C-printresult-%ED%95%B4%EB%8F%84-%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-%EC%95%88-%EB%B3%B4%EC%9D%BC%EA%B9%8C-iteratorresult-%EC%BB%A4%EC%84%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;많은 입문자가&lt;span&gt;&amp;nbsp;&lt;/span&gt;print(result)를 해보고 당황합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;print(result)
# 출력: &amp;lt;sqlalchemy.engine.result.ChunkedIteratorResult object at 0x103b616a0&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이유&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;result는 데이터 리스트 자체가 아니라, **데이터베이스에서 데이터를 한 줄씩 꺼내올 수 있는 '결과 핸들러(Iterator / Result 커서)'**이기 때문입니다.&lt;/li&gt;
&lt;li&gt;사물함 안에 데이터가 들어있는데, 사물함의 겉모습(메모리 주소)만 출력한 것과 같습니다.&lt;/li&gt;
&lt;li&gt;따라서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터를 실제로 꺼내는 전용 메서드(mappings(),&lt;span&gt;&amp;nbsp;&lt;/span&gt;all(),&lt;span&gt;&amp;nbsp;&lt;/span&gt;scalars())를 호출&lt;/b&gt;해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-3. 3대 데이터 추출 메서드 비교 (mappings,&lt;span&gt;&amp;nbsp;&lt;/span&gt;all,&lt;span&gt;&amp;nbsp;&lt;/span&gt;scalars)&lt;/h3&gt;
&lt;a id=&quot;user-content-7-3-3대-데이터-추출-메서드-비교-mappings-all-scalars&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-3-3%EB%8C%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%94%EC%B6%9C-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%B9%84%EA%B5%90-mappings-all-scalars&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOxKXS/dJMcaggnJAU/oCDKg7ZQiED8p1K5jY4UW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOxKXS/dJMcaggnJAU/oCDKg7ZQiED8p1K5jY4UW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOxKXS/dJMcaggnJAU/oCDKg7ZQiED8p1K5jY4UW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOxKXS%2FdJMcaggnJAU%2FoCDKg7ZQiED8p1K5jY4UW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;611&quot; height=&quot;297&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;메서드&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;반환 데이터 형태&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;주요 용도&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;result.mappings().all()&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;list[dict]&lt;span&gt;&amp;nbsp;&lt;/span&gt;(딕셔너리 리스트)&lt;/td&gt;
&lt;td&gt;딕셔너리 형태로 JSON 직렬화하거나 키값으로 접근할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;result.all()&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;list[tuple]&lt;span&gt;&amp;nbsp;&lt;/span&gt;(튜플 리스트)&lt;/td&gt;
&lt;td&gt;원시 튜플 데이터 그대로 인덱싱할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;result.scalars().all()&lt;/b&gt;&lt;br /&gt;(또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.scalars(stmt).all())&lt;/td&gt;
&lt;td&gt;&lt;b&gt;list[Item]&lt;span&gt;&amp;nbsp;&lt;/span&gt;(ORM 객체 리스트)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;실무 최다 사용!&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;item.name,&lt;span&gt;&amp;nbsp;&lt;/span&gt;item.price&lt;span&gt;&amp;nbsp;&lt;/span&gt;처럼 ORM 객체로 다룰 때&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-4.   치명적 주의점: Result 커서의 일회성 소모(Consumption) 특성&lt;/h3&gt;
&lt;a id=&quot;user-content-7-4--치명적-주의점-result-커서의-일회성-소모consumption-특성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-4--%EC%B9%98%EB%AA%85%EC%A0%81-%EC%A3%BC%EC%9D%98%EC%A0%90-result-%EC%BB%A4%EC%84%9C%EC%9D%98-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%86%8C%EB%AA%A8consumption-%ED%8A%B9%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;⚠️&lt;span&gt;&amp;nbsp;&lt;/span&gt;한 번 비워버린 상자는 다시 쓸 수 없다!&lt;/b&gt;&lt;br /&gt;result&lt;span&gt;&amp;nbsp;&lt;/span&gt;커서 객체는&lt;span&gt;&amp;nbsp;&lt;/span&gt;result.mappings().all()을 호출하여 데이터를 모두 꺼내고 나면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;커서가 데이터의 맨 끝(End of File)에 도달&lt;/b&gt;합니다.&lt;br /&gt;따라서 바로 아래 줄에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;result.all()을 또 호출하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이미 비어버렸으므로 빈 리스트([])가 반환&lt;/b&gt;됩니다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;해결책:&lt;/h4&gt;
&lt;a id=&quot;user-content-해결책&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#%ED%95%B4%EA%B2%B0%EC%B1%85&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터를 다시 조회하고 싶다면, 반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;result = session.execute(stmt)로 쿼리를 재실행&lt;/b&gt;하여 새 커서를 받아와야 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-5. 특정 데이터 단일 조회:&lt;span&gt;&amp;nbsp;&lt;/span&gt;.where()와&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.scalar()&lt;/h3&gt;
&lt;a id=&quot;user-content-7-5-특정-데이터-단일-조회-where와-sessionscalar&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#7-5-%ED%8A%B9%EC%A0%95-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8B%A8%EC%9D%BC-%EC%A1%B0%ED%9A%8C-where%EC%99%80-sessionscalar&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조건절 추가:&lt;span&gt;&amp;nbsp;&lt;/span&gt;select(Item).where(Item.id == item_id)&lt;/li&gt;
&lt;li&gt;단일 객체 1개만 꺼낼 때는&lt;span&gt;&amp;nbsp;&lt;/span&gt;.all()이 아니라 **.scalar()**를 호출합니다:&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;applescript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;stmt = select(Item).where(Item.id == 1)

# 단 1개의 Item 인스턴스를 반환 (없으면 None)
item = session.scalar(stmt)
if item:
    print(item.name, item.price)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. FastAPI + SQLAlchemy 연동 실전 영속 CRUD 구현&lt;/h2&gt;
&lt;a id=&quot;user-content-8-fastapi--sqlalchemy-연동-실전-영속-crud-구현&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-fastapi--sqlalchemy-%EC%97%B0%EB%8F%99-%EC%8B%A4%EC%A0%84-%EC%98%81%EC%86%8D-crud-%EA%B5%AC%ED%98%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-1. DB 연결 및 세션 팩토리 공통 모듈 (connection.py)&lt;/h3&gt;
&lt;a id=&quot;user-content-8-1-db-연결-및-세션-팩토리-공통-모듈-connectionpy&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-1-db-%EC%97%B0%EA%B2%B0-%EB%B0%8F-%EC%84%B8%EC%85%98-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EA%B3%B5%ED%86%B5-%EB%AA%A8%EB%93%88-connectionpy&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# connection.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

DATABASE_URL = &quot;sqlite:///./test.db&quot;

# echo=True: 터미널에 실행되는 SQL 출력
engine = create_engine(
    DATABASE_URL,
    echo=True,
    connect_args={&quot;check_same_thread&quot;: False}  # SQLite를 FastAPI에서 쓸 때 필수 옵션
)

# 세션 생성 공장(SessionFactory)
SessionFactory = sessionmaker(
    bind=engine,
    autocommit=False,
    autoflush=False,
    expire_on_commit=False
)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-2. [Create] 상품 생성 (POST /items, try-finally vs Context Manager)&lt;/h3&gt;
&lt;a id=&quot;user-content-8-2-create-상품-생성-post-items-try-finally-vs-context-manager&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-2-create-%EC%83%81%ED%92%88-%EC%83%9D%EC%84%B1-post-items-try-finally-vs-context-manager&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;세션을 열고 닫는 방식에는 2가지 패턴이 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;방법 A: try-finally 패턴 (슬라이드 14페이지)&lt;/h4&gt;
&lt;a id=&quot;user-content-방법-a-try-finally-패턴-슬라이드-14페이지&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#%EB%B0%A9%EB%B2%95-a-try-finally-%ED%8C%A8%ED%84%B4-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%93%9C-14%ED%8E%98%EC%9D%B4%EC%A7%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.post(&quot;/items&quot;, response_model=ItemResponse, status_code=201)
def create_item(body: ItemCreateRequest):
    session = SessionFactory()
    try:
        new_item = Item(name=body.name, price=body.price)
        session.add(new_item)
        session.commit()
        return new_item
    finally:
        session.close()  # 에러가 발생해도 세션은 반드시 닫힘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;방법 B: Context Manager (with) 패턴 (슬라이드 15페이지 - 추천!)&lt;/h4&gt;
&lt;a id=&quot;user-content-방법-b-context-manager-with-패턴-슬라이드-15페이지---추천&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#%EB%B0%A9%EB%B2%95-b-context-manager-with-%ED%8C%A8%ED%84%B4-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%93%9C-15%ED%8E%98%EC%9D%B4%EC%A7%80---%EC%B6%94%EC%B2%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.post(&quot;/items&quot;, response_model=ItemResponse, status_code=201)
def create_item(body: ItemCreateRequest):
    # with 블록을 빠져나갈 때 session.close()가 자동으로 호출됨!
    with SessionFactory() as session:
        new_item = Item(name=body.name, price=body.price)
        session.add(new_item)
        session.commit()
        return new_item&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-3. [Read All] 전체 상품 조회 (GET /items,&lt;span&gt;&amp;nbsp;&lt;/span&gt;scalars().all())&lt;/h3&gt;
&lt;a id=&quot;user-content-8-3-read-all-전체-상품-조회-get-items-scalarsall&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-3-read-all-%EC%A0%84%EC%B2%B4-%EC%83%81%ED%92%88-%EC%A1%B0%ED%9A%8C-get-items-scalarsall&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;vim&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.get(&quot;/items&quot;, response_model=list[ItemResponse])
def list_items():
    session = SessionFactory()
    try:
        stmt = select(Item)
        items = session.scalars(stmt).all()
        return items
    finally:
        session.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-4. [Read One] 단일 상품 상세 조회 (GET /items/{item_id}, 404 예외)&lt;/h3&gt;
&lt;a id=&quot;user-content-8-4-read-one-단일-상품-상세-조회-get-itemsitem_id-404-예외&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-4-read-one-%EB%8B%A8%EC%9D%BC-%EC%83%81%ED%92%88-%EC%83%81%EC%84%B8-%EC%A1%B0%ED%9A%8C-get-itemsitem_id-404-%EC%98%88%EC%99%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;applescript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.get(&quot;/items/{item_id}&quot;, response_model=ItemResponse)
def get_item(item_id: int):
    session = SessionFactory()
    try:
        stmt = select(Item).where(Item.id == item_id)
        item = session.scalar(stmt)
        
        # 상품이 존재하지 않으면 404 에러 반환
        if item is None:
            raise HTTPException(status_code=404, detail=&quot;Item not found&quot;)
            
        return item
    finally:
        session.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-5. [Update] 상품 부분 수정 (PATCH /items/{item_id}, DB 변경 반영)&lt;/h3&gt;
&lt;a id=&quot;user-content-8-5-update-상품-부분-수정-patch-itemsitem_id-db-변경-반영&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-5-update-%EC%83%81%ED%92%88-%EB%B6%80%EB%B6%84-%EC%88%98%EC%A0%95-patch-itemsitem_id-db-%EB%B3%80%EA%B2%BD-%EB%B0%98%EC%98%81&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;수정할 필드가 전달되었는지(is not None) 각각 독립적인&lt;span&gt;&amp;nbsp;&lt;/span&gt;if문으로 검사한 뒤&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.commit()을 호출하면 DB에 즉시 UPDATE SQL이 실행됩니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;applescript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.patch(&quot;/items/{item_id}&quot;, response_model=ItemResponse)
def patch_item(item_id: int, body: ItemUpdateRequest):
    session = SessionFactory()
    try:
        stmt = select(Item).where(Item.id == item_id)
        item = session.scalar(stmt)
        
        if item is None:
            raise HTTPException(status_code=404, detail=&quot;Item not found&quot;)
        
        # 1. 이름이 들어왔으면 수정
        if body.name is not None:
            item.name = body.name
            
        # 2. 가격이 들어왔으면 수정 (elif가 아닌 독립된 if문!)
        if body.price is not None:
            item.price = body.price
            
        session.commit()  # 변경 사항 DB 반영
        return item
    finally:
        session.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-6. [Delete] 상품 삭제 (DELETE /items/{item_id},&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.delete)&lt;/h3&gt;
&lt;a id=&quot;user-content-8-6-delete-상품-삭제-delete-itemsitem_id-sessiondelete&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#8-6-delete-%EC%83%81%ED%92%88-%EC%82%AD%EC%A0%9C-delete-itemsitem_id-sessiondelete&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DB에서 조회한 ORM 객체를&lt;span&gt;&amp;nbsp;&lt;/span&gt;session.delete(item)에 전달하고 커밋하면 DELETE SQL이 실행됩니다.&lt;br /&gt;삭제 성공 시 본문 없는&lt;span&gt;&amp;nbsp;&lt;/span&gt;204 No Content&lt;span&gt;&amp;nbsp;&lt;/span&gt;응답을 반환합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import Response

@app.delete(&quot;/items/{item_id}&quot;, status_code=204)
def delete_item(item_id: int):
    session = SessionFactory()
    try:
        stmt = select(Item).where(Item.id == item_id)
        item = session.scalar(stmt)
        
        if item is None:
            raise HTTPException(status_code=404, detail=&quot;Item not found&quot;)
            
        session.delete(item)    # DB에서 삭제 예약
        session.commit()         # 삭제 확정
        return Response(status_code=204)
    finally:
        session.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-9--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day3/fastapi-sqlalchemy-orm-database-crud-note.md#9--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│            FastAPI &amp;amp; SQLAlchemy ORM 데이터베이스 핵심 치트시트         │
├──────────────────────────────┬─────────────────────────────────────────┤
│ 문법 / 개념                  │ 핵심 요약 및 사용 공식                  │
├──────────────────────────────┼─────────────────────────────────────────┤
│ RDB 도입 이유                │ 영속성(재시작 시 보존), 동시성, 신뢰성 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ ORM 매핑 3대 공식            │ 테이블 = 클래스 / 행 = 객체 / 열 = 속성 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Engine                       │ create_engine() : DB 물리적 연결 통로   │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Session                      │ SessionFactory() : DB 작업 창구/트랜잭션│
├──────────────────────────────┼─────────────────────────────────────────┤
│ class Base(DeclarativeBase): │ 모든 ORM 모델의 부모 클래스 선언        │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Mapped[T] = mapped_column()  │ SQLAlchemy 2.0 표준 컬럼 타입 매핑 문법 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Base.metadata.create_all()   │ 파이썬 모델 기준으로 실제 DB 테이블 생성│
├──────────────────────────────┼─────────────────────────────────────────┤
│ session.add(item)            │ 영속성 관리 영역(Staging)에 등록        │
├──────────────────────────────┼─────────────────────────────────────────┤
│ session.commit()             │ 변경 사항을 실제 DB 파일에 최종 확정    │
├──────────────────────────────┼─────────────────────────────────────────┤
│ session.close()              │ DB 세션 및 연결 자원 반납               │
├──────────────────────────────┼─────────────────────────────────────────┤
│ with SessionFactory() as s:  │ Context Manager로 세션 자동 닫기 보장   │
├──────────────────────────────┼─────────────────────────────────────────┤
│ session.scalars(stmt).all()  │ 쿼리 결과를 ORM 객체 리스트로 추출      │
├──────────────────────────────┼─────────────────────────────────────────┤
│ result.mappings().all()      │ 쿼리 결과를 딕셔너리 리스트로 추출      │
├──────────────────────────────┼─────────────────────────────────────────┤
│ session.scalar(stmt)         │ .where() 조건에 맞는 단일 객체 1개 추출 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ session.delete(item)         │ 조회된 ORM 객체를 DB에서 삭제           │
└──────────────────────────────┴─────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/36</guid>
      <comments>https://write31991.tistory.com/36#entry36comment</comments>
      <pubDate>Mon, 26 Oct 2026 15:01:01 +0900</pubDate>
    </item>
    <item>
      <title>FastAPI 2일차</title>
      <link>https://write31991.tistory.com/35</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-has-sidebar=&quot;true&quot; data-component=&quot;SplitPageLayout&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div data-is-hidden-narrow=&quot;false&quot; data-component=&quot;SplitPageLayout.Content&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div id=&quot;repos-split-pane-content&quot; data-selector=&quot;repos-split-pane-content&quot;&gt;
&lt;div data-hpc=&quot;true&quot;&gt;
&lt;div&gt;
&lt;h1&gt;⚡ FastAPI &amp;amp; Pydantic 데이터 검증과 실전 CRUD 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content--fastapi--pydantic-데이터-검증과-실전-crud-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#-fastapi--pydantic-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B2%80%EC%A6%9D%EA%B3%BC-%EC%8B%A4%EC%A0%84-crud-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python 백엔드의 심장 **타입 힌트(Type Hints)**부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Request Body와 직렬화/역직렬화 메커니즘&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Pydantic의 핵심 동작 원리(BaseModel,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Field,&lt;span&gt;&amp;nbsp;&lt;/span&gt;model_dump)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Response Model의 3대 가치(검증, 민감정보 필터링, 문서화)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTTP 상태 코드(201, 200, 204, 404, 422) 설계 표준&lt;/b&gt;, 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTTPException&lt;span&gt;&amp;nbsp;&lt;/span&gt;에러 핸들링과 완벽한 CRUD(Create, Read, Update, Delete) 풀 구현&lt;/b&gt;까지 총정리한 실전 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-type-hints-%ED%83%80%EC%9E%85-%ED%9E%8C%ED%8A%B8%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-%EB%AA%A8%EB%8D%98-%EB%AC%B8%EB%B2%95&quot;&gt;Type Hints (타입 힌트)의 본질과 모던 문법&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-1-type-hints%EB%A5%BC-%EC%93%B0%EB%8A%94-4%EB%8C%80-%EC%9D%B4%EC%9C%A0-%EC%99%9C-fastapi%EB%8A%94-%ED%83%80%EC%9E%85-%ED%9E%8C%ED%8A%B8-%EC%9C%84%EC%97%90-%EC%A7%80%EC%96%B4%EC%A1%8C%EB%8A%94%EA%B0%80&quot;&gt;1-1. Type Hints를 쓰는 4대 이유 (왜 FastAPI는 타입 힌트 위에 지어졌는가?)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-2-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95%EA%B3%BC-%EC%9C%A0%EB%8B%88%EC%98%A8-%ED%83%80%EC%9E%85-&quot;&gt;1-2. 기본 자료형과 유니온 타입 (|)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-3-%ED%95%A8%EC%88%98%EC%9D%98-%EC%9D%B8%EC%9E%90-%EB%B0%8F-%EB%B0%98%ED%99%98-%ED%83%80%EC%9E%85-%EC%A7%80%EC%A0%95--&quot;&gt;1-3. 함수의 인자 및 반환 타입 지정 (-&amp;gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-4-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%83%80%EC%9E%85-listt-dictk-v-%EC%A4%91%EC%B2%A9-%EA%B5%AC%EC%A1%B0&quot;&gt;1-4. 컬렉션 타입 (list[T],&amp;nbsp;dict[K, V], 중첩 구조)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-5-optional-%ED%83%80%EC%9E%85-t--none--none&quot;&gt;1-5. Optional 타입 (T | None = None)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#2-request-body%EC%99%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A7%81%EB%A0%AC%ED%99%94--%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94&quot;&gt;Request Body와 데이터 직렬화 / 역직렬화&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#2-1-pathquery-vs-request-body%EC%9D%98-%EA%B2%B0%EC%A0%95%EC%A0%81-%EC%B0%A8%EC%9D%B4&quot;&gt;2-1. Path/Query vs Request Body의 결정적 차이&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#2-2-%EC%A7%81%EB%A0%AC%ED%99%94serialization-vs-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94deserialization-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC&quot;&gt;2-2. 직렬화(Serialization) vs 역직렬화(Deserialization) 개념 정리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-pydantic-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B2%80%EC%A6%9D%EA%B3%BC-%ED%8C%8C%EC%8B%B1%EC%9D%98-%ED%95%B5%EC%8B%AC-%EC%97%94%EC%A7%84&quot;&gt;Pydantic: 데이터 검증과 파싱의 핵심 엔진&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-1-fastapi%EC%9D%98-2%EB%8C%80-%EC%A7%80%EC%A3%BC-starlette-vs-pydantic&quot;&gt;3-1. FastAPI의 2대 지주 (Starlette vs Pydantic)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-2-basemodel-%EC%A0%95%EC%9D%98%EC%99%80-%EC%9E%90%EB%8F%99-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98-%EC%9B%90%EB%A6%AC&quot;&gt;3-2.&amp;nbsp;BaseModel&amp;nbsp;정의와 자동 타입 변환 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-3-pydantic-%ED%95%B5%EC%8B%AC-%EB%A9%94%EC%84%9C%EB%93%9C-4%EC%84%A0-model_dump-model_dump_json-model_validate&quot;&gt;3-3. Pydantic 핵심 메서드 4선 (model_dump,&amp;nbsp;model_dump_json,&amp;nbsp;model_validate)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-4-field%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%A0%95%EB%B0%80%ED%95%9C-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC-min_length-ge-le&quot;&gt;3-4.&amp;nbsp;Field(...)를 활용한 정밀한 유효성 검사 (min_length,&amp;nbsp;ge,&amp;nbsp;le)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-fastapi%EC%97%90%EC%84%9C-request-body-%EB%8B%A4%EB%A3%A8%EA%B8%B0&quot;&gt;FastAPI에서 Request Body 다루기&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-1-pydantic-%EB%AA%A8%EB%8D%B8%EC%9D%84-%ED%83%80%EC%9E%85-%ED%9E%8C%ED%8A%B8%EB%A1%9C-%EC%A0%84%EB%8B%AC%ED%95%98%EC%97%AC-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EC%9E%90%EB%8F%99-%EC%A3%BC%EC%9E%85%EB%B0%9B%EA%B8%B0&quot;&gt;4-1. Pydantic 모델을 타입 힌트로 전달하여 인스턴스 자동 주입받기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-2-%EC%A0%90-%ED%91%9C%EA%B8%B0%EB%B2%95%EC%9D%84-%ED%86%B5%ED%95%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B3%A0-%ED%8E%B8%EB%A6%AC%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%91%EA%B7%BC&quot;&gt;4-2. 점(.) 표기법을 통한 안전하고 편리한 데이터 접근&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-3-%EA%B8%B0%EB%B3%B8%EA%B0%92default%EA%B3%BC-%EC%84%A0%ED%83%9D-%ED%95%84%EB%93%9Coptional-field-%EC%84%A4%EA%B3%84&quot;&gt;4-3. 기본값(Default)과 선택 필드(Optional Field) 설계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-4-%EA%B3%84%EC%B8%B5%ED%98%95-json%EC%9D%84-%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94-%EC%A4%91%EC%B2%A9-%EB%AA%A8%EB%8D%B8-nested-model&quot;&gt;4-4. 계층형 JSON을 처리하는 중첩 모델 (Nested Model)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-response-model-%EC%9D%91%EB%8B%B5-%EB%AA%A8%EB%8D%B8%EC%9D%98-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%EA%B0%80%EC%B9%98&quot;&gt;Response Model (응답 모델)의 3대 핵심 가치&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-1-%EC%99%9C-%EC%9D%91%EB%8B%B5-%EB%AA%A8%EB%8D%B8%EC%9D%84-%EB%B3%84%EB%8F%84%EB%A1%9C-%EC%A7%80%EC%A0%95%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80&quot;&gt;5-1. 왜 응답 모델을 별도로 지정해야 하는가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-2-%EA%B0%80%EC%B9%98-1-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%98%95%ED%83%9C-%EA%B2%80%EC%A6%9D-validation&quot;&gt;5-2. 가치 1: 데이터 형태 검증 (Validation)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-3-%EA%B0%80%EC%B9%98-2-%EB%AF%BC%EA%B0%90%EC%A0%95%EB%B3%B4-%EB%A7%88%EC%8A%A4%ED%82%B9-%EB%B0%8F-%EB%B6%88%ED%95%84%EC%9A%94%ED%95%9C-%ED%95%84%EB%93%9C-%EC%9E%90%EB%8F%99-%EC%A0%9C%EA%B1%B0-filtering&quot;&gt;5-3. 가치 2: 민감정보 마스킹 및 불필요한 필드 자동 제거 (Filtering)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-4-%EA%B0%80%EC%B9%98-3-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%98%91%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%9C-swagger-%EB%AC%B8%EC%84%9C-%EC%9E%90%EB%8F%99%ED%99%94&quot;&gt;5-4. 가치 3: 프론트엔드 협업을 위한 Swagger 문서 자동화&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#6-http-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C-status-code-%EC%84%A4%EA%B3%84-%ED%91%9C%EC%A4%80&quot;&gt;HTTP 상태 코드 (Status Code) 설계 표준&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#6-1-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EC%88%AB%EC%9E%90%EC%9D%98-%EC%9D%98%EB%AF%B8&quot;&gt;6-1. 상태 코드의 정의와 숫자의 의미&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#6-2-crud-%EA%B8%B0%EB%8A%A5%EB%B3%84-%ED%91%9C%EC%A4%80-method--status-code-%EB%A7%A4%ED%95%91%ED%91%9C&quot;&gt;6-2. CRUD 기능별 표준 Method &amp;amp; Status Code 매핑표&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#6-3-apppost-status_code201-%EC%A0%81%EC%9A%A9%EB%B2%95&quot;&gt;6-3.&amp;nbsp;@app.post(..., status_code=201)&amp;nbsp;적용법&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#7-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC-error-handling--httpexception&quot;&gt;에러 처리 (Error Handling) &amp;amp; HTTPException&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#7-1-httpexception%EC%9D%98-%EC%97%AD%ED%95%A0%EA%B3%BC-%EB%AC%B8%EB%B2%95&quot;&gt;7-1.&amp;nbsp;HTTPException의 역할과 문법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#7-2-404-not-found-%EB%AA%85%EC%8B%9C%EC%A0%81-%EB%B0%98%ED%99%98-%ED%8C%A8%ED%84%B4&quot;&gt;7-2. 404 Not Found 명시적 반환 패턴&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#8-%EC%8B%A4%EC%A0%84-%EC%8B%A4%EC%8A%B5-%EC%9A%94%EC%B2%AD-%EC%9D%91%EB%8B%B5-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%A6%9D-post-hello&quot;&gt;실전 실습: 요청-응답 유효성 검증 (POST /hello)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#8-1-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD-%EB%B6%84%EC%84%9D-%EC%9D%B4%EB%A6%84-%EA%B2%80%EC%A6%9D--%EB%B9%88-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B6%84%EA%B8%B0&quot;&gt;8-1. 요구사항 분석 (이름 검증 &amp;amp; 빈 문자열 분기)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#8-2-%EC%8B%A4%EC%8A%B5-%EC%99%84%EC%84%B1-%EC%BD%94%EB%93%9C-%EB%B0%8F-%ED%95%B4%EC%84%A4&quot;&gt;8-2. 실습 완성 코드 및 해설&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-%EB%8C%80%EB%A7%9D%EC%9D%98-%EC%99%84%EC%84%B1-%EC%8B%A4%EB%AC%B4%ED%98%95-crud-api-%EC%99%84%EB%B2%BD-%EA%B5%AC%ED%98%84&quot;&gt;대망의 완성: 실무형 CRUD API 완벽 구현&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-1-dtodata-transfer-object-%EB%AA%A8%EB%8D%B8-%EB%B6%84%EB%A6%AC-%EC%84%A4%EA%B3%84&quot;&gt;9-1. DTO(Data Transfer Object) 모델 분리 설계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-2-create-%EC%83%81%ED%92%88-%EB%93%B1%EB%A1%9D-post-items-201-created&quot;&gt;9-2. [Create] 상품 등록 (POST /items, 201 Created)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-3-read-all-%EC%A0%84%EC%B2%B4-%EC%83%81%ED%92%88-%EC%A1%B0%ED%9A%8C-get-items-200-ok&quot;&gt;9-3. [Read All] 전체 상품 조회 (GET /items, 200 OK)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-4-read-one-%EB%8B%A8%EC%9D%BC-%EC%83%81%ED%92%88-%EC%83%81%EC%84%B8-%EC%A1%B0%ED%9A%8C-get-itemsitem_id-404-%EC%98%88%EC%99%B8&quot;&gt;9-4. [Read One] 단일 상품 상세 조회 (GET /items/{item_id}, 404 예외)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-5-update-%EC%83%81%ED%92%88-%EB%B6%80%EB%B6%84-%EC%88%98%EC%A0%95-patch-itemsitem_id-%EB%8F%85%EB%A6%BD-if%EB%AC%B8-%EC%A3%BC%EC%9D%98%EC%A0%90&quot;&gt;9-5. [Update] 상품 부분 수정 (PATCH /items/{item_id}, 독립 if문 주의점)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-6-delete-%EC%83%81%ED%92%88-%EC%82%AD%EC%A0%9C-delete-itemsitem_id-204-no-content&quot;&gt;9-6. [Delete] 상품 삭제 (DELETE /items/{item_id}, 204 No Content)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#10--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Type Hints (타입 힌트)의 본질과 모던 문법&lt;/h2&gt;
&lt;a id=&quot;user-content-1-type-hints-타입-힌트의-본질과-모던-문법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-type-hints-%ED%83%80%EC%9E%85-%ED%9E%8C%ED%8A%B8%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-%EB%AA%A8%EB%8D%98-%EB%AC%B8%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. Type Hints를 쓰는 4대 이유 (왜 FastAPI는 타입 힌트 위에 지어졌는가?)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-type-hints를-쓰는-4대-이유-왜-fastapi는-타입-힌트-위에-지어졌는가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-1-type-hints%EB%A5%BC-%EC%93%B0%EB%8A%94-4%EB%8C%80-%EC%9D%B4%EC%9C%A0-%EC%99%9C-fastapi%EB%8A%94-%ED%83%80%EC%9E%85-%ED%9E%8C%ED%8A%B8-%EC%9C%84%EC%97%90-%EC%A7%80%EC%96%B4%EC%A1%8C%EB%8A%94%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬은 원래 동적 타입(Dynamic Typing) 언어입니다. 즉, 변수에 어떤 값을 넣어도 에러가 나지 않는 자유로움이 있지만, 프로젝트 규모가 커지면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;이 함수에 문자열을 넣어야 하나? 숫자를 넣어야 하나?&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;헷갈리게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python 3.5+부터 도입된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Type Hints&lt;/b&gt;는 변수, 함수의 매개변수, 반환값에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;의도된 데이터 타입&quot;을 명시하는 문법&lt;/b&gt;입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kTVJy/dJMcahmcNUc/PjCxeZK7WNzwChgz1qoxU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kTVJy/dJMcahmcNUc/PjCxeZK7WNzwChgz1qoxU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kTVJy/dJMcahmcNUc/PjCxeZK7WNzwChgz1qoxU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkTVJy%2FdJMcahmcNUc%2FPjCxeZK7WNzwChgz1qoxU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;672&quot; height=&quot;257&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;Note&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;순수 Python과 FastAPI의 결정적 차이&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순수 파이썬 인터프리터는 타입 힌트를 작성해도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실행 자체를 강제하지 않습니다&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(힌트일 뿐 무시함).&lt;/li&gt;
&lt;li&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;FastAPI와 Pydantic은 이 타입 힌트를 런타임에 직접 읽어와서(Reflection)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터 유효성 검사 규칙 및 직렬화 규칙으로 자동 승격시킵니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. 기본 자료형과 유니온 타입 (|)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-2-기본-자료형과-유니온-타입-&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-2-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95%EA%B3%BC-%EC%9C%A0%EB%8B%88%EC%98%A8-%ED%83%80%EC%9E%85-&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수명 뒤에 콜론(:)을 붙이고 원하는 데이터 타입을 명시합니다.&lt;br /&gt;Python 3.10부터는&lt;span&gt;&amp;nbsp;&lt;/span&gt;Union[int, float]&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신 파이프 기호(|)를 사용하여 여러 타입을 허용할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 1. 단일 기본 타입 힌트
name: str = &quot;alex&quot;          # 문자열
price: int = 100            # 정수
ratio: float = 0.3          # 실수(부동소수점)
is_active: bool = True      # 불리언 (참/거짓)

# 2. 유니온 타입 (|): 둘 이상의 타입을 허용하고 싶을 때
# 정수 또는 실수를 모두 허용
score: int | float = 90
score = 85.5  # ✅ 둘 다 정상&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3. 함수의 인자 및 반환 타입 지정 (-&amp;gt;)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-3-함수의-인자-및-반환-타입-지정--&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-3-%ED%95%A8%EC%88%98%EC%9D%98-%EC%9D%B8%EC%9E%90-%EB%B0%8F-%EB%B0%98%ED%99%98-%ED%83%80%EC%9E%85-%EC%A7%80%EC%A0%95--&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 매개변수에는 콜론(:), 함수의 최종 반환값에는 화살표(-&amp;gt;)를 사용하여 타입을 명시합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;def add(n1: int, n2: int) -&amp;gt; int:
    &quot;&quot;&quot;정수 2개를 입력받아 정수 합을 반환하는 함수&quot;&quot;&quot;
    return n1 + n2

result = add(10, 20)
# IDE는 result가 int임을 즉시 알고 int 전용 메서드를 자동완성해 줍니다!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-4. 컬렉션 타입 (list[T],&lt;span&gt;&amp;nbsp;&lt;/span&gt;dict[K, V], 중첩 구조)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-4-컬렉션-타입-listt-dictk-v-중첩-구조&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-4-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%83%80%EC%9E%85-listt-dictk-v-%EC%A4%91%EC%B2%A9-%EA%B5%AC%EC%A1%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트나 딕셔너리 내부의 원소 타입까지 구체적으로 명시할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;vim&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 1. 문자열만 담긴 리스트
names: list[str] = [&quot;alex&quot;, &quot;bob&quot;, &quot;chris&quot;]

# 2. 정수, 실수, None을 모두 담을 수 있는 유연한 리스트
numbers: list[int | float | None] = [100, 90.5, 80, None]

# 3. 키는 str, 값은 int 또는 None을 갖는 딕셔너리
scores: dict[str, int | None] = {
    &quot;math&quot;: 90,
    &quot;eng&quot;: 100,
    &quot;history&quot;: None
}

# 4. 실무에서 가장 흔한 '딕셔너리들의 리스트' (중첩 구조)
users: list[dict[str, int | str]] = [
    {&quot;id&quot;: 1, &quot;name&quot;: &quot;alex&quot;},
    {&quot;id&quot;: 2, &quot;name&quot;: &quot;bob&quot;}
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-5. Optional 타입 (T | None = None)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-5-optional-타입-t--none--none&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#1-5-optional-%ED%83%80%EC%9E%85-t--none--none&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 데이터가 **&quot;있을 수도 있고, 없을 수도 있는 경우(None 허용)&quot;**에 사용합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;makefile&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 값이 안 들어오면 기본값으로 None을 가짐
name: str | None = None

# 나중에 문자열이 채워질 수 있음
name = &quot;alex&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Request Body와 데이터 직렬화 / 역직렬화&lt;/h2&gt;
&lt;a id=&quot;user-content-2-request-body와-데이터-직렬화--역직렬화&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#2-request-body%EC%99%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A7%81%EB%A0%AC%ED%99%94--%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. Path/Query vs Request Body의 결정적 차이&lt;/h3&gt;
&lt;/div&gt;
&amp;nbsp; &amp;nbsp;구분&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  Path Parameter&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  Query Parameter&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  Request Body (요청 본문)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;전달 위치&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;URL 경로 자체 (/items/3)&lt;/td&gt;
&lt;td&gt;URL 뒤 쿼리스트링 (?page=1)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;HTTP 요청 본문(Body) 내부&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;데이터 형식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;단순 문자열 / 숫자&lt;/td&gt;
&lt;td&gt;단순 Key-Value 문자열&lt;/td&gt;
&lt;td&gt;&lt;b&gt;복잡한 JSON 객체, 중첩 리스트 등 대용량 데이터&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;주 사용 목적&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;리소스 식별(Identify)&lt;/td&gt;
&lt;td&gt;필터링, 정렬, 검색 옵션&lt;/td&gt;
&lt;td&gt;&lt;b&gt;데이터 신규 등록(POST), 수정(PUT/PATCH)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;보안/노출&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;URL 및 서버 접근 로그에 그대로 노출&lt;/td&gt;
&lt;td&gt;URL 및 로그에 노출&lt;/td&gt;
&lt;td&gt;&lt;b&gt;URL에 노출되지 않아 비교적 안전&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. 직렬화(Serialization) vs 역직렬화(Deserialization) 개념 정리&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-직렬화serialization-vs-역직렬화deserialization-개념-정리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#2-2-%EC%A7%81%EB%A0%AC%ED%99%94serialization-vs-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94deserialization-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 통신에서 컴퓨터 메모리 속 객체와 네트워크 전송용 문자열은 서로 변환 과정을 거쳐야 합니다.&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;color: #1f2328;&quot;&gt;
&lt;pre id=&quot;code_1792736437124&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to render rich display

Parse error on line 10:
... CJ --&amp;gt;|1. HTTP 요청 (Request)&amp;lt;br/&amp;gt;JSON ➔
-----------------------^
Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'

For more information, see https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;coq&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;graph LR
    subgraph Client[&quot;  클라이언트 (Browser / App)&quot;]
        CJ[&quot;JSON 텍스트 포맷&amp;lt;br/&amp;gt;{'name': 'apple', 'price': 1000}&quot;]
    end

    subgraph Server[&quot;⚡ FastAPI 서버 (Python Runtime)&quot;]
        PO[&quot;Python 객체 (Pydantic Instance)&amp;lt;br/&amp;gt;item.name == 'apple'&quot;]
    end

    CJ --&amp;gt;|1. HTTP 요청 (Request)&amp;lt;br/&amp;gt;JSON ➔ Python : 역직렬화 (Deserialization)| PO
    PO --&amp;gt;|2. HTTP 응답 (Response)&amp;lt;br/&amp;gt;Python ➔ JSON : 직렬화 (Serialization)| CJ
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역직렬화 (Deserialization)&lt;/b&gt;:&lt;br /&gt;클라이언트가 보낸 HTTP 요청 본문의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JSON 문자열을 파이썬이 다룰 수 있는 객체/딕셔너리로 조립&lt;/b&gt;하는 과정.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;직렬화 (Serialization)&lt;/b&gt;:&lt;br /&gt;서버 내부의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;파이썬 데이터(Pydantic 모델, 딕셔너리, 리스트)를 전송 가능한 JSON 문자열로 변환&lt;/b&gt;하여 HTTP 응답 본문에 싣는 과정.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Pydantic: 데이터 검증과 파싱의 핵심 엔진&lt;/h2&gt;
&lt;a id=&quot;user-content-3-pydantic-데이터-검증과-파싱의-핵심-엔진&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-pydantic-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B2%80%EC%A6%9D%EA%B3%BC-%ED%8C%8C%EC%8B%B1%EC%9D%98-%ED%95%B5%EC%8B%AC-%EC%97%94%EC%A7%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. FastAPI의 2대 지주 (Starlette vs Pydantic)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1-fastapi의-2대-지주-starlette-vs-pydantic&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-1-fastapi%EC%9D%98-2%EB%8C%80-%EC%A7%80%EC%A3%BC-starlette-vs-pydantic&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI는 바퀴를 다시 발명하지 않고, 세상에서 가장 뛰어난 두 오픈소스를 결합하여 탄생했습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oqRw3/dJMcagAGfBR/rbcViUijMkNQ07LIH818NK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oqRw3/dJMcagAGfBR/rbcViUijMkNQ07LIH818NK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oqRw3/dJMcagAGfBR/rbcViUijMkNQ07LIH818NK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoqRw3%2FdJMcagAGfBR%2FrbcViUijMkNQ07LIH818NK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;279&quot; height=&quot;240&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;BaseModel&lt;span&gt;&amp;nbsp;&lt;/span&gt;정의와 자동 타입 변환 원리&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2-basemodel-정의와-자동-타입-변환-원리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-2-basemodel-%EC%A0%95%EC%9D%98%EC%99%80-%EC%9E%90%EB%8F%99-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98-%EC%9B%90%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pydantic의 모든 데이터 모델은 **BaseModel**을 상속받아 클래스로 정의합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: int&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;타입 강제 변환(Type Coercion)&lt;/b&gt;:&lt;br /&gt;만약 클라이언트가&lt;span&gt;&amp;nbsp;&lt;/span&gt;{&quot;name&quot;: &quot;apple&quot;, &quot;price&quot;: &quot;1000&quot;}&lt;span&gt;&amp;nbsp;&lt;/span&gt;처럼 숫자를 문자열로 보냈더라도, Pydantic은&lt;span&gt;&amp;nbsp;&lt;/span&gt;int로 변환 가능하면 자동으로 정수&lt;span&gt;&amp;nbsp;&lt;/span&gt;1000으로 파싱해 줍니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타입 검증 실패&lt;/b&gt;:&lt;br /&gt;만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;{&quot;name&quot;: &quot;apple&quot;, &quot;price&quot;: &quot;cheap&quot;}&lt;span&gt;&amp;nbsp;&lt;/span&gt;처럼 정수로 바꿀 수 없는 값을 넣으면 Pydantic은 즉시 에러를 발생시킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-3. Pydantic 핵심 메서드 4선 (model_dump,&lt;span&gt;&amp;nbsp;&lt;/span&gt;model_dump_json,&lt;span&gt;&amp;nbsp;&lt;/span&gt;model_validate)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-3-pydantic-핵심-메서드-4선-model_dump-model_dump_json-model_validate&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-3-pydantic-%ED%95%B5%EC%8B%AC-%EB%A9%94%EC%84%9C%EB%93%9C-4%EC%84%A0-model_dump-model_dump_json-model_validate&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pydantic v2 기준, 실무에서 매일 사용하는 필수 메서드들입니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: int

# 1. 인스턴스 생성
item = Item(name=&quot;apple&quot;, price=1000)
print(item)  # 출력: name='apple' price=1000

# 2. model_dump(): Pydantic 인스턴스를 순수 파이썬 dict로 변환
dict_data = item.model_dump()
print(dict_data)  # {'name': 'apple', 'price': 1000}

# 3. model_dump_json(): Pydantic 인스턴스를 JSON 문자열로 변환
json_str = item.model_dump_json()
print(json_str)   # '{&quot;name&quot;:&quot;apple&quot;,&quot;price&quot;:1000}'

# 4. model_validate(): 기존 dict 데이터를 검증하여 Pydantic 인스턴스로 복원
raw_dict = {&quot;name&quot;: &quot;banana&quot;, &quot;price&quot;: 2000}
banana_item = Item.model_validate(raw_dict)
print(banana_item.name)  # &quot;banana&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Field(...)를 활용한 정밀한 유효성 검사 (min_length,&lt;span&gt;&amp;nbsp;&lt;/span&gt;ge,&lt;span&gt;&amp;nbsp;&lt;/span&gt;le)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-4-field를-활용한-정밀한-유효성-검사-min_length-ge-le&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#3-4-field%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%A0%95%EB%B0%80%ED%95%9C-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC-min_length-ge-le&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순 타입 체크를 넘어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;글자수 최소/최대 제한, 숫자의 범위 제한&lt;/b&gt;을 걸 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from pydantic import BaseModel, Field

class Item(BaseModel):
    # 이름은 필수(...)이며 최소 2글자 이상
    name: str = Field(..., min_length=2, description=&quot;상품 이름 (2자 이상)&quot;)
    
    # 가격은 필수(...)이며 0원 이상 (음수 가격 방지)
    price: int = Field(..., ge=0, description=&quot;상품 가격 (0원 이상)&quot;)

# ❌ 검증 실패 예시:
# Item(name=&quot;a&quot;, price=-10) 
# -&amp;gt; 1) name 길이가 2 미만이므로 에러!
# -&amp;gt; 2) price가 0보다 작으므로 에러!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. FastAPI에서 Request Body 다루기&lt;/h2&gt;
&lt;a id=&quot;user-content-4-fastapi에서-request-body-다루기&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-fastapi%EC%97%90%EC%84%9C-request-body-%EB%8B%A4%EB%A3%A8%EA%B8%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. Pydantic 모델을 타입 힌트로 전달하여 인스턴스 자동 주입받기&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-pydantic-모델을-타입-힌트로-전달하여-인스턴스-자동-주입받기&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-1-pydantic-%EB%AA%A8%EB%8D%B8%EC%9D%84-%ED%83%80%EC%9E%85-%ED%9E%8C%ED%8A%B8%EB%A1%9C-%EC%A0%84%EB%8B%AC%ED%95%98%EC%97%AC-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EC%9E%90%EB%8F%99-%EC%A3%BC%EC%9E%85%EB%B0%9B%EA%B8%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI 엔드포인트 함수의 매개변수에&lt;span&gt;&amp;nbsp;&lt;/span&gt;BaseModel을 상속받은 클래스를 타입으로 적어주면 끝납니다!&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class CreateItemRequest(BaseModel):
    name: str
    price: int

@app.post(&quot;/items&quot;, summary=&quot;새로운 상품 등록 API&quot;)
def create_item(body: CreateItemRequest):
    # FastAPI가 내부적으로 CreateItemRequest(**request_json) 인스턴스를 만들어 주입함!
    return body&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. 점(.) 표기법을 통한 안전하고 편리한 데이터 접근&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-점-표기법을-통한-안전하고-편리한-데이터-접근&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-2-%EC%A0%90-%ED%91%9C%EA%B8%B0%EB%B2%95%EC%9D%84-%ED%86%B5%ED%95%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B3%A0-%ED%8E%B8%EB%A6%AC%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%91%EA%B7%BC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딕셔너리의&lt;span&gt;&amp;nbsp;&lt;/span&gt;body[&quot;name&quot;]&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식은 오타가 나도 실행 전까지 알기 어렵습니다.&lt;br /&gt;반면 Pydantic 모델은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;점(.) 표기법&lt;/b&gt;을 지원하므로 오타가 나면 IDE가 즉시 경고를 띄워줍니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.post(&quot;/items&quot;)
def create_item_handler(body: CreateItemRequest):
    # 안전하고 직관적인 점 표기법
    new_item = {
        &quot;id&quot;: 1,
        &quot;name&quot;: body.name,   # ✅ 자동완성 지원
        &quot;price&quot;: body.price  # ✅ 자동완성 지원
    }
    return new_item&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3. 기본값(Default)과 선택 필드(Optional Field) 설계&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-기본값default과-선택-필드optional-field-설계&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-3-%EA%B8%B0%EB%B3%B8%EA%B0%92default%EA%B3%BC-%EC%84%A0%ED%83%9D-%ED%95%84%EB%93%9Coptional-field-%EC%84%A4%EA%B3%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 특정 필드를 보내지 않아도 오류가 나지 않도록 기본값을 부여할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;class Item(BaseModel):
    name: str                             # 필수값 (기본값 없음)
    price: int                            # 필수값 (기본값 없음)
    description: str | None = None        # 선택값 (생략 시 None)
    is_active: bool = True                # 선택값 (생략 시 True)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-4. 계층형 JSON을 처리하는 중첩 모델 (Nested Model)&lt;/h3&gt;
&lt;a id=&quot;user-content-4-4-계층형-json을-처리하는-중첩-모델-nested-model&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#4-4-%EA%B3%84%EC%B8%B5%ED%98%95-json%EC%9D%84-%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94-%EC%A4%91%EC%B2%A9-%EB%AA%A8%EB%8D%B8-nested-model&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 자주 쓰이는 복잡한 계층형 JSON 구조도 Pydantic 클래스 안에 다른 Pydantic 클래스를 넣으면 완벽하게 검증됩니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;class User(BaseModel):
    id: int
    name: str

class Order(BaseModel):
    user: User      # User 모델을 중첩 필드로 포함
    amount: int

@app.post(&quot;/orders&quot;)
def create_order(order: Order):
    # 클라이언트 전송 JSON 형태:
    # {
    #   &quot;user&quot;: { &quot;id&quot;: 1, &quot;name&quot;: &quot;alex&quot; },
    #   &quot;amount&quot;: 50000
    # }
    print(order.user.name)  # &quot;alex&quot;
    return order&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Response Model (응답 모델)의 3대 핵심 가치&lt;/h2&gt;
&lt;a id=&quot;user-content-5-response-model-응답-모델의-3대-핵심-가치&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-response-model-%EC%9D%91%EB%8B%B5-%EB%AA%A8%EB%8D%B8%EC%9D%98-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%EA%B0%80%EC%B9%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데코레이터에 **response_model=Pydantic클래스**를 지정하면 서버가 클라이언트에게 내보내는 응답 데이터를 엄격하게 통제할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.post(&quot;/items&quot;, response_model=ItemResponse)
def create_item(item: ItemCreateRequest):
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;722&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZokd2/dJMcagU13A6/zBNm4B8Ts9js5aM1PILkhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZokd2/dJMcagU13A6/zBNm4B8Ts9js5aM1PILkhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZokd2/dJMcagU13A6/zBNm4B8Ts9js5aM1PILkhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZokd2%2FdJMcagU13A6%2FzBNm4B8Ts9js5aM1PILkhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;368&quot; height=&quot;230&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. 왜 응답 모델을 별도로 지정해야 하는가?&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-왜-응답-모델을-별도로-지정해야-하는가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-1-%EC%99%9C-%EC%9D%91%EB%8B%B5-%EB%AA%A8%EB%8D%B8%EC%9D%84-%EB%B3%84%EB%8F%84%EB%A1%9C-%EC%A7%80%EC%A0%95%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스(DB)에서 데이터를 꺼내오면&lt;span&gt;&amp;nbsp;&lt;/span&gt;password,&lt;span&gt;&amp;nbsp;&lt;/span&gt;created_at,&lt;span&gt;&amp;nbsp;&lt;/span&gt;internal_score&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 클라이언트에게 절대 노출되면 안 되는 필드들이 함께 딸려옵니다.&lt;/li&gt;
&lt;li&gt;만약 이를 그대로&lt;span&gt;&amp;nbsp;&lt;/span&gt;return하면 **심각한 보안 사고(개인정보 노출)**로 이어집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. 가치 2: 민감정보 마스킹 및 불필요한 필드 자동 제거 (Filtering)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-가치-2-민감정보-마스킹-및-불필요한-필드-자동-제거-filtering&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-2-%EA%B0%80%EC%B9%98-2-%EB%AF%BC%EA%B0%90%EC%A0%95%EB%B3%B4-%EB%A7%88%EC%8A%A4%ED%82%B9-%EB%B0%8F-%EB%B6%88%ED%95%84%EC%9A%94%ED%95%9C-%ED%95%84%EB%93%9C-%EC%9E%90%EB%8F%99-%EC%A0%9C%EA%B1%B0-filtering&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;objectivec&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 클라이언트에게 응답할 모델 정의 (비밀번호 없음!)
class UserResponse(BaseModel):
    id: int
    username: str

@app.get(&quot;/users/{user_id}&quot;, response_model=UserResponse)
def get_user(user_id: int):
    # DB에서 조회한 원본 데이터 (민감한 password 포함)
    db_user = {
        &quot;id&quot;: 1,
        &quot;username&quot;: &quot;alex&quot;,
        &quot;password&quot;: &quot;super-secret-password-1234&quot;,  #   위험 필드!
        &quot;internal_memo&quot;: &quot;블랙리스트 유저 아님&quot;
    }
    
    # response_model=UserResponse 덕분에 FastAPI가 password를 자동으로 버려줌!
    return db_user
    # 클라이언트가 최종 수신하는 JSON:
    # { &quot;id&quot;: 1, &quot;username&quot;: &quot;alex&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #8250df;&quot; data-ke-size=&quot;size16&quot;&gt;Important&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;핵심 요약&lt;/b&gt;:&lt;br /&gt;함수 내부에서 아무리 많은 필드가 담긴 딕셔너리를 반환하더라도,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;response_model에 선언되지 않은 필드는 FastAPI가 깨끗하게 걸러내고(제거하고) 안전한 데이터만 반환&lt;/b&gt;합니다!&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 가치 3: 프론트엔드 협업을 위한 Swagger 문서 자동화&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3-가치-3-프론트엔드-협업을-위한-swagger-문서-자동화&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#5-3-%EA%B0%80%EC%B9%98-3-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%98%91%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%9C-swagger-%EB%AC%B8%EC%84%9C-%EC%9E%90%EB%8F%99%ED%99%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;response_model=list[ItemResponse]를 걸어두면, Swagger UI 문서에 이 API가 어떤 구조의 JSON 리스트를 돌려주는지(키 이름, 데이터 타입)가 시각적으로 완벽하게 표시됩니다.&lt;/li&gt;
&lt;li&gt;프론트엔드 개발자는 백엔드 코드를 보지 않고도 문서를 보고 바로 화면을 연동할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. HTTP 상태 코드 (Status Code) 설계 표준&lt;/h2&gt;
&lt;a id=&quot;user-content-6-http-상태-코드-status-code-설계-표준&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#6-http-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C-status-code-%EC%84%A4%EA%B3%84-%ED%91%9C%EC%A4%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. 상태 코드의 정의와 숫자의 의미&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-상태-코드의-정의와-숫자의-의미&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#6-1-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EC%88%AB%EC%9E%90%EC%9D%98-%EC%9D%98%EB%AF%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 상태 코드는 클라이언트의 요청에 대해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서버가 처리 결과를 3자리 숫자로 명확하게 알려주는 전 세계 공통 약속&lt;/b&gt;입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2xx: 성공 (Success)&lt;/li&gt;
&lt;li&gt;4xx: 클라이언트 요청 오류 (Client Error - 잘못된 파라미터, 권한 없음 등)&lt;/li&gt;
&lt;li&gt;5xx: 서버 내부 오류 (Server Error - 코드 버그, DB 다운 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2. CRUD 기능별 표준 Method &amp;amp; Status Code 매핑표&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-crud-기능별-표준-method--status-code-매핑표&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#6-2-crud-%EA%B8%B0%EB%8A%A5%EB%B3%84-%ED%91%9C%EC%A4%80-method--status-code-%EB%A7%A4%ED%95%91%ED%91%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI 개발 시 무조건 준수해야 하는 REST API 상태 코드 표준 매핑입니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&amp;nbsp; &amp;nbsp; CRUD 기능&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; HTTP Method&amp;nbsp; &amp;nbsp; &amp;nbsp;표준 상태 코드&amp;nbsp; &amp;nbsp; 상태 코드 이름&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 17.5581%;&quot;&gt;&lt;b&gt;생성 (Create)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;&lt;b&gt;POST&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4418%;&quot;&gt;&lt;b&gt;201&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.0233%;&quot;&gt;&lt;b&gt;Created&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.7907%;&quot;&gt;새로운 리소스가 성공적으로 생성됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 17.5581%;&quot;&gt;&lt;b&gt;전체 조회 (Read)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;&lt;b&gt;GET&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4418%;&quot;&gt;&lt;b&gt;200&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.0233%;&quot;&gt;&lt;b&gt;OK&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.7907%;&quot;&gt;요청이 성공적으로 처리됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 17.5581%;&quot;&gt;&lt;b&gt;단일 조회 (Read)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;&lt;b&gt;GET&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4418%;&quot;&gt;&lt;b&gt;200&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.0233%;&quot;&gt;&lt;b&gt;OK&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.7907%;&quot;&gt;단일 데이터 조회 성공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 17.5581%;&quot;&gt;&lt;b&gt;수정 (Update)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;&lt;b&gt;PUT / PATCH&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4418%;&quot;&gt;&lt;b&gt;200&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.0233%;&quot;&gt;&lt;b&gt;OK&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.7907%;&quot;&gt;리소스 수정 성공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 17.5581%;&quot;&gt;&lt;b&gt;삭제 (Delete)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;&lt;b&gt;DELETE&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4418%;&quot;&gt;&lt;b&gt;204&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.0233%;&quot;&gt;&lt;b&gt;No Content&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.7907%;&quot;&gt;삭제 성공 (본문에 반환할 데이터가 없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 17.5581%;&quot;&gt;&lt;b&gt;자원 없음&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;모든 Method&lt;/td&gt;
&lt;td style=&quot;width: 12.4418%;&quot;&gt;&lt;b&gt;404&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.0233%;&quot;&gt;&lt;b&gt;Not Found&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.7907%;&quot;&gt;요청한 ID의 리소스가 존재하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 17.5581%;&quot;&gt;&lt;b&gt;데이터 검증 실패&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;모든 Method&lt;/td&gt;
&lt;td style=&quot;width: 12.4418%;&quot;&gt;&lt;b&gt;422&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.0233%;&quot;&gt;&lt;b&gt;Unprocessable Entity&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.7907%;&quot;&gt;Pydantic 타입/길이 검증 규칙 위반&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;@app.post(..., status_code=201)&lt;span&gt;&amp;nbsp;&lt;/span&gt;적용법&lt;/h3&gt;
&lt;a id=&quot;user-content-6-3-apppost-status_code201-적용법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#6-3-apppost-status_code201-%EC%A0%81%EC%9A%A9%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI는 기본 성공 상태 코드가&lt;span&gt;&amp;nbsp;&lt;/span&gt;200이므로, 신규 생성(POST)이나 삭제(DELETE)는 데코레이터에서 상태 코드를 명시해야 합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 신규 상품 생성 시 201 Created 지정
@app.post(&quot;/items&quot;, response_model=ItemResponse, status_code=201)
def create_item(body: ItemCreateRequest):
    ...

# 상품 삭제 성공 시 204 No Content 지정
@app.delete(&quot;/items/{item_id}&quot;, status_code=204)
def delete_item(item_id: int):
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 에러 처리 (Error Handling) &amp;amp; HTTPException&lt;/h2&gt;
&lt;a id=&quot;user-content-7-에러-처리-error-handling--httpexception&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#7-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC-error-handling--httpexception&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;HTTPException의 역할과 문법&lt;/h3&gt;
&lt;a id=&quot;user-content-7-1-httpexception의-역할과-문법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#7-1-httpexception%EC%9D%98-%EC%97%AD%ED%95%A0%EA%B3%BC-%EB%AC%B8%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 로직 수행 중 비정상적인 상황(예: 찾는 상품이 없음)을 마주쳤을 때, 서버 프로세스를 다운시키지 않고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;클라이언트가 납득할 수 있는 정돈된 HTTP 에러 응답을 던지는 도구&lt;/b&gt;입니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;properties&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI, HTTPException

app = FastAPI()

# 에러 발생 시 즉시 코드 실행 중단 및 404 응답 반환
raise HTTPException(
    status_code=404,
    detail=&quot;요청하신 상품을 찾을 수 없습니다.&quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 수신 JSON:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;json&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;{
  &quot;detail&quot;: &quot;요청하신 상품을 찾을 수 없습니다.&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 실전 실습: 요청-응답 유효성 검증 (POST /hello)&lt;/h2&gt;
&lt;a id=&quot;user-content-8-실전-실습-요청-응답-유효성-검증-post-hello&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#8-%EC%8B%A4%EC%A0%84-%EC%8B%A4%EC%8A%B5-%EC%9A%94%EC%B2%AD-%EC%9D%91%EB%8B%B5-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%A6%9D-post-hello&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제 요구사항&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;엔드포인트:&lt;span&gt;&amp;nbsp;&lt;/span&gt;POST /hello&lt;/li&gt;
&lt;li&gt;요청 본문 형식:&lt;span&gt;&amp;nbsp;&lt;/span&gt;{&quot;name&quot;: &quot;xxx&quot;}&lt;span&gt;&amp;nbsp;&lt;/span&gt;검증&lt;/li&gt;
&lt;li&gt;응답 형식:&lt;span&gt;&amp;nbsp;&lt;/span&gt;{&quot;message&quot;: &quot;안녕하세요, xxx님!&quot;}&lt;span&gt;&amp;nbsp;&lt;/span&gt;형식 검증&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특수 조건&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;name이 빈 문자열(&quot;&quot;)이면&lt;span&gt;&amp;nbsp;&lt;/span&gt;{&quot;message&quot;: &quot;이름을 입력하세요&quot;}&lt;span&gt;&amp;nbsp;&lt;/span&gt;반환&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;완성 코드:&lt;/h4&gt;
&lt;a id=&quot;user-content-완성-코드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#%EC%99%84%EC%84%B1-%EC%BD%94%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# 1. 요청 모델 정의
class HelloRequest(BaseModel):
    name: str

# 2. 응답 모델 정의
class HelloResponse(BaseModel):
    message: str

@app.post(&quot;/hello&quot;, response_model=HelloResponse)
def say_hello(body: HelloRequest):
    # 빈 문자열 검증 (공백 제거 후 체크)
    if not body.name.strip():
        return HelloResponse(message=&quot;이름을 입력하세요&quot;)
    
    return HelloResponse(message=f&quot;안녕하세요, {body.name}님!&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 대망의 완성: 실무형 CRUD API 완벽 구현&lt;/h2&gt;
&lt;a id=&quot;user-content-9-대망의-완성-실무형-crud-api-완벽-구현&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-%EB%8C%80%EB%A7%9D%EC%9D%98-%EC%99%84%EC%84%B1-%EC%8B%A4%EB%AC%B4%ED%98%95-crud-api-%EC%99%84%EB%B2%BD-%EA%B5%AC%ED%98%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬라이드 24~32페이지의 모든 내용을 종합한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인메모리 상품 관리 풀 CRUD API&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;완성 소스코드입니다.&lt;/p&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-1. DTO(Data Transfer Object) 모델 분리 설계&lt;/h3&gt;
&lt;a id=&quot;user-content-9-1-dtodata-transfer-object-모델-분리-설계&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-1-dtodata-transfer-object-%EB%AA%A8%EB%8D%B8-%EB%B6%84%EB%A6%AC-%EC%84%A4%EA%B3%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI, HTTPException, Path, Body
from pydantic import BaseModel

app = FastAPI(title=&quot;상품 관리 CRUD API&quot;, version=&quot;1.0.0&quot;)

# 1. 등록용 요청 모델 (id는 서버가 생성하므로 받지 않음)
class ItemCreateRequest(BaseModel):
    name: str
    price: int

# 2. 부분 수정용 요청 모델 (수정하고 싶은 필드만 보낼 수 있도록 None 허용)
class ItemUpdateRequest(BaseModel):
    name: str | None = None
    price: int | None = None

# 3. 클라이언트 반환용 응답 모델
class ItemResponse(BaseModel):
    id: int
    name: str
    price: int

# 인메모리 데이터 저장소
ITEMS = [
    {&quot;id&quot;: 1, &quot;name&quot;: &quot;apple&quot;, &quot;price&quot;: 1000},
    {&quot;id&quot;: 2, &quot;name&quot;: &quot;banana&quot;, &quot;price&quot;: 2000},
    {&quot;id&quot;: 3, &quot;name&quot;: &quot;cherry&quot;, &quot;price&quot;: 3000},
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-2. [Create] 상품 등록 (POST /items, 201 Created)&lt;/h3&gt;
&lt;a id=&quot;user-content-9-2-create-상품-등록-post-items-201-created&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-2-create-%EC%83%81%ED%92%88-%EB%93%B1%EB%A1%9D-post-items-201-created&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;haxe&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.post(&quot;/items&quot;, response_model=ItemResponse, status_code=201, summary=&quot;상품 등록 API&quot;)
def create_item(body: ItemCreateRequest):
    new_item = {
        &quot;id&quot;: len(ITEMS) + 1,
        &quot;name&quot;: body.name,
        &quot;price&quot;: body.price,
    }
    ITEMS.append(new_item)
    return new_item&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-3. [Read All] 전체 상품 조회 (GET /items, 200 OK)&lt;/h3&gt;
&lt;a id=&quot;user-content-9-3-read-all-전체-상품-조회-get-items-200-ok&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-3-read-all-%EC%A0%84%EC%B2%B4-%EC%83%81%ED%92%88-%EC%A1%B0%ED%9A%8C-get-items-200-ok&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.get(&quot;/items&quot;, response_model=list[ItemResponse], summary=&quot;상품 전체 조회 API&quot;)
def list_items():
    return ITEMS&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-4. [Read One] 단일 상품 상세 조회 (GET /items/{item_id}, 404 예외)&lt;/h3&gt;
&lt;a id=&quot;user-content-9-4-read-one-단일-상품-상세-조회-get-itemsitem_id-404-예외&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-4-read-one-%EB%8B%A8%EC%9D%BC-%EC%83%81%ED%92%88-%EC%83%81%EC%84%B8-%EC%A1%B0%ED%9A%8C-get-itemsitem_id-404-%EC%98%88%EC%99%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.get(&quot;/items/{item_id}&quot;, response_model=ItemResponse, summary=&quot;단일 상품 상세 조회 API&quot;)
def get_item(item_id: int = Path(..., ge=1, description=&quot;조회할 상품 ID&quot;)):
    for item in ITEMS:
        if item[&quot;id&quot;] == item_id:
            return item
    
    # 끝까지 못 찾으면 404 에러 발생
    raise HTTPException(status_code=404, detail=&quot;상품을 찾을 수 없습니다.&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-5. [Update] 상품 부분 수정 (PATCH /items/{item_id}, 독립 if문 주의점)&lt;/h3&gt;
&lt;a id=&quot;user-content-9-5-update-상품-부분-수정-patch-itemsitem_id-독립-if문-주의점&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-5-update-%EC%83%81%ED%92%88-%EB%B6%80%EB%B6%84-%EC%88%98%EC%A0%95-patch-itemsitem_id-%EB%8F%85%EB%A6%BD-if%EB%AC%B8-%EC%A3%BC%EC%9D%98%EC%A0%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #9a6700;&quot; data-ke-size=&quot;size16&quot;&gt;Warning&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;수정 로직 작성 시 치명적 주의점&lt;/b&gt;:&lt;br /&gt;if body.name is not None:&lt;span&gt;&amp;nbsp;&lt;/span&gt;뒤에&lt;span&gt;&amp;nbsp;&lt;/span&gt;elif body.price is not None:&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 쓰면 안 됩니다!&lt;br /&gt;elif를 쓰면 클라이언트가 이름과 가격을 둘 다 수정하려고 보냈을 때 이름만 바뀌고 가격은 무시됩니다.&lt;br /&gt;반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;독립된 개별&lt;span&gt;&amp;nbsp;&lt;/span&gt;if문&lt;/b&gt;으로 각각 검사해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.patch(&quot;/items/{item_id}&quot;, response_model=ItemResponse, summary=&quot;상품 부분 수정 API&quot;)
def patch_item(
    item_id: int = Path(..., ge=1),
    body: ItemUpdateRequest = Body(...)
):
    for stored_item in ITEMS:
        if stored_item[&quot;id&quot;] == item_id:
            # 1. 이름이 전달되었으면 이름 갱신
            if body.name is not None:
                stored_item[&quot;name&quot;] = body.name
            
            # 2. 가격이 전달되었으면 가격 갱신 (독립적인 if문!)
            if body.price is not None:
                stored_item[&quot;price&quot;] = body.price
                
            return stored_item

    # 대상 상품이 없으면 404 에러
    raise HTTPException(status_code=404, detail=&quot;상품을 찾을 수 없습니다.&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-6. [Delete] 상품 삭제 (DELETE /items/{item_id}, 204 No Content)&lt;/h3&gt;
&lt;a id=&quot;user-content-9-6-delete-상품-삭제-delete-itemsitem_id-204-no-content&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#9-6-delete-%EC%83%81%ED%92%88-%EC%82%AD%EC%A0%9C-delete-itemsitem_id-204-no-content&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.delete(&quot;/items/{item_id}&quot;, status_code=204, summary=&quot;상품 삭제 API&quot;)
def delete_item(item_id: int = Path(..., ge=1)):
    for item in ITEMS:
        if item[&quot;id&quot;] == item_id:
            ITEMS.remove(item)
            # ⚠️ return을 명시하지 않으면 아래 404 코드로 흘러내려가므로 즉시 조기 반환!
            return

    raise HTTPException(status_code=404, detail=&quot;상품을 찾을 수 없습니다.&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-10--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day2/fastapi-pydantic-crud-model-serving-note.md#10--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│               FastAPI &amp;amp; Pydantic &amp;amp; CRUD 핵심 치트시트                  │
├──────────────────────────────┬─────────────────────────────────────────┤
│ 문법 / 개념                  │ 핵심 요약 및 사용 공식                  │
├──────────────────────────────┼─────────────────────────────────────────┤
│ val: int | None = None       │ None을 허용하는 선택적 타입 힌트        │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Request Body                 │ JSON으로 들어오는 대용량 요청 본문      │
├──────────────────────────────┼─────────────────────────────────────────┤
│ 직렬화 (Serialization)       │ Python 객체 ➔ JSON 문자열               │
├──────────────────────────────┼─────────────────────────────────────────┤
│ 역직렬화 (Deserialization)   │ JSON 문자열 ➔ Python 객체               │
├──────────────────────────────┼─────────────────────────────────────────┤
│ class Item(BaseModel):       │ Pydantic 기반 입출력 데이터 검증 모델   │
├──────────────────────────────┼─────────────────────────────────────────┤
│ model.model_dump()           │ Pydantic 모델을 순수 Python dict로 변환 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Field(..., min_length=2)     │ Pydantic 필드 상세 유효성 검사 규칙 설정│
├──────────────────────────────┼─────────────────────────────────────────┤
│ body: CreateItemRequest      │ Request Body를 Pydantic 객체로 자동 주입│
├──────────────────────────────┼─────────────────────────────────────────┤
│ response_model=ItemResponse  │ 응답 검증 + 민감 필드 자동 필터링(제거) │
├──────────────────────────────┼─────────────────────────────────────────┤
│ status_code=201              │ 리소스 신규 생성 성공 (POST 표준)       │
├──────────────────────────────┼─────────────────────────────────────────┤
│ status_code=204              │ 리소스 삭제 성공, 본문 없음 (DELETE 표준)│
├──────────────────────────────┼─────────────────────────────────────────┤
│ 422 Unprocessable Entity     │ Pydantic 타입 검증 실패 시 자동 반환    │
├──────────────────────────────┼─────────────────────────────────────────┤
│ raise HTTPException(404, ...)│ 리소스가 없을 때 던지는 명시적 에러 응답│
├──────────────────────────────┼─────────────────────────────────────────┤
│ PATCH 부분 수정 주의점       │ name과 price 검증 시 elif 금지!         │
│                              │ 각각 독립된 if문으로 처리할 것          │
└──────────────────────────────┴─────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/35</guid>
      <comments>https://write31991.tistory.com/35#entry35comment</comments>
      <pubDate>Fri, 23 Oct 2026 15:25:14 +0900</pubDate>
    </item>
    <item>
      <title>FastAPI 1일차</title>
      <link>https://write31991.tistory.com/34</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-has-sidebar=&quot;true&quot; data-component=&quot;SplitPageLayout&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div data-is-hidden-narrow=&quot;false&quot; data-component=&quot;SplitPageLayout.Content&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div id=&quot;repos-split-pane-content&quot; data-selector=&quot;repos-split-pane-content&quot;&gt;
&lt;div data-hpc=&quot;true&quot;&gt;
&lt;div&gt;
&lt;h1&gt;⚡ FastAPI 기초 &amp;amp; AI 모델 서빙 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content--fastapi-기초--ai-모델-서빙-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#-fastapi-%EA%B8%B0%EC%B4%88--ai-%EB%AA%A8%EB%8D%B8-%EC%84%9C%EB%B9%99-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python 기반 고성능 웹 프레임워크&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;FastAPI의 핵심 철학과 아키텍처&lt;/b&gt;부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가상환경 격리(.venv)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 통신 원리(외부 통신 vs localhost 내부 루프백)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Python 객체의 JSON 자동 직렬화&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데코레이터(@app.get)의 역할&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;대화형 API 문서(Swagger UI &amp;amp; ReDoc)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Path Parameter vs Query Parameter의 명확한 구분과 유효성 검증(Path, Query)&lt;/b&gt;, 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;라우팅 충돌 방지 원칙과 종합 이커머스 API 실전 구현&lt;/b&gt;까지 총정리한 실무 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#1-fastapi%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EC%9B%B9-api-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC&quot;&gt;FastAPI란 무엇인가? (고성능 웹 API 프레임워크)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#1-1-fast%EC%9D%98-2%EA%B0%80%EC%A7%80-%EB%B3%B8%EC%A7%88-%EC%B2%98%EB%A6%AC-%EC%86%8D%EB%8F%84--%EA%B0%9C%EB%B0%9C-%EC%86%8D%EB%8F%84&quot;&gt;1-1. 'Fast'의 2가지 본질 (처리 속도 &amp;amp; 개발 속도)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#1-2-fastapi%EC%9D%98-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%ED%8A%B9%EC%A7%95&quot;&gt;1-2. FastAPI의 3대 핵심 특징&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#1-3-python-%EC%9B%B9-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-3%EB%8C%80%EC%9E%A5-%EB%B9%84%EA%B5%90-fastapi-vs-django-vs-flask&quot;&gt;1-3. Python 웹 프레임워크 3대장 비교 (FastAPI vs Django vs Flask)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%EA%B3%BC-%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BDvenv%EC%9D%98-%EB%B3%B8%EC%A7%88&quot;&gt;개발 환경 구축과 가상환경(.venv)의 본질&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-1-%EC%99%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A7%88%EB%8B%A4-%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD%EC%9D%84-%EB%B6%84%EB%A6%AC%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80&quot;&gt;2-1. 왜 프로젝트마다 가상환경을 분리해야 하는가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-2-os%EB%B3%84-%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD-%EC%83%9D%EC%84%B1-%EB%B0%8F-%ED%99%9C%EC%84%B1%ED%99%94-%EB%AA%85%EB%A0%B9%EC%96%B4-macos-vs-windows&quot;&gt;2-2. OS별 가상환경 생성 및 활성화 명령어 (macOS vs Windows)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-3-%ED%99%9C%EC%84%B1%ED%99%94-%EC%A0%84%ED%9B%84%EC%9D%98-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9D%B8%ED%84%B0%ED%94%84%EB%A6%AC%ED%84%B0-%EA%B2%BD%EB%A1%9C-%EB%B3%80%ED%99%94&quot;&gt;2-3. 활성화 전후의 파이썬 인터프리터 경로 변화&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-4-fastapi-%ED%91%9C%EC%A4%80-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EC%B9%98-pip-install-fastapistandard&quot;&gt;2-4. FastAPI 표준 패키지 설치 (pip install &quot;fastapi[standard]&quot;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-5-%EC%83%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B6%84%EC%84%9D%EC%9D%98-2%EB%8C%80-%EC%A7%84%EC%9E%85%EC%A0%90-readmemd--mainpy&quot;&gt;2-5. 새 프로젝트 분석의 2대 진입점 (README.md &amp;amp; main.py)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#3-fastapi-%EC%84%9C%EB%B2%84-%EC%8B%A4%ED%96%89%EA%B3%BC-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%86%B5%EC%8B%A0-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98&quot;&gt;FastAPI 서버 실행과 네트워크 통신 메커니즘&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#3-1-%EA%B0%9C%EB%B0%9C-%EC%84%9C%EB%B2%84-%EA%B8%B0%EB%8F%99-fastapi-dev-%EB%AA%85%EB%A0%B9%EC%96%B4&quot;&gt;3-1. 개발 서버 기동:&amp;nbsp;fastapi dev&amp;nbsp;명령어&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#3-2-%EC%99%B8%EB%B6%80-%EC%9A%94%EC%B2%ADnavercomdns-vs-%EB%82%B4%EB%B6%80-%EC%9A%94%EC%B2%ADlocalhost8000%EB%A3%A8%ED%94%84%EB%B0%B1-%EC%99%84%EB%B2%BD-%EB%B9%84%EA%B5%90&quot;&gt;3-2. 외부 요청(naver.com/DNS) vs 내부 요청(localhost:8000/루프백) 완벽 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#3-3-python-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%9D%98-%EC%9E%90%EB%8F%99-json-%EC%A7%81%EB%A0%AC%ED%99%94-%EC%9B%90%EB%A6%AC-listdict--json&quot;&gt;3-3. Python 데이터의 자동 JSON 직렬화 원리 (list/dict ➔ JSON)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#4-python-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0decorator%EC%99%80-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EC%8B%9C%EC%8A%A4%ED%85%9C&quot;&gt;Python 데코레이터(Decorator)와 라우팅 시스템&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#4-1-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC&quot;&gt;4-1. 데코레이터(@)의 본질과 동작 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#4-2-fastapi%EC%97%90%EC%84%9C-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0%EC%9D%98-%EC%97%AD%ED%95%A0-appget&quot;&gt;4-2. FastAPI에서 데코레이터의 역할 (@app.get)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#4-3-%EB%8C%80%ED%99%94%ED%98%95-%EC%9E%90%EB%8F%99-api-%EB%AC%B8%EC%84%9C-swagger-ui--redoc&quot;&gt;4-3. 대화형 자동 API 문서 (Swagger UI &amp;amp; ReDoc)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-path-parameter-%EA%B2%BD%EB%A1%9C-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98&quot;&gt;Path Parameter (경로 매개변수)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-1-path-parameter%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EB%A6%AC%EC%86%8C%EC%8A%A4-%EC%8B%9D%EB%B3%84identify&quot;&gt;5-1. Path Parameter의 정의와 리소스 식별(Identify)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-2-%ED%83%80%EC%9E%85-%ED%9E%8C%ED%8A%B8-%EA%B8%B0%EB%B0%98-%EC%9E%90%EB%8F%99-%EA%B2%80%EC%A6%9D%EA%B3%BC-422-unprocessable-entity&quot;&gt;5-2. 타입 힌트 기반 자동 검증과 422 Unprocessable Entity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-3--%EC%B9%98%EB%AA%85%EC%A0%81-%EC%A3%BC%EC%9D%98%EC%A0%90-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EC%88%9C%EC%84%9C-%EC%B6%A9%EB%8F%8C%EA%B3%BC-%ED%95%B4%EA%B2%B0-%EA%B3%B5%EC%8B%9D&quot;&gt;5-3.   치명적 주의점: 라우팅 순서 충돌과 해결 공식&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-4-path-%EA%B3%A0%EA%B8%89-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC-%EC%98%B5%EC%85%98-path&quot;&gt;5-4. Path 고급 유효성 검사 옵션 (Path())&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-5-%EC%8B%A4%EC%8A%B5-1-path-parameter-%EB%A7%8C%EB%93%A4%EA%B8%B0-max_length6&quot;&gt;5-5. [실습 1] Path Parameter 만들기 (max_length=6)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-query-parameter-%EC%BF%BC%EB%A6%AC-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98&quot;&gt;Query Parameter (쿼리 매개변수)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-1-query-parameter%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EC%A3%BC%EC%9A%94-%EC%9A%A9%EB%8F%84-%ED%95%84%ED%84%B0%EB%A7%81%EC%A0%95%EB%A0%AC%EA%B2%80%EC%83%89&quot;&gt;6-1. Query Parameter의 정의와 주요 용도 (필터링&amp;middot;정렬&amp;middot;검색)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-2-%ED%95%84%EC%88%98required-vs-%EC%84%A0%ED%83%9Doptional%EA%B8%B0%EB%B3%B8%EA%B0%92-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%EA%B5%AC%EB%B6%84&quot;&gt;6-2. 필수(Required) vs 선택(Optional/기본값) 파라미터 구분&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-3-query-%EA%B3%A0%EA%B8%89-%EC%98%B5%EC%85%98-query-min_length-ge-le&quot;&gt;6-3. Query 고급 옵션 (Query(),&amp;nbsp;min_length,&amp;nbsp;ge,&amp;nbsp;le)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-4-%EC%8B%A4%EC%8A%B5-2-%EC%83%81%ED%92%88-%EA%B2%80%EC%83%89-api-%EB%A7%8C%EB%93%A4%EA%B8%B0&quot;&gt;6-4. [실습 2] 상품 검색 API 만들기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#7-path-parameter-vs-query-parameter-%EB%B9%84%EA%B5%90-%EB%B0%8F-%ED%98%BC%ED%95%A9-%EC%82%AC%EC%9A%A9&quot;&gt;Path Parameter vs Query Parameter 비교 및 혼합 사용&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#7-1-%EC%96%B8%EC%A0%9C-path%EB%A5%BC-%EC%93%B0%EA%B3%A0-%EC%96%B8%EC%A0%9C-query%EB%A5%BC-%EC%93%B0%EB%8A%94%EA%B0%80-%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95-%EA%B8%B0%EC%A4%80&quot;&gt;7-1. 언제 Path를 쓰고, 언제 Query를 쓰는가? (의사결정 기준)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#7-2-path%EC%99%80-query%EB%A5%BC-%EB%8F%99%EC%8B%9C%EC%97%90-%EA%B2%B0%ED%95%A9%ED%95%9C-%EC%97%94%EB%93%9C%ED%8F%AC%EC%9D%B8%ED%8A%B8-%EC%84%A4%EA%B3%84&quot;&gt;7-2. Path와 Query를 동시에 결합한 엔드포인트 설계&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#8-%EC%A2%85%ED%95%A9-%EC%8B%A4%EC%A0%84-%EC%98%88%EC%A0%9C-%EC%9D%B4%EC%BB%A4%EB%A8%B8%EC%8A%A4-%EC%83%81%ED%92%88-%EA%B4%80%EB%A6%AC-api--swagger-%EA%B2%80%EC%A6%9D&quot;&gt;종합 실전 예제: 이커머스 상품 관리 API &amp;amp; Swagger 검증&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#8-1-%EC%A0%84%EC%B2%B4-%EC%83%81%ED%92%88-%EC%A1%B0%ED%9A%8C-%EA%B2%80%EC%83%89-%EB%8B%A8%EC%9D%BC-%EC%83%81%ED%92%88-%EC%83%81%EC%84%B8-%EC%A1%B0%ED%9A%8C-%ED%92%80-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C&quot;&gt;8-1. 전체 상품 조회, 검색, 단일 상품 상세 조회 풀 소스코드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#8-2-swagger-ui-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%8F-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EC%97%90%EB%9F%AC-%EB%B6%84%EC%84%9D&quot;&gt;8-2. Swagger UI 대시보드 테스트 및 유효성 에러 분석&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#9--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. FastAPI란 무엇인가? (고성능 웹 API 프레임워크)&lt;/h2&gt;
&lt;a id=&quot;user-content-1-fastapi란-무엇인가-고성능-웹-api-프레임워크&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#1-fastapi%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EC%9B%B9-api-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. 'Fast'의 2가지 본질 (처리 속도 &amp;amp; 개발 속도)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-fast의-2가지-본질-처리-속도--개발-속도&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#1-1-fast%EC%9D%98-2%EA%B0%80%EC%A7%80-%EB%B3%B8%EC%A7%88-%EC%B2%98%EB%A6%AC-%EC%86%8D%EB%8F%84--%EA%B0%9C%EB%B0%9C-%EC%86%8D%EB%8F%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FastAPI&lt;/b&gt;는 현대적인 Python 3.10+의 표준 기능(타입 힌트, 비동기)을 기반으로 구축된 최첨단 고성능 웹 API 프레임워크입니다.&lt;br /&gt;이름에 붙은 **'Fast'**에는 엔지니어링 관점에서 2가지 중요한 의미가 담겨 있습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;실행 및 요청 처리 속도가 빠르다 (High Performance)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기 네트워킹 코어인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Starlette&lt;/b&gt;과 초고속 데이터 검증 라이브러리인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Pydantic&lt;/b&gt;을 기반으로 설계되었습니다.&lt;/li&gt;
&lt;li&gt;전통적인 Python 웹 프레임워크(Django, Flask)에 비해 압도적으로 빠르며, **Node.js(Express)나 Go 언어에 필적하는 벤치마크 처리량(RPS)**을 달성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발하는 속도가 빠르다 (Fast Development)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표준 Python 타입 힌트만 적어주면 데이터 유효성 검사, 직렬화, API 문서화가 자동으로 완료됩니다.&lt;/li&gt;
&lt;li&gt;개발자의 반복적인 보일러플레이트 코드를 줄여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;개발 생산성을 200~300% 향상&lt;/b&gt;시킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. FastAPI의 3대 핵심 특징&lt;/h3&gt;
&lt;a id=&quot;user-content-1-2-fastapi의-3대-핵심-특징&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#1-2-fastapi%EC%9D%98-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%ED%8A%B9%EC%A7%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0k817/dJMb992EEiD/xDSbGiYS8eZVPxRFOkzhCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0k817/dJMb992EEiD/xDSbGiYS8eZVPxRFOkzhCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0k817/dJMb992EEiD/xDSbGiYS8eZVPxRFOkzhCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0k817%2FdJMb992EEiD%2FxDSbGiYS8eZVPxRFOkzhCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;441&quot; height=&quot;203&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;빠른 성능 (Starlette 기반)&lt;/b&gt;:&lt;br /&gt;async&lt;span&gt;&amp;nbsp;&lt;/span&gt;/&lt;span&gt;&amp;nbsp;&lt;/span&gt;await&lt;span&gt;&amp;nbsp;&lt;/span&gt;비동기 프로그래밍을 완벽 지원하여 I/O 바운드 작업(DB 쿼리, 외부 API 호출, ML 추론 요청)을 효율적으로 병렬 처리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타입 힌트 기반 자동 검증 (Type Hinting &amp;amp; Validation)&lt;/b&gt;:&lt;br /&gt;함수 인자에&lt;span&gt;&amp;nbsp;&lt;/span&gt;user_id: int처럼 파이썬 타입만 지정하면, 요청 데이터의 타입을 자동으로 체크하고 잘못된 입력값은 사전에 422 에러로 차단합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동 API 문서 (Swagger UI &amp;amp; ReDoc)&lt;/b&gt;:&lt;br /&gt;코드를 작성하고 서버를 띄우는 순간, 브라우저에서 직접 테스트할 수 있는 대화형 웹 문서가 1초 만에 자동 생성됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;Note&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;언제 FastAPI를 사용하는가?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RESTful 백엔드 API 마이크로서비스 구축&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AI / ML / 딥러닝 모델 서빙 (PyTorch, TensorFlow, Scikit-learn, OpenAI API 래핑)&lt;/b&gt;: 데이터 과학자와 머신러닝 엔지니어들이 가장 사랑하는 서빙 프레임워크의 표준입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3. Python 웹 프레임워크 3대장 비교 (FastAPI vs Django vs Flask)&lt;/h3&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&amp;nbsp; &amp;nbsp;비교 항목&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  Django&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   Flask&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ⚡ FastAPI
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;철학 &amp;amp; 아키텍처&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;풀스택, Batteries-Included (ORM, 어드민, 인증 기본 내장)&lt;/td&gt;
&lt;td&gt;마이크로 프레임워크, 극단적 미니멀리즘과 높은 자유도&lt;/td&gt;
&lt;td&gt;모던 API 전용 프레임워크, 비동기 네이티브, 타입 세이프&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;처리 성능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;보통 (동기 중심, 전통적 WSGI)&lt;/td&gt;
&lt;td&gt;보통 (동기 중심, 전통적 WSGI)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;매우 빠름 (ASGI 기반, Starlette 코어)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;타입 검증&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;수동 폼/시리얼라이저 작성 필요&lt;/td&gt;
&lt;td&gt;서드파티 라이브러리(Marshmallow 등) 필요&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Python 표준 타입 힌트로 자동 검증 (Pydantic)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;API 문서화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Swagger 연동 시 별도 플러그인 필요&lt;/td&gt;
&lt;td&gt;flasgger&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 외부 패키지 수동 세팅&lt;/td&gt;
&lt;td&gt;&lt;b&gt;코드 작성 즉시 Swagger/ReDoc 자동 생성&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;러닝 커브&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;높음 (규칙과 내부 구조가 방대함)&lt;/td&gt;
&lt;td&gt;낮음 (시작은 쉬우나 규모 확장 시 설계 어려움)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;낮음~보통 (직관적인 문법, 명확한 에러 메시지)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;주요 사용처&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;대규모 모놀리식 웹 서비스, 관리자 페이지&lt;/td&gt;
&lt;td&gt;간단한 프로토타입, 소규모 웹 사이트&lt;/td&gt;
&lt;td&gt;&lt;b&gt;고성능 REST API 서버, AI/ML 모델 서빙&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 개발 환경 구축과 가상환경(.venv)의 본질&lt;/h2&gt;
&lt;a id=&quot;user-content-2-개발-환경-구축과-가상환경venv의-본질&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%EA%B3%BC-%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BDvenv%EC%9D%98-%EB%B3%B8%EC%A7%88&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 왜 프로젝트마다 가상환경을 분리해야 하는가?&lt;/h3&gt;
&lt;a id=&quot;user-content-2-1-왜-프로젝트마다-가상환경을-분리해야-하는가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-1-%EC%99%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A7%88%EB%8B%A4-%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD%EC%9D%84-%EB%B6%84%EB%A6%AC%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터의 전역(Global) 파이썬 환경에 라이브러리를 마구잡이로 설치하면, 프로젝트 A(예: FastAPI 0.95, Pydantic v1)와 프로젝트 B(FastAPI 0.110, Pydantic v2) 간의 **패키지 버전 충돌(Dependency Hell)**이 발생합니다.&lt;/li&gt;
&lt;li&gt;**가상환경(Virtual Environment)**은 프로젝트 폴더 내부에 파이썬 실행 파일과 라이브러리를 격리 보관하는 독립된 방입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;폴더 이름 관례 (.venv)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름 앞에 붙은 점(.)은 운영체제에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;숨김(Hidden) 파일/디렉터리&lt;/b&gt;를 의미합니다.&lt;/li&gt;
&lt;li&gt;소스 코드가 아니라 환경 설정 격리용 디렉터리이므로 Git 관리 대상에서 제외(.gitignore)합니다.&lt;/li&gt;
&lt;li&gt;보통 프로젝트 폴더 하나당&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;하나의 가상환경만 생성&lt;/b&gt;하여 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. OS별 가상환경 생성 및 활성화 명령어 (macOS vs Windows)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-os별-가상환경-생성-및-활성화-명령어-macos-vs-windows&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-2-os%EB%B3%84-%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD-%EC%83%9D%EC%84%B1-%EB%B0%8F-%ED%99%9C%EC%84%B1%ED%99%94-%EB%AA%85%EB%A0%B9%EC%96%B4-macos-vs-windows&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;jboss-cli&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 1. 프로젝트 폴더 생성 및 이동
mkdir fastapi-study &amp;amp;&amp;amp; cd fastapi-study

# 2. Python 3.10+ 버전 확인
python3 --version

# 3. .venv 가상환경 생성
python3 -m venv .venv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;가상환경 활성화(Activate) 명령어 비교:&lt;/h4&gt;
&lt;/div&gt;
&amp;nbsp; &amp;nbsp;운영체제 (OS)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 가상환경 활성화 명령어&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;터미널 표시 변화&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;비활성화(종료) 명령어
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 28.2558%;&quot;&gt;&lt;b&gt;macOS / Linux&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25.5814%;&quot;&gt;source .venv/bin/activate&lt;/td&gt;
&lt;td style=&quot;width: 27.093%;&quot;&gt;프롬프트 앞에&lt;span&gt;&amp;nbsp;&lt;/span&gt;(.venv)&lt;span&gt;&amp;nbsp;&lt;/span&gt;표시&lt;/td&gt;
&lt;td style=&quot;width: 18.8372%;&quot;&gt;deactivate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 28.2558%;&quot;&gt;&lt;b&gt;Windows (CMD)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25.5814%;&quot;&gt;.venv\Scripts\activate.bat&lt;/td&gt;
&lt;td style=&quot;width: 27.093%;&quot;&gt;프롬프트 앞에&lt;span&gt;&amp;nbsp;&lt;/span&gt;(.venv)&lt;span&gt;&amp;nbsp;&lt;/span&gt;표시&lt;/td&gt;
&lt;td style=&quot;width: 18.8372%;&quot;&gt;deactivate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 28.2558%;&quot;&gt;&lt;b&gt;Windows (PowerShell)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25.5814%;&quot;&gt;.venv\Scripts\Activate.ps1&lt;/td&gt;
&lt;td style=&quot;width: 27.093%;&quot;&gt;프롬프트 앞에&lt;span&gt;&amp;nbsp;&lt;/span&gt;(.venv)&lt;span&gt;&amp;nbsp;&lt;/span&gt;표시&lt;/td&gt;
&lt;td style=&quot;width: 18.8372%;&quot;&gt;deactivate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. 활성화 전후의 파이썬 인터프리터 경로 변화&lt;/h3&gt;
&lt;a id=&quot;user-content-2-3-활성화-전후의-파이썬-인터프리터-경로-변화&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-3-%ED%99%9C%EC%84%B1%ED%99%94-%EC%A0%84%ED%9B%84%EC%9D%98-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9D%B8%ED%84%B0%ED%94%84%EB%A6%AC%ED%84%B0-%EA%B2%BD%EB%A1%9C-%EB%B3%80%ED%99%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;which python3&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Windows의 경우&lt;span&gt;&amp;nbsp;&lt;/span&gt;where python) 명령어로 파이썬 실행 위치를 추적해보면 가상환경의 작동 원리가 선명해집니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lxIBx/dJMcahfoyxF/rAuas86mz0Bfs0A8t0U1Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lxIBx/dJMcahfoyxF/rAuas86mz0Bfs0A8t0U1Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lxIBx/dJMcahfoyxF/rAuas86mz0Bfs0A8t0U1Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlxIBx%2FdJMcahfoyxF%2FrAuas86mz0Bfs0A8t0U1Hk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1238&quot; height=&quot;238&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;활성화 전&lt;/b&gt;: OS 전체에서 공유하는 전역 파이썬 경로를 가리킴.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활성화 후&lt;/b&gt;: 터미널의 환경변수(PATH)가 변경되어, 내가 생성한&lt;span&gt;&amp;nbsp;&lt;/span&gt;.venv&lt;span&gt;&amp;nbsp;&lt;/span&gt;폴더 안의 파이썬 인터프리터와&lt;span&gt;&amp;nbsp;&lt;/span&gt;pip&lt;span&gt;&amp;nbsp;&lt;/span&gt;저장소를 바라보게 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-4. FastAPI 표준 패키지 설치 (pip install &quot;fastapi[standard]&quot;)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-4-fastapi-표준-패키지-설치-pip-install-fastapistandard&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-4-fastapi-%ED%91%9C%EC%A4%80-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EC%B9%98-pip-install-fastapistandard&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상환경이 켜진 상태((.venv)&lt;span&gt;&amp;nbsp;&lt;/span&gt;확인)에서 아래 명령어를 실행합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;cmake&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;pip install &quot;fastapi[standard]&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #1a7f37;&quot; data-ke-size=&quot;size16&quot;&gt;Tip&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;fastapi[standard]&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;인가요?&lt;/b&gt;&lt;br /&gt;과거에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;pip install fastapi uvicorn&lt;span&gt;&amp;nbsp;&lt;/span&gt;처럼 서버 엔진을 따로 설치했으나, 최신 FastAPI는&lt;span&gt;&amp;nbsp;&lt;/span&gt;[standard]&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션을 붙여 설치하면 프로덕션 ASGI 서버인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Uvicorn&lt;/b&gt;, 개발용 CLI 도구인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;FastAPI CLI&lt;/b&gt;, Pydantic 이메일 검증기 등이 한 번에 완벽하게 세팅됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-5. 새 프로젝트 분석의 2대 진입점 (README.md &amp;amp; main.py)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-5-새-프로젝트-분석의-2대-진입점-readmemd--mainpy&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#2-5-%EC%83%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B6%84%EC%84%9D%EC%9D%98-2%EB%8C%80-%EC%A7%84%EC%9E%85%EC%A0%90-readmemd--mainpy&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현업이나 오픈소스에서 새로운 파이썬 백엔드 프로젝트를 인수인계받거나 열어볼 때는 다음 2가지를 먼저 확인합니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;README.md&lt;/b&gt;: 프로젝트의 전체 소개, 목적, 아키텍처 다이어그램, 환경 변수 세팅 및 실행 가이드 역할.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;main.py&lt;span&gt;&amp;nbsp;&lt;/span&gt;(또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;app.py)&lt;/b&gt;: 전체 애플리케이션의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;코드 진입점(Entry Point)&lt;/b&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;app = FastAPI()&lt;span&gt;&amp;nbsp;&lt;/span&gt;인스턴스가 생성되고 라우터들이 등록되는 출발점.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. FastAPI 서버 실행과 네트워크 통신 메커니즘&lt;/h2&gt;
&lt;a id=&quot;user-content-3-fastapi-서버-실행과-네트워크-통신-메커니즘&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#3-fastapi-%EC%84%9C%EB%B2%84-%EC%8B%A4%ED%96%89%EA%B3%BC-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%86%B5%EC%8B%A0-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. 개발 서버 기동:&lt;span&gt;&amp;nbsp;&lt;/span&gt;fastapi dev&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1-개발-서버-기동-fastapi-dev-명령어&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#3-1-%EA%B0%9C%EB%B0%9C-%EC%84%9C%EB%B2%84-%EA%B8%B0%EB%8F%99-fastapi-dev-%EB%AA%85%EB%A0%B9%EC%96%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main.py&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일이 있는 위치에서 터미널에 아래 명령어를 입력합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;nginx&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;fastapi dev
# 또는 명시적 파일 지정: fastapi dev main.py&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;fastapi dev의 핵심 기능&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;http://127.0.0.1:8000&lt;span&gt;&amp;nbsp;&lt;/span&gt;(8000번 포트)에서 개발 서버 자동 시작.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핫 리로드 (Auto-reload)&lt;/b&gt;: 코드를 수정하고 저장(Ctrl + S)하면 서버가 재시작 없이 실시간으로 변경 사항을 감지하여 반영.&lt;/li&gt;
&lt;li&gt;대화형 문서 링크 자동 안내 (Documentation at http://127.0.0.1:8000/docs).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. 외부 요청(naver.com/DNS) vs 내부 요청(localhost:8000/루프백) 완벽 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2-외부-요청navercomdns-vs-내부-요청localhost8000루프백-완벽-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#3-2-%EC%99%B8%EB%B6%80-%EC%9A%94%EC%B2%ADnavercomdns-vs-%EB%82%B4%EB%B6%80-%EC%9A%94%EC%B2%ADlocalhost8000%EB%A3%A8%ED%94%84%EB%B0%B1-%EC%99%84%EB%B2%BD-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 브라우저 주소창에 주소를 칠 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;외부 웹사이트 접속&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;로컬 개발 서버 접속&lt;/b&gt;은 네트워크 레벨에서 근본적으로 다르게 동작합니다.&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;color: #1f2328;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span&gt;&lt;b&gt;Unable to render rich display&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Parse error on line 5:&lt;br /&gt;... --&amp;gt;|3. 실제 공인 IP 반환 (예: 223.130.195.95)|&lt;br /&gt;-----------------------^&lt;br /&gt;Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', &lt;br /&gt;'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'&lt;br /&gt;&lt;br /&gt;For more information, see&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&quot;&gt;https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;graph TD
    subgraph Case1[&quot;1. 외부 서버에 요청하는 경우 (naver.com)&quot;]
        U1[&quot;내 컴퓨터 브라우저 (Chrome)&quot;] --&amp;gt;|1. naver.com 입력| OS1[&quot;운영체제 O/S 네트워크 스택&quot;]
        OS1 --&amp;gt;|2. 외부 DNS 서버 질의| DNS[&quot;DNS 서버 (전화번호부)&quot;]
        DNS --&amp;gt;|3. 실제 공인 IP 반환 (예: 223.130.195.95)| OS1
        OS1 --&amp;gt;|4. 광랜/인터넷망 경유| EXT[&quot;원격지 네이버 데이터센터 서버&quot;]
    end

    subgraph Case2[&quot;2. 내 컴퓨터에 요청하는 경우 (localhost:8000)&quot;]
        U2[&quot;내 컴퓨터 브라우저 (Chrome)&quot;] --&amp;gt;|1. localhost:8000 입력| OS2[&quot;운영체제 O/S (루프백 감지)&quot;]
        OS2 --&amp;gt;|2. 외부 인터넷으로 나가지 않음!| LOCAL[&quot;내 컴퓨터 내부 8000번 포트 (FastAPI 서버)&quot;]
    end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&amp;nbsp; &amp;nbsp;구분&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   외부 서버 요청 (https://naver.com)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   내부 로컬 요청 (localhost:8000)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;목적지&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;전 세계 어딘가에 위치한 원격 데이터센터 서버&lt;/td&gt;
&lt;td&gt;&lt;b&gt;현재 내가 작업하고 있는 바로 그 컴퓨터&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;DNS 질의&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;외부 DNS 서버를 거쳐 실제 공인 IP(예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;1.2.3.4)를 알아옴&lt;/td&gt;
&lt;td&gt;DNS 질의 불필요 (localhost는 OS 내부에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;127.0.0.1로 즉시 해석)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;네트워크 경로&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;공유기 ➔ 통신사 망 ➔ 인터넷 백본망 ➔ 목적지 서버&lt;/td&gt;
&lt;td&gt;**루프백 인터페이스(Loopback Interface)**를 타고 컴퓨터 내부에서 유턴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;인터넷 연결 필요 여부&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;인터넷이 끊기면 통신 불가&lt;/td&gt;
&lt;td&gt;&lt;b&gt;인터넷(Wi-Fi)이 완전히 끊겨도 로컬 테스트 100% 가능&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-3. Python 데이터의 자동 JSON 직렬화 원리 (list/dict ➔ JSON)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-3-python-데이터의-자동-json-직렬화-원리-listdict--json&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#3-3-python-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%9D%98-%EC%9E%90%EB%8F%99-json-%EC%A7%81%EB%A0%AC%ED%99%94-%EC%9B%90%EB%A6%AC-listdict--json&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HTTP 프로토콜의 엄격한 제약&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트(웹 브라우저, 모바일 앱)와 서버가 주고받는 HTTP 응답 메시지의 본문(Body)에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JSON 문자열 형태의 텍스트만 실을 수 있습니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FastAPI의 자동 변환(Serialization) 마법&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자가 파이썬 함수에서 복잡하게&lt;span&gt;&amp;nbsp;&lt;/span&gt;json.dumps()를 호출할 필요가 없습니다.&lt;/li&gt;
&lt;li&gt;파이썬 딕셔너리나 리스트를 그대로&lt;span&gt;&amp;nbsp;&lt;/span&gt;return하면, FastAPI가 내부적으로 HTTP 응답 헤더(Content-Type: application/json)와 함께 완벽한 JSON 규격으로 변환해 줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI

app = FastAPI()

@app.get(&quot;/items&quot;)
def get_items():
    # 파이썬 List와 Dict 자료구조 반환
    return [
        {&quot;id&quot;: 1, &quot;name&quot;: &quot;apple&quot;, &quot;price&quot;: 1000},
        {&quot;id&quot;: 2, &quot;name&quot;: &quot;banana&quot;, &quot;price&quot;: 2000}
    ]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Python 자료형과 JSON 데이터 타입 매핑표:&lt;/h4&gt;
&lt;/div&gt;
&amp;nbsp; &amp;nbsp;Python 자료형&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;변환 방향&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 표준 JSON 데이터 타입
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 25.9302%;&quot;&gt;dict&lt;span&gt;&amp;nbsp;&lt;/span&gt;(딕셔너리)&lt;/td&gt;
&lt;td style=&quot;width: 9.65112%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%;&quot;&gt;&lt;b&gt;JSON Object&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;({ &quot;key&quot;: &quot;value&quot; })&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 25.9302%;&quot;&gt;list&lt;span&gt;&amp;nbsp;&lt;/span&gt;(리스트)&lt;/td&gt;
&lt;td style=&quot;width: 9.65112%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%;&quot;&gt;&lt;b&gt;JSON Array&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;([ 1, 2, 3 ])&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 25.9302%;&quot;&gt;tuple&lt;span&gt;&amp;nbsp;&lt;/span&gt;(튜플)&lt;/td&gt;
&lt;td style=&quot;width: 9.65112%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%;&quot;&gt;&lt;b&gt;JSON Array&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;([ &quot;a&quot;, &quot;b&quot; ])&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 25.9302%;&quot;&gt;str&lt;span&gt;&amp;nbsp;&lt;/span&gt;(문자열)&lt;/td&gt;
&lt;td style=&quot;width: 9.65112%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%;&quot;&gt;&lt;b&gt;JSON String&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&quot;text&quot;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 25.9302%;&quot;&gt;int,&lt;span&gt;&amp;nbsp;&lt;/span&gt;float&lt;span&gt;&amp;nbsp;&lt;/span&gt;(숫자)&lt;/td&gt;
&lt;td style=&quot;width: 9.65112%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%;&quot;&gt;&lt;b&gt;JSON Number&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(123,&lt;span&gt;&amp;nbsp;&lt;/span&gt;3.14)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 25.9302%;&quot;&gt;bool&lt;span&gt;&amp;nbsp;&lt;/span&gt;(True,&lt;span&gt;&amp;nbsp;&lt;/span&gt;False)&lt;/td&gt;
&lt;td style=&quot;width: 9.65112%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%;&quot;&gt;&lt;b&gt;JSON Boolean&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(true,&lt;span&gt;&amp;nbsp;&lt;/span&gt;false)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 25.9302%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 9.65112%;&quot;&gt;➔&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%;&quot;&gt;&lt;b&gt;JSON Null&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(null)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Python 데코레이터(Decorator)와 라우팅 시스템&lt;/h2&gt;
&lt;a id=&quot;user-content-4-python-데코레이터decorator와-라우팅-시스템&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#4-python-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0decorator%EC%99%80-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EC%8B%9C%EC%8A%A4%ED%85%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 데코레이터(@)의 본질과 동작 원리&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-데코레이터의-본질과-동작-원리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#4-1-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;**데코레이터(Decorator)**란:&lt;br /&gt;어떤 함수를 수정하지 않고 감싸서(Wrapping),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;해당 함수의 실행 전이나 후에 공통 로직(로깅, 인증, 시간 측정 등)을 덧붙여주는 파이썬 문법&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 가치&lt;/b&gt;: 중복 코드 제거, 선언적(Declarative) 기능 부여.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# [데코레이터의 기본 원리 구조]
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print(&quot;--- [전처리] 함수 실행 전 공통 작업 ---&quot;)
        result = func(*args, **kwargs)
        print(&quot;--- [후처리] 함수 실행 후 공통 작업 ---&quot;)
        return result
    return wrapper

# @ 기호로 함수 위에 장식
@my_decorator
def hello():
    print(&quot;안녕하세요! 메인 비즈니스 로직입니다.&quot;)

hello()
# 출력 결과:
# --- [전처리] 함수 실행 전 공통 작업 ---
# 안녕하세요! 메인 비즈니스 로직입니다.
# --- [후처리] 함수 실행 후 공통 작업 ---&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. FastAPI에서 데코레이터의 역할 (@app.get)&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-fastapi에서-데코레이터의-역할-appget&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#4-2-fastapi%EC%97%90%EC%84%9C-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0%EC%9D%98-%EC%97%AD%ED%95%A0-appget&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI에서는 데코레이터가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;일반 파이썬 함수를 웹 상에서 접근 가능한 'HTTP 엔드포인트(라우트)'로 승격시키는 결정적 역할&lt;/b&gt;을 합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.get(&quot;/&quot;)
def root():
    return {&quot;message&quot;: &quot;Hello FastAPI&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;데코레이터가 수행하는 3가지 내부 작업&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;HTTP 메서드 지정&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;get,&lt;span&gt;&amp;nbsp;&lt;/span&gt;post,&lt;span&gt;&amp;nbsp;&lt;/span&gt;put,&lt;span&gt;&amp;nbsp;&lt;/span&gt;delete&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 클라이언트가 어떤 방식으로 요청해야 하는지 정의.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;URL 경로 매핑&lt;/b&gt;: 클라이언트가 브라우저 주소창에&lt;span&gt;&amp;nbsp;&lt;/span&gt;/&lt;span&gt;&amp;nbsp;&lt;/span&gt;경로로 요청을 보낼 때 이 함수를 실행하도록 라우팅 테이블에 등록.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메타데이터 등록&lt;/b&gt;: 함수의 매개변수, 반환 타입, 주석을 읽어와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Swagger 문서(OpenAPI 스키마)에 자동 등록&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동작 비유&lt;/b&gt;: 프론트엔드의&lt;span&gt;&amp;nbsp;&lt;/span&gt;addEventListener(&quot;click&quot;, handler)처럼, **&quot;이 특정 URL로 GET 요청이 들어오면, 바로 밑에 있는 함수를 실행해 줘!&quot;**라고 등록해 두는 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3. 대화형 자동 API 문서 (Swagger UI &amp;amp; ReDoc)&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-대화형-자동-api-문서-swagger-ui--redoc&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#4-3-%EB%8C%80%ED%99%94%ED%98%95-%EC%9E%90%EB%8F%99-api-%EB%AC%B8%EC%84%9C-swagger-ui--redoc&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 켜진 상태에서 브라우저 주소창에 아래 주소를 입력하면 문서를 확인할 수 있습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Swagger UI (http://localhost:8000/docs)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 널리 사용되는 대화형 테스트 대시보드.&lt;/li&gt;
&lt;li&gt;각 API를 펼쳐서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Try it out&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;버튼을 누르면, Postman 같은 외부 툴 없이도 브라우저에서 실시간으로 파라미터를 입력하고 요청을 전송해 결과를 확인할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ReDoc (http://localhost:8000/redoc)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;깔끔하고 정돈된 3단 레이아웃의 공식 개발자 API 명세서 페이지.&lt;/li&gt;
&lt;li&gt;다른 팀이나 고객사에게 API 스펙을 공유할 때 매우 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Path Parameter (경로 매개변수)&lt;/h2&gt;
&lt;a id=&quot;user-content-5-path-parameter-경로-매개변수&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-path-parameter-%EA%B2%BD%EB%A1%9C-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. Path Parameter의 정의와 리소스 식별(Identify)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-path-parameter의-정의와-리소스-식별identify&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-1-path-parameter%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EB%A6%AC%EC%86%8C%EC%8A%A4-%EC%8B%9D%EB%B3%84identify&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Path Parameter (경로 매개변수)&lt;/b&gt;: URL 경로 자체의 일부분으로 변수처럼 포함되어 전달되는 값입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언제 사용하는가?&lt;/b&gt;: 특정 **리소스(자원)를 고유하게 식별(Identify)**할 때 사용합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;/users/3&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔ 3번 고유 ID를 가진 유저 정보&lt;/li&gt;
&lt;li&gt;예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;/items/apple&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;apple이라는 고유 식별명을 가진 아이템&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 경로에 중괄호 {user_id} 를 넣고, 함수 인자로 동일한 이름을 전달받음
@app.get(&quot;/users/{user_id}&quot;)
def get_user(user_id: int):
    return {&quot;user_id&quot;: user_id}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. 타입 힌트 기반 자동 검증과 422 Unprocessable Entity&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-타입-힌트-기반-자동-검증과-422-unprocessable-entity&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-2-%ED%83%80%EC%9E%85-%ED%9E%8C%ED%8A%B8-%EA%B8%B0%EB%B0%98-%EC%9E%90%EB%8F%99-%EA%B2%80%EC%A6%9D%EA%B3%BC-422-unprocessable-entity&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI는 파이썬의 타입 힌트(user_id: int)를 보고 자동으로 유효성 검사를 수행합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정상 요청 (GET /users/3)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URL의 문자열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;3&quot;을 파이썬 정수&lt;span&gt;&amp;nbsp;&lt;/span&gt;3으로 자동 형변환하여 함수에 전달 ➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;200 OK&lt;span&gt;&amp;nbsp;&lt;/span&gt;성공!&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비정상 요청 (GET /users/abc)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;abc&quot;는 정수(int)로 변환할 수 없음.&lt;/li&gt;
&lt;li&gt;FastAPI가 함수 내부를 실행하기도 전에 가로채서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;422 Unprocessable Entity&lt;span&gt;&amp;nbsp;&lt;/span&gt;에러 응답&lt;/b&gt;을 자동으로 반환!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;json&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 422 에러 응답 예시 (FastAPI 자동 생성) */
{
  &quot;detail&quot;: [
    {
      &quot;type&quot;: &quot;int_parsing&quot;,
      &quot;loc&quot;: [&quot;path&quot;, &quot;user_id&quot;],
      &quot;msg&quot;: &quot;Input should be a valid integer, unable to parse string as an integer&quot;,
      &quot;input&quot;: &quot;abc&quot;
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3.   치명적 주의점: 라우팅 순서 충돌과 해결 공식&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3--치명적-주의점-라우팅-순서-충돌과-해결-공식&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-3--%EC%B9%98%EB%AA%85%EC%A0%81-%EC%A3%BC%EC%9D%98%EC%A0%90-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EC%88%9C%EC%84%9C-%EC%B6%A9%EB%8F%8C%EA%B3%BC-%ED%95%B4%EA%B2%B0-%EA%B3%B5%EC%8B%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 접두사(prefix)를 가진 엔드포인트를 만들 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;코드 작성 순서&lt;/b&gt;에 따라 심각한 라우팅 버그가 발생할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# ❌ 잘못된 순서 (버그 발생!)
@app.get(&quot;/items/{item_id}&quot;)
def get_item(item_id: str):
    return {&quot;item_id&quot;: item_id}

@app.get(&quot;/items/search&quot;)
def search_item():
    return {&quot;message&quot;: &quot;검색 결과&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  왜 문제가 발생할까?&lt;/b&gt;&lt;br /&gt;FastAPI는 라우트를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;위에서 아래로 선언된 순서대로&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;매칭합니다.&lt;br /&gt;만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;/items/{item_id}가 위에 있다면, 사용자가&lt;span&gt;&amp;nbsp;&lt;/span&gt;/items/search를 호출했을 때 FastAPI는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;search&quot;라는 단어를&lt;span&gt;&amp;nbsp;&lt;/span&gt;{item_id}&lt;span&gt;&amp;nbsp;&lt;/span&gt;변수 값으로 인식하여 위쪽 함수를 실행해 버립니다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  해결 공식 (라우팅 우선순위 원칙):&lt;/h4&gt;
&lt;a id=&quot;user-content--해결-공식-라우팅-우선순위-원칙&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#-%ED%95%B4%EA%B2%B0-%EA%B3%B5%EC%8B%9D-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84-%EC%9B%90%EC%B9%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;고정된 정적 경로(/items/search)를 항상 코드 위쪽에 먼저 선언하고,&lt;br /&gt;가변 변수가 들어간 경로(/items/{item_id})를 아래쪽에 나중에 선언하라!&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-4. Path 고급 유효성 검사 옵션 (Path())&lt;/h3&gt;
&lt;a id=&quot;user-content-5-4-path-고급-유효성-검사-옵션-path&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-4-path-%EA%B3%A0%EA%B8%89-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC-%EC%98%B5%EC%85%98-path&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI의&lt;span&gt;&amp;nbsp;&lt;/span&gt;Path&lt;span&gt;&amp;nbsp;&lt;/span&gt;모듈을 사용하면 숫자 범위, 문자열 길이, Swagger 문서 설명 등을 강력하게 강제할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI, Path

app = FastAPI()

@app.get(&quot;/users/{user_id}&quot;)
def get_user(
    user_id: int = Path(
        ...,                    # ... (Ellipsis)는 '필수값'임을 의미
        ge=1,                   # ge: Greater than or equal to (1 이상이어야 함)
        description=&quot;조회할 유저의 고유 ID (1 이상의 양수)&quot;
    )
):
    return {&quot;user_id&quot;: user_id}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;주요 검증 키워드:&lt;/h4&gt;
&lt;a id=&quot;user-content-주요-검증-키워드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#%EC%A3%BC%EC%9A%94-%EA%B2%80%EC%A6%9D-%ED%82%A4%EC%9B%8C%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;...&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Ellipsis): 기본값이 없는 필수 파라미터임을 명시&lt;/li&gt;
&lt;li&gt;ge&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&amp;gt;=): 이상&lt;/li&gt;
&lt;li&gt;gt&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&amp;gt;): 초과&lt;/li&gt;
&lt;li&gt;le&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&amp;lt;=): 이하&lt;/li&gt;
&lt;li&gt;lt&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&amp;lt;): 미만&lt;/li&gt;
&lt;li&gt;min_length,&lt;span&gt;&amp;nbsp;&lt;/span&gt;max_length: 문자열 최소/최대 길이 제한&lt;/li&gt;
&lt;li&gt;description: Swagger 문서에 친절한 한글 설명 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-5. [실습 1] Path Parameter 만들기 (max_length=6)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-5-실습-1-path-parameter-만들기-max_length6&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#5-5-%EC%8B%A4%EC%8A%B5-1-path-parameter-%EB%A7%8C%EB%93%A4%EA%B8%B0-max_length6&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;요구사항&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔드포인트:&lt;span&gt;&amp;nbsp;&lt;/span&gt;GET /items/{item_name}&lt;/li&gt;
&lt;li&gt;item_name은 문자열(str) 타입이어야 하며, 최대 글자수(max_length)는 6글자 이하로 제한&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답 예시&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;/items/apple&lt;span&gt;&amp;nbsp;&lt;/span&gt;입력 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;{&quot;item_name&quot;: &quot;apple&quot;}&lt;span&gt;&amp;nbsp;&lt;/span&gt;반환&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;완성 코드:&lt;/h4&gt;
&lt;a id=&quot;user-content-완성-코드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#%EC%99%84%EC%84%B1-%EC%BD%94%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI, Path

app = FastAPI()

@app.get(&quot;/items/{item_name}&quot;)
def get_item(
    item_name: str = Path(..., max_length=6, description=&quot;6자 이하의 아이템 이름&quot;)
):
    return {&quot;item_name&quot;: item_name}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Query Parameter (쿼리 매개변수)&lt;/h2&gt;
&lt;a id=&quot;user-content-6-query-parameter-쿼리-매개변수&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-query-parameter-%EC%BF%BC%EB%A6%AC-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. Query Parameter의 정의와 주요 용도 (필터링&amp;middot;정렬&amp;middot;검색)&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-query-parameter의-정의와-주요-용도-필터링정렬검색&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-1-query-parameter%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EC%A3%BC%EC%9A%94-%EC%9A%A9%EB%8F%84-%ED%95%84%ED%84%B0%EB%A7%81%EC%A0%95%EB%A0%AC%EA%B2%80%EC%83%89&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Query Parameter (쿼리 매개변수)&lt;/b&gt;: URL 경로 끝에 물음표(?)를 붙이고&lt;span&gt;&amp;nbsp;&lt;/span&gt;key=value&lt;span&gt;&amp;nbsp;&lt;/span&gt;형태로 전달하는 데이터입니다. 여러 개일 경우&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;amp;로 연결합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;/search?q=fastapi&amp;amp;limit=10&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요 용도&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 리소스를 지칭하는 것이 아니라, 목록을 조회할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;필터링(Filtering), 검색(Search), 정렬(Sorting), 페이지네이션(Pagination)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등의 부가 옵션을 줄 때 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2. 필수(Required) vs 선택(Optional/기본값) 파라미터 구분&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-필수required-vs-선택optional기본값-파라미터-구분&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-2-%ED%95%84%EC%88%98required-vs-%EC%84%A0%ED%83%9Doptional%EA%B8%B0%EB%B3%B8%EA%B0%92-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%EA%B5%AC%EB%B6%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URL 경로({})에 선언되지 않은 함수 매개변수는 FastAPI가 자동으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Query Parameter&lt;/b&gt;로 취급합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;groovy&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@app.get(&quot;/search&quot;)
def search(q: str, limit: int = 10):
    return {&quot;q&quot;: q, &quot;limit&quot;: limit}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;q: str&lt;/b&gt;: 기본값이 지정되지 않았으므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;필수(Required)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;쿼리 파라미터입니다. (?q=단어가 없으면 422 에러)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;limit: int = 10&lt;/b&gt;: 기본값&lt;span&gt;&amp;nbsp;&lt;/span&gt;10이 할당되어 있으므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;선택(Optional)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;쿼리 파라미터입니다. (생략 시 자동으로 10이 적용됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-3. Query 고급 옵션 (Query(),&lt;span&gt;&amp;nbsp;&lt;/span&gt;min_length,&lt;span&gt;&amp;nbsp;&lt;/span&gt;ge,&lt;span&gt;&amp;nbsp;&lt;/span&gt;le)&lt;/h3&gt;
&lt;a id=&quot;user-content-6-3-query-고급-옵션-query-min_length-ge-le&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-3-query-%EA%B3%A0%EA%B8%89-%EC%98%B5%EC%85%98-query-min_length-ge-le&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Path와 마찬가지로&lt;span&gt;&amp;nbsp;&lt;/span&gt;from fastapi import Query를 임포트하여 쿼리 스트링에 대한 상세한 유효성 검증을 걸 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI, Query

app = FastAPI()

@app.get(&quot;/search&quot;)
def search(
    q: str = Query(..., min_length=2, max_length=30, description=&quot;검색어 (2~30자)&quot;),
    limit: int = Query(10, ge=1, le=100, description=&quot;한 페이지당 가져올 개수 (1~100)&quot;)
):
    return {&quot;q&quot;: q, &quot;limit&quot;: limit}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-4. [실습 2] 상품 검색 API 만들기&lt;/h3&gt;
&lt;a id=&quot;user-content-6-4-실습-2-상품-검색-api-만들기&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#6-4-%EC%8B%A4%EC%8A%B5-2-%EC%83%81%ED%92%88-%EA%B2%80%EC%83%89-api-%EB%A7%8C%EB%93%A4%EA%B8%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;요구사항&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔드포인트:&lt;span&gt;&amp;nbsp;&lt;/span&gt;GET /products/search&lt;/li&gt;
&lt;li&gt;쿼리 파라미터&lt;span&gt;&amp;nbsp;&lt;/span&gt;q(검색어, str, 필수),&lt;span&gt;&amp;nbsp;&lt;/span&gt;limit(개수, int, 기본값 10)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답 예시&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;/products/search?q=apple&amp;amp;limit=5&lt;span&gt;&amp;nbsp;&lt;/span&gt;호출 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;{&quot;q&quot;: &quot;apple&quot;, &quot;limit&quot;: 5}&lt;span&gt;&amp;nbsp;&lt;/span&gt;반환&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;완성 코드:&lt;/h4&gt;
&lt;a id=&quot;user-content-완성-코드-1&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#%EC%99%84%EC%84%B1-%EC%BD%94%EB%93%9C-1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;groovy&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI

app = FastAPI()

@app.get(&quot;/products/search&quot;)
def product_search(q: str, limit: int = 10):
    return {&quot;q&quot;: q, &quot;limit&quot;: limit}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. Path Parameter vs Query Parameter 비교 및 혼합 사용&lt;/h2&gt;
&lt;a id=&quot;user-content-7-path-parameter-vs-query-parameter-비교-및-혼합-사용&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#7-path-parameter-vs-query-parameter-%EB%B9%84%EA%B5%90-%EB%B0%8F-%ED%98%BC%ED%95%A9-%EC%82%AC%EC%9A%A9&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-1. 언제 Path를 쓰고, 언제 Query를 쓰는가? (의사결정 기준)&lt;/h3&gt;
&lt;/div&gt;
&amp;nbsp; &amp;nbsp;구분&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   Path Parameter&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   Query Parameter
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;URL 형태&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;/users/10&lt;/td&gt;
&lt;td&gt;/users?role=admin&amp;amp;sort=desc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;핵심 목적&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;리소스의 '고유 식별(Identification)'&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;리소스 목록의 '조건 제어(Filtering, Pagination)'&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;필수 여부&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;URL 경로의 일부이므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;무조건 필수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;대부분&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;선택 옵션&lt;/b&gt;(기본값 제공 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;데이터 의미&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&quot;10번 유저를 가져와라&quot;&lt;/td&gt;
&lt;td&gt;&quot;유저들 중 관리자 역할만 내림차순 정렬해서 가져와라&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;RESTful 권장&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;자원의 계층 구조를 나타낼 때&lt;/td&gt;
&lt;td&gt;자원을 정렬, 검색, 페이징할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-2. Path와 Query를 동시에 결합한 엔드포인트 설계&lt;/h3&gt;
&lt;a id=&quot;user-content-7-2-path와-query를-동시에-결합한-엔드포인트-설계&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#7-2-path%EC%99%80-query%EB%A5%BC-%EB%8F%99%EC%8B%9C%EC%97%90-%EA%B2%B0%ED%95%A9%ED%95%9C-%EC%97%94%EB%93%9C%ED%8F%AC%EC%9D%B8%ED%8A%B8-%EC%84%A4%EA%B3%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 리소스 식별과 조회 옵션을 동시에 전달하기 위해 두 방식을 함께 사용합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;# 예: 3번 유저의 게시글 중 5개만 조회
# GET /users/3/posts?limit=5
@app.get(&quot;/users/{user_id}/posts&quot;)
def list_user_posts(user_id: int, limit: int = 10):
    # user_id는 URL 경로에 있으므로 -&amp;gt; Path Parameter
    # limit는 URL 경로에 없으므로 -&amp;gt; Query Parameter
    return {
        &quot;user_id&quot;: user_id,
        &quot;limit&quot;: limit,
        &quot;message&quot;: f&quot;{user_id}번 유저의 게시글을 최대 {limit}개 조회합니다.&quot;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 종합 실전 예제: 이커머스 상품 관리 API &amp;amp; Swagger 검증&lt;/h2&gt;
&lt;a id=&quot;user-content-8-종합-실전-예제-이커머스-상품-관리-api--swagger-검증&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#8-%EC%A2%85%ED%95%A9-%EC%8B%A4%EC%A0%84-%EC%98%88%EC%A0%9C-%EC%9D%B4%EC%BB%A4%EB%A8%B8%EC%8A%A4-%EC%83%81%ED%92%88-%EA%B4%80%EB%A6%AC-api--swagger-%EA%B2%80%EC%A6%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의 슬라이드 29페이지에 등장한 실무형 이커머스 상품 조회 및 검색 API 전체 완성 코드입니다.&lt;/p&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-1. 전체 상품 조회, 검색, 단일 상품 상세 조회 풀 소스코드&lt;/h3&gt;
&lt;a id=&quot;user-content-8-1-전체-상품-조회-검색-단일-상품-상세-조회-풀-소스코드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#8-1-%EC%A0%84%EC%B2%B4-%EC%83%81%ED%92%88-%EC%A1%B0%ED%9A%8C-%EA%B2%80%EC%83%89-%EB%8B%A8%EC%9D%BC-%EC%83%81%ED%92%88-%EC%83%81%EC%84%B8-%EC%A1%B0%ED%9A%8C-%ED%92%80-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;from fastapi import FastAPI, Path, Query

app = FastAPI(
    title=&quot;이커머스 상품 관리 API&quot;,
    description=&quot;FastAPI 기초 학습을 위한 상품 조회 및 검색 엔드포인트&quot;,
    version=&quot;1.0.0&quot;
)

# 인메모리 가상 상품 데이터베이스
ITEMS = [
    {&quot;id&quot;: 1, &quot;name&quot;: &quot;apple&quot;, &quot;price&quot;: 1000},
    {&quot;id&quot;: 2, &quot;name&quot;: &quot;banana&quot;, &quot;price&quot;: 2000},
    {&quot;id&quot;: 3, &quot;name&quot;: &quot;cherry&quot;, &quot;price&quot;: 3000},
]

# 1. 전체 상품 조회 API
@app.get(&quot;/items&quot;, summary=&quot;전체 상품 조회 API&quot;)
def get_items_handler():
    &quot;&quot;&quot;등록된 모든 상품의 리스트를 반환합니다.&quot;&quot;&quot;
    return ITEMS


# 2. 상품 검색 API (고정 경로이므로 {item_id}보다 무조건 먼저 선언해야 함!)
@app.get(&quot;/items/search&quot;, summary=&quot;상품 검색 API&quot;)
def search_items_handler(
    q: str = Query(..., min_length=2, description=&quot;검색할 상품 키워드 (2자 이상)&quot;)
):
    &quot;&quot;&quot;
    상품 이름에 검색 키워드(q)가 포함된 상품 목록을 필터링하여 반환합니다.
    예: /items/search?q=ap -&amp;gt; apple 상품 반환
    &quot;&quot;&quot;
    searched = []
    for item in ITEMS:
        if q.lower() in item[&quot;name&quot;].lower():
            searched.append(item)
    return searched


# 3. 단일 상품 상세 조회 API (변수 경로이므로 search보다 아래에 배치)
@app.get(&quot;/items/{item_id}&quot;, summary=&quot;단일 상품 상세 조회 API&quot;)
def get_item_detail_handler(
    item_id: int = Path(..., ge=1, le=3, description=&quot;조회할 상품의 ID (1~3 범위)&quot;)
):
    &quot;&quot;&quot;
    고유 item_id를 받아 해당하는 단일 상품 정보를 반환합니다.
    인덱스는 0부터 시작하므로 item_id - 1로 접근합니다.
    &quot;&quot;&quot;
    return ITEMS[item_id - 1]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-2. Swagger UI 대시보드 테스트 및 유효성 에러 분석&lt;/h3&gt;
&lt;a id=&quot;user-content-8-2-swagger-ui-대시보드-테스트-및-유효성-에러-분석&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#8-2-swagger-ui-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%8F-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EC%97%90%EB%9F%AC-%EB%B6%84%EC%84%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 실행 후&lt;span&gt;&amp;nbsp;&lt;/span&gt;http://localhost:8000/docs에 접속하면 아래와 같은 화면이 나타납니다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;776&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZks8t/dJMcaaUIf3J/4q1U9fGy7pz6sKvOQRaD30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZks8t/dJMcaaUIf3J/4q1U9fGy7pz6sKvOQRaD30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZks8t/dJMcaaUIf3J/4q1U9fGy7pz6sKvOQRaD30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZks8t%2FdJMcaaUIf3J%2F4q1U9fGy7pz6sKvOQRaD30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;645&quot; height=&quot;353&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;OpenAPI 3.1 스키마 준수&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;summary로 지정한 한글 설명이 엔드포인트 오른쪽에 깔끔하게 노출됩니다.&lt;/li&gt;
&lt;li&gt;파라미터 타입, 제약조건(min_length, ge, le), 필수 여부가 표 형태로 일목요연하게 표시됩니다.&lt;/li&gt;
&lt;li&gt;잘못된 값을 넣고&lt;span&gt;&amp;nbsp;&lt;/span&gt;Execute를 실행하면 FastAPI 엔진이 자동으로 검증 실패(422 HTTPValidationError)를 반환하는 것을 브라우저에서 즉시 체험할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-9--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/FastAPI/day1/fastapi-fundamentals-api-serving-note.md#9--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;sql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│                   FastAPI 기초 &amp;amp; 서빙 핵심 치트시트                    │
├──────────────────────────────┬─────────────────────────────────────────┤
│ 명령어 / 문법                │ 기능 및 핵심 사용 공식                  │
├──────────────────────────────┼─────────────────────────────────────────┤
│ python -m venv .venv         │ 프로젝트 전용 독립 가상환경 생성        │
├──────────────────────────────┼─────────────────────────────────────────┤
│ source .venv/bin/activate    │ 가상환경 활성화 (Windows: Scripts\activate)│
├──────────────────────────────┼─────────────────────────────────────────┤
│ pip install &quot;fastapi[standard]&quot;│ FastAPI + Uvicorn + CLI 통합 설치     │
├──────────────────────────────┼─────────────────────────────────────────┤
│ fastapi dev main.py          │ 핫 리로드 지원 로컬 개발 서버 구동      │
├──────────────────────────────┼─────────────────────────────────────────┤
│ localhost:8000               │ 외부로 나가지 않는 내 컴퓨터 내부 루프백│
├──────────────────────────────┼─────────────────────────────────────────┤
│ /docs                        │ Swagger UI 대화형 API 테스트 문서       │
├──────────────────────────────┼─────────────────────────────────────────┤
│ /redoc                       │ ReDoc 읽기 전용 공식 기술 문서         │
├──────────────────────────────┼─────────────────────────────────────────┤
│ @app.get(&quot;/경로&quot;)            │ 함수를 HTTP 엔드포인트로 등록하는 데코레이터│
├──────────────────────────────┼─────────────────────────────────────────┤
│ return {...} / [...]         │ 파이썬 딕셔너리/리스트를 자동 JSON 직렬화│
├──────────────────────────────┼─────────────────────────────────────────┤
│ {item_id}: int               │ Path Parameter (리소스 고유 식별용)     │
├──────────────────────────────┼─────────────────────────────────────────┤
│ 라우팅 선언 공식             │ 정적 경로(/search)를 항상 변수 경로      │
│                              │ (/{item_id})보다 먼저 위에 선언할 것!  │
├──────────────────────────────┼─────────────────────────────────────────┤
│ q: str                       │ Query Parameter (필수 검색어)           │
├──────────────────────────────┼─────────────────────────────────────────┤
│ limit: int = 10              │ Query Parameter (기본값 있는 선택 옵션) │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Path(..., ge=1, le=100)      │ 경로 매개변수 범위 및 유효성 검사       │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Query(..., min_length=2)     │ 쿼리 매개변수 글자수 및 조건 강제       │
├──────────────────────────────┼─────────────────────────────────────────┤
│ 422 Unprocessable Entity     │ 타입 검증 실패 시 자동 반환되는 HTTP 에러│
└──────────────────────────────┴─────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/34</guid>
      <comments>https://write31991.tistory.com/34#entry34comment</comments>
      <pubDate>Wed, 21 Oct 2026 17:09:26 +0900</pubDate>
    </item>
    <item>
      <title>HTML/CSS &amp;amp; Javascript 8일차</title>
      <link>https://write31991.tistory.com/33</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-has-sidebar=&quot;true&quot; data-component=&quot;SplitPageLayout&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div data-is-hidden-narrow=&quot;false&quot; data-component=&quot;SplitPageLayout.Content&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div id=&quot;repos-split-pane-content&quot; data-selector=&quot;repos-split-pane-content&quot;&gt;
&lt;div data-hpc=&quot;true&quot;&gt;
&lt;div&gt;
&lt;h1&gt;  JavaScript Web API 완벽 정리 노트: Timer, Storage &amp;amp; Fetch API&lt;/h1&gt;
&lt;a id=&quot;user-content--javascript-web-api-완벽-정리-노트-timer-storage--fetch-api&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#-javascript-web-api-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8-timer-storage--fetch-api&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저가 제공하는 강력한 도구 상자 **Web API의 핵심 3대장(Timer API, Web Storage API, Fetch API)**을 총정리한 실전 가이드입니다.&lt;br /&gt;&lt;b&gt;setInterval과&lt;span&gt;&amp;nbsp;&lt;/span&gt;timerId를 활용한 카운트다운 타이머&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;LocalStorage vs SessionStorage의 수명&amp;middot;보안&amp;middot;객체 직렬화&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;비동기(Asynchronous) 통신의 원리와&lt;span&gt;&amp;nbsp;&lt;/span&gt;.then()&lt;span&gt;&amp;nbsp;&lt;/span&gt;체이닝의 진실&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;GET/POST 통신과 얼리 리턴(Early Return) 최적화&lt;/b&gt;, 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;클라이언트 캐싱과 모던 프레임워크 상태 관리&lt;/b&gt;까지 한 번에 정리합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#1-timer-api-%EC%A3%BC%EA%B8%B0%EC%A0%81-%EC%8B%A4%ED%96%89%EA%B3%BC-%EC%A0%9C%EC%96%B4-setinterval--timerid&quot;&gt;Timer API: 주기적 실행과 제어 (setInterval &amp;amp; timerId)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#1-1-setinterval%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90%EA%B3%BC-1%EC%B4%88-%EC%A3%BC%EA%B8%B0-%EC%8B%A4%ED%96%89&quot;&gt;1-1. setInterval의 기본 개념과 1초 주기 실행&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#1-2-timerid%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-clearinterval&quot;&gt;1-2. timerId의 본질과 clearInterval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#1-3-%EC%8B%A4%EC%8A%B5-1-5%EC%B4%88-%EC%B9%B4%EC%9A%B4%ED%8A%B8%EB%8B%A4%EC%9A%B4-%ED%83%80%EC%9D%B4%EB%A8%B8%EC%99%80-%EB%B2%84%ED%8A%BC-%EC%97%B0%ED%83%80-%EB%B0%A9%EC%A7%80-%EA%B0%80%EB%93%9C&quot;&gt;1-3. [실습 1] 5초 카운트다운 타이머와 버튼 연타 방지 가드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-web-storage-api-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%A0%80%EC%9E%A5%EC%86%8C-localstorage-vs-sessionstorage&quot;&gt;Web Storage API: 브라우저 저장소 (LocalStorage vs SessionStorage)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-1-web-storage%EC%9D%98-%ED%8A%B9%EC%A7%95-key-value--%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%A0%80%EC%9E%A5&quot;&gt;2-1. Web Storage의 특징 (Key-Value &amp;amp; 문자열 저장)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-2-localstorage-vs-sessionstorage-%EC%99%84%EB%B2%BD-%EB%B9%84%EA%B5%90&quot;&gt;2-2. LocalStorage vs SessionStorage 완벽 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-3-%ED%95%B5%EC%8B%AC-%EB%A9%94%EC%84%9C%EB%93%9C-4%EC%B4%9D%EC%82%AC-setitem-getitem-removeitem-clear&quot;&gt;2-3. 핵심 메서드 4총사 (setItem, getItem, removeItem, clear)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-4-%EA%B0%9D%EC%B2%B4object-%EC%A0%80%EC%9E%A5%EC%9D%98-%ED%95%84%EC%88%98-%EA%B3%B5%EC%8B%9D-json-%EC%A7%81%EB%A0%AC%ED%99%94--%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94&quot;&gt;2-4. 객체(Object) 저장의 필수 공식: JSON 직렬화 &amp;amp; 역직렬화&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-5-%EC%8B%A4%EC%8A%B5-2-%EC%83%88%EB%A1%9C%EA%B3%A0%EC%B9%A8%ED%95%B4%EB%8F%84-%EC%9C%A0%EC%A7%80%EB%90%98%EB%8A%94-%EC%9E%85%EB%A0%A5%EA%B0%92-%EC%A0%80%EC%9E%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8&quot;&gt;2-5. [실습 2] 새로고침해도 유지되는 입력값 저장 프로그램&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#3-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80-%EB%B3%B4%EC%95%88--%EA%B3%B5%EC%9A%A9-pc-%ED%95%84%EC%88%98-%EB%B3%B4%EC%95%88-%EC%88%98%EC%B9%99&quot;&gt;브라우저 스토리지 보안 &amp;amp; 공용 PC 필수 보안 수칙&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#3-1-%EC%8B%9C%ED%81%AC%EB%A6%BF-%EB%AA%A8%EB%93%9C-incognito-mode%EC%9D%98-%EC%9E%A5%EC%A0%90%EA%B3%BC-%EC%9B%90%EB%A6%AC&quot;&gt;3-1. 시크릿 모드 (Incognito Mode)의 장점과 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#3-2-%EA%B3%B5%EC%9A%A9-pc-%EC%82%AC%EC%9A%A9-%EC%8B%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EA%BC%AD-%EC%A7%80%EC%BC%9C%EC%95%BC-%ED%95%A0-3%EB%8C%80-%EB%B3%B4%EC%95%88-%EC%8A%B5%EA%B4%80&quot;&gt;3-2. 공용 PC 사용 시 개발자가 꼭 지켜야 할 3대 보안 습관&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-fetch-api%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0asynchronous-%ED%86%B5%EC%8B%A0%EC%9D%98-%EB%B3%B8%EC%A7%88&quot;&gt;Fetch API와 비동기(Asynchronous) 통신의 본질&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-1-fetch-api%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;4-1. Fetch API란 무엇인가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-2-%EB%B9%84%EB%8F%99%EA%B8%B0asynchronous%EC%9D%98-%ED%95%B5%EC%8B%AC-%EC%99%9C-let-response--fetch%EB%8A%94-%EC%95%88-%EB%90%A0%EA%B9%8C&quot;&gt;4-2. 비동기(Asynchronous)의 핵심: 왜 let response = fetch()는 안 될까?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-3-then-%EC%B2%B4%EC%9D%B4%EB%8B%9D%EC%9D%98-%EC%A7%84%EC%8B%A4-%EC%88%9C%EC%84%9C%EB%8C%80%EB%A1%9C-%EC%8B%A4%ED%96%89%EB%90%98%EB%8A%94%EB%8D%B0-%EC%99%9C-100-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%9D%B8%EA%B0%80&quot;&gt;4-3. .then() 체이닝의 진실: &quot;순서대로 실행되는데 왜 100% 비동기인가?&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-4-%EB%A7%8C%EC%95%BD-%ED%86%B5%EC%8B%A0%EC%9D%B4-%EB%8F%99%EA%B8%B0synchronous%EC%98%80%EB%8B%A4%EB%A9%B4-%EB%B2%8C%EC%96%B4%EC%A7%80%EB%8A%94-%EB%81%94%EC%B0%8D%ED%95%9C-%EC%9D%BC&quot;&gt;4-4. 만약 통신이 '동기(Synchronous)'였다면 벌어지는 끔찍한 일&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#5-fetch-api-%EA%B8%B0%EB%B3%B8-%EC%82%AC%EC%9A%A9%EB%B2%95-get-%EC%9A%94%EC%B2%AD--dom-%EB%A0%8C%EB%8D%94%EB%A7%81&quot;&gt;Fetch API 기본 사용법 (GET 요청 &amp;amp; DOM 렌더링)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#5-1-get-%EC%9A%94%EC%B2%AD-4%EB%8B%A8%EA%B3%84-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4&quot;&gt;5-1. GET 요청 4단계 라이프사이클&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#5-2-%EC%8B%A4%EC%8A%B5-3-%EB%B2%84%ED%8A%BC-%ED%81%B4%EB%A6%AD-%EC%8B%9C-%EA%B2%8C%EC%8B%9C%EA%B8%80-5%EA%B0%9C-%EC%A1%B0%ED%9A%8C%ED%95%98%EC%97%AC-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EB%A0%8C%EB%8D%94%EB%A7%81&quot;&gt;5-2. [실습 3] 버튼 클릭 시 게시글 5개 조회하여 리스트 렌더링&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#6-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%B5%9C%EC%A0%81%ED%99%94--%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4-early-return&quot;&gt;데이터 렌더링 최적화 &amp;amp; 얼리 리턴 (Early Return)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#6-1-%EC%A4%91%EB%B3%B5-%EC%B6%9C%EB%A0%A5-%EB%AC%B8%EC%A0%9C-%EB%B0%9C%EC%83%9D%EA%B3%BC-4%EA%B0%80%EC%A7%80-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95&quot;&gt;6-1. 중복 출력 문제 발생과 4가지 해결 방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#6-2-%EC%99%9C-1%EB%B2%88innerhtml%EB%B3%B4%EB%8B%A4-2%EB%B2%88early-return%EC%9D%B4-%ED%9B%A8%EC%94%AC-%EB%9B%B0%EC%96%B4%EB%82%9C%EA%B0%80&quot;&gt;6-2. 왜 1번(innerHTML=&quot;&quot;)보다 2번(Early Return)이 훨씬 뛰어난가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#6-3-%ED%95%9C-%EA%B1%B8%EC%9D%8C-%EB%8D%94-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%BA%90%EC%8B%B1-client-caching-%EA%B3%A0%EB%8F%84%ED%99%94&quot;&gt;6-3. 한 걸음 더: 클라이언트 메모리 캐싱 (Client Caching) 고도화&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#7-fetch-api-post-%EC%9A%94%EC%B2%AD%EC%9C%BC%EB%A1%9C-%EC%84%9C%EB%B2%84%EC%97%90-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%86%A1&quot;&gt;Fetch API: POST 요청으로 서버에 데이터 전송&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#7-1-post-%EC%9A%94%EC%B2%AD%EC%9D%98-3%EB%8C%80-%ED%95%84%EC%88%98-%EC%9A%94%EC%86%8C-method-headers-body&quot;&gt;7-1. POST 요청의 3대 필수 요소 (method, headers, body)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#7-2-%EC%8B%A4%EC%8A%B5-4-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%A0%84%EC%86%A1-%EB%B0%8F-json-%EC%9D%91%EB%8B%B5-%EA%B0%80%EB%8F%85%EC%84%B1-%EC%B6%9C%EB%A0%A5-null-2&quot;&gt;7-2. [실습 4] 이메일 전송 및 JSON 응답 가독성 출력 (null, 2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#8-%EC%A2%85%ED%95%A9-%EC%B5%9C%EC%A2%85-%EC%8B%A4%EC%8A%B5-to-do-%EC%95%B1--%EB%AA%A8%EB%8D%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC&quot;&gt;종합 최종 실습: To-do 앱 &amp;amp; 모던 프레임워크 상태 관리&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#8-1-web-api-%EC%82%BC%EC%B4%9D%EC%82%ACdom--storage--fetch%EC%9D%98-%EC%9C%B5%ED%95%A9&quot;&gt;8-1. Web API 삼총사(DOM + Storage + Fetch)의 융합&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#8-2-%EB%B0%94%EB%8B%90%EB%9D%BC-js%EC%9D%98-%ED%95%9C%EA%B3%84%EC%99%80-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACreact-nextjs-vuejs%EB%A1%9C%EC%9D%98-%ED%99%95%EC%9E%A5&quot;&gt;8-2. 바닐라 JS의 한계와 프레임워크(React, Next.js, Vue.js)로의 확장&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#9--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Timer API: 주기적 실행과 제어 (setInterval &amp;amp; timerId)&lt;/h2&gt;
&lt;a id=&quot;user-content-1-timer-api-주기적-실행과-제어-setinterval--timerid&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#1-timer-api-%EC%A3%BC%EA%B8%B0%EC%A0%81-%EC%8B%A4%ED%96%89%EA%B3%BC-%EC%A0%9C%EC%96%B4-setinterval--timerid&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. setInterval의 기본 개념과 1초 주기 실행&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-setinterval의-기본-개념과-1초-주기-실행&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#1-1-setinterval%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90%EA%B3%BC-1%EC%B4%88-%EC%A3%BC%EA%B8%B0-%EC%8B%A4%ED%96%89&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;setInterval(callback, delay)&lt;/b&gt;: 브라우저 Web API로, 지정한 시간(밀리초, ms) 간격마다 등록된 콜백 함수를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;무한히 반복 실행&lt;/b&gt;합니다. (1000ms = 1초)&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 1초(1000ms)마다 주기적으로 콘솔에 메시지 출력
setInterval(function () {
  console.log(&quot;1초마다 실행&quot;);
}, 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. timerId의 본질과 clearInterval&lt;/h3&gt;
&lt;a id=&quot;user-content-1-2-timerid의-본질과-clearinterval&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#1-2-timerid%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-clearinterval&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;timerId&lt;/b&gt;: 브라우저 엔진이 활성화된 타이머들을 고유하게 식별하기 위해 발급해 주는 **식별 번호(ID)**입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;필요성&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;반복 실행 중인 타이머를 원하는 시점에 종료(clearInterval)하기 위해.&lt;/li&gt;
&lt;li&gt;사용자가 시작 버튼을 여러 번 연속으로 눌렀을 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타이머가 중복 생성되어 카운트 속도가 비정상적으로 빨라지는 버그를 사전에 방지&lt;/b&gt;하기 위해.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 타이머를 실행하고 고유 식별 번호를 timerId 변수에 저장
const timerId = setInterval(function () {
  console.log(&quot;실행&quot;);
}, 1000);

// 특정 조건 도달 시 타이머 중단
clearInterval(timerId);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3. [실습 1] 5초 카운트다운 타이머와 버튼 연타 방지 가드&lt;/h3&gt;
&lt;a id=&quot;user-content-1-3-실습-1-5초-카운트다운-타이머와-버튼-연타-방지-가드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#1-3-%EC%8B%A4%EC%8A%B5-1-5%EC%B4%88-%EC%B9%B4%EC%9A%B4%ED%8A%B8%EB%8B%A4%EC%9A%B4-%ED%83%80%EC%9D%B4%EB%A8%B8%EC%99%80-%EB%B2%84%ED%8A%BC-%EC%97%B0%ED%83%80-%EB%B0%A9%EC%A7%80-%EA%B0%80%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: &quot;카운트다운 시작&quot; 버튼을 클릭하면 5초부터 1초마다 숫자가 감소하고, 0초가 되면 타이머가 멈추며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;끝&quot;을 출력하는 타이머를 작성하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;1376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcMEDw/dJMcadKDnwF/76H8CDkhxGIRpjF1FnnuI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcMEDw/dJMcadKDnwF/76H8CDkhxGIRpjF1FnnuI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcMEDw/dJMcadKDnwF/76H8CDkhxGIRpjF1FnnuI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcMEDw%2FdJMcadKDnwF%2F76H8CDkhxGIRpjF1FnnuI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;262&quot; height=&quot;675&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;1376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#html&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;button id=&quot;start&quot;&amp;gt;카운트다운 시작&amp;lt;/button&amp;gt;
&amp;lt;p id=&quot;result&quot;&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#javascript&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const startBtn = document.querySelector(&quot;#start&quot;);
const timeEl = document.querySelector(&quot;#result&quot;);

let time = 5;
let timerId = null; // 현재 타이머가 돌고 있는지 체크하는 상태값

startBtn.addEventListener(&quot;click&quot;, function () {
  //   [버튼 연타 방지 가드 / Early Return]
  // 이미 실행 중이면 추가 타이머를 만들지 않고 즉시 함수 종료!
  if (timerId !== null) return;

  // 시작 즉시 현재 시간 표시
  timeEl.textContent = time;

  // 1초마다 실행되는 타이머 등록
  timerId = setInterval(function () {
    time--; // 1초 감소

    if (time === 0) {
      // 0초가 되면 카운트다운 종료
      timeEl.textContent = &quot;끝&quot;;
      clearInterval(timerId); // 타이머 반복 중단!
      timerId = null;         // 상태를 null로 리셋하여 다시 시작 가능하게 함
      time = 5;               // 다음 실행을 위해 시간 복구
    } else {
      timeEl.textContent = time; // 4, 3, 2, 1 화면 갱신
    }
  }, 1000);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Web Storage API: 브라우저 저장소 (LocalStorage vs SessionStorage)&lt;/h2&gt;
&lt;a id=&quot;user-content-2-web-storage-api-브라우저-저장소-localstorage-vs-sessionstorage&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-web-storage-api-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%A0%80%EC%9E%A5%EC%86%8C-localstorage-vs-sessionstorage&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. Web Storage의 특징 (Key-Value &amp;amp; 문자열 저장)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-1-web-storage의-특징-key-value--문자열-저장&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-1-web-storage%EC%9D%98-%ED%8A%B9%EC%A7%95-key-value--%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%A0%80%EC%9E%A5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저가 클라이언트(사용자 컴퓨터) 환경에 제공하는 내장 데이터 저장소입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3대 핵심 특징&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;서버 없는 로컬 데이터 보관&lt;/b&gt;: 데이터베이스(DB)나 백엔드 서버 없이도 브라우저 자체에 데이터를 저장하고 조회할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Key - Value 구조&lt;/b&gt;: 데이터는 언제나 고유한 이름(Key)과 실제 값(Value)의 쌍으로 저장됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;값은 항상 문자열(String)&lt;/b&gt;: 숫자, 불리언, 객체, 배열 등 어떤 데이터를 넣어도 내부적으로는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문자열 형태&lt;/b&gt;로만 저장됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. LocalStorage vs SessionStorage 완벽 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-localstorage-vs-sessionstorage-완벽-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-2-localstorage-vs-sessionstorage-%EC%99%84%EB%B2%BD-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 스토리지의 두 축인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;로컬 스토리지&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;세션 스토리지&lt;/b&gt;의 결정적 차이는 **데이터의 수명(지속성)**과 **공유 범위(Scope)**입니다.&lt;/p&gt;
&amp;nbsp; &amp;nbsp;구분&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  로컬 스토리지 (Local Storage)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ⏳ 세션 스토리지 (Session Storage)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;데이터 수명 (지속성)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;영구적 (Permanent)&lt;/b&gt;&lt;br /&gt;사용자가 직접 삭제하거나 코드로 지우지 않는 한 브라우저를 닫거나 컴퓨터를 재부팅해도 보존됨&lt;/td&gt;
&lt;td&gt;&lt;b&gt;임시적 (Temporary)&lt;/b&gt;&lt;br /&gt;해당 탭(Tab) 또는 브라우저 창을 닫는 즉시 메모리에서 영구 삭제됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;공유 범위 (Scope)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;동일 도메인(Origin) 전체 공유&lt;/b&gt;&lt;br /&gt;새 탭, 새 창을 여러 개 열어도 동일한 도메인이면 데이터가 실시간 공유됨&lt;/td&gt;
&lt;td&gt;&lt;b&gt;해당 탭(Tab) 단독 독립 공간&lt;/b&gt;&lt;br /&gt;같은 사이트라도 탭마다 별개의 세션이 생성되며 서로 데이터를 공유하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;만료 시간&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;없음 (수동 삭제 전까지 영구 유지)&lt;/td&gt;
&lt;td&gt;탭 종료 시 자동 소멸&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;대표 활용 예시&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&amp;bull; 자동 로그인 토큰/아이디 기억&lt;br /&gt;&amp;bull; 다크 모드 / 라이트 모드 테마 설정&lt;br /&gt;&amp;bull; 비회원 장바구니 목록 보관&lt;/td&gt;
&lt;td&gt;&amp;bull; 일회성 설문조사 / 회원가입 폼 임시 데이터&lt;br /&gt;&amp;bull; 은행 / 금융 웹사이트 일회성 로그인 세션&lt;br /&gt;&amp;bull; 이전 페이지 뒤로가기 시 복구할 임시 UI 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. 핵심 메서드 4총사 (setItem, getItem, removeItem, clear)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-3-핵심-메서드-4총사-setitem-getitem-removeitem-clear&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-3-%ED%95%B5%EC%8B%AC-%EB%A9%94%EC%84%9C%EB%93%9C-4%EC%B4%9D%EC%82%AC-setitem-getitem-removeitem-clear&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;localStorage와&lt;span&gt;&amp;nbsp;&lt;/span&gt;sessionStorage는 사용하는 메서드 이름과 문법이 100% 동일합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 1. 데이터 저장 (Key, Value)
localStorage.setItem(&quot;name&quot;, &quot;Alex&quot;);
localStorage.setItem(&quot;theme&quot;, &quot;dark&quot;);

// 2. 데이터 조회 (Key)
const username = localStorage.getItem(&quot;name&quot;);
console.log(username); // &quot;Alex&quot;
// ⚠️ 존재하지 않는 Key를 조회하면 null을 반환합니다.

// 3. 특정 데이터 1개 삭제 (Key)
localStorage.removeItem(&quot;name&quot;);

// 4. 스토리지 전체 데이터 비우기 (초기화)
localStorage.clear();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-4. 객체(Object) 저장의 필수 공식: JSON 직렬화 &amp;amp; 역직렬화&lt;/h3&gt;
&lt;a id=&quot;user-content-2-4-객체object-저장의-필수-공식-json-직렬화--역직렬화&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-4-%EA%B0%9D%EC%B2%B4object-%EC%A0%80%EC%9E%A5%EC%9D%98-%ED%95%84%EC%88%98-%EA%B3%B5%EC%8B%9D-json-%EC%A7%81%EB%A0%AC%ED%99%94--%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #9a6700;&quot; data-ke-size=&quot;size16&quot;&gt;Warning&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;스토리지에 객체를 그냥 넣으면 발생하는 대참사!&lt;/b&gt;&lt;br /&gt;localStorage.setItem(&quot;user&quot;, { name: &quot;Alex&quot; });&lt;br /&gt;위 코드를 실행하면 자바스크립트는 객체를 문자열로 강제 변환하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;[object Object]&quot;라는 쓸모없는 문자열로 저장해버립니다!&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;해결책&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장할 때:&lt;span&gt;&amp;nbsp;&lt;/span&gt;JSON.stringify(객체)를 사용해 객체를 **JSON 문자열로 직렬화(Serialization)**하여 저장.&lt;/li&gt;
&lt;li&gt;꺼낼 때:&lt;span&gt;&amp;nbsp;&lt;/span&gt;JSON.parse(문자열)를 사용해 JSON 문자열을 **다시 자바스크립트 객체로 역직렬화(Deserialization)**하여 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const user = { name: &quot;Alex&quot;, age: 20 };

// 1. 객체를 JSON 문자열로 변환하여 저장: '{&quot;name&quot;:&quot;Alex&quot;,&quot;age&quot;:20}'
localStorage.setItem(&quot;user&quot;, JSON.stringify(user));

// 2. 스토리지에서 문자열을 꺼내와서 다시 실제 JS 객체로 복원!
const savedUser = JSON.parse(localStorage.getItem(&quot;user&quot;));

console.log(savedUser.name); // &quot;Alex&quot;
console.log(savedUser.age);  // 20&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-5. [실습 2] 새로고침해도 유지되는 입력값 저장 프로그램&lt;/h3&gt;
&lt;a id=&quot;user-content-2-5-실습-2-새로고침해도-유지되는-입력값-저장-프로그램&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#2-5-%EC%8B%A4%EC%8A%B5-2-%EC%83%88%EB%A1%9C%EA%B3%A0%EC%B9%A8%ED%95%B4%EB%8F%84-%EC%9C%A0%EC%A7%80%EB%90%98%EB%8A%94-%EC%9E%85%EB%A0%A5%EA%B0%92-%EC%A0%80%EC%9E%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: 이름을 입력하고 &quot;저장&quot; 버튼을 누르면 화면에 출력되고, 브라우저를 새로고침(F5)해도 이전 입력값이 그대로 남아있도록 구현하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html-1&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#html-1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;input id=&quot;name&quot; placeholder=&quot;이름 입력&quot; /&amp;gt;
&amp;lt;button id=&quot;save&quot;&amp;gt;저장&amp;lt;/button&amp;gt;
&amp;lt;p id=&quot;result&quot;&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-1&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#javascript-1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;dart&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const input = document.querySelector(&quot;#name&quot;);
const button = document.querySelector(&quot;#save&quot;);
const result = document.querySelector(&quot;#result&quot;);

// 1. [페이지 초기 로드 시점] 스토리지에 기존 저장된 이름이 있는지 확인
const savedName = localStorage.getItem(&quot;name&quot;);
if (savedName) {
  // 저장된 값이 존재하면 결과 문단에 즉시 복원 표시!
  result.textContent = savedName;
}

// 2. [저장 버튼 클릭 시점] 새 입력값을 스토리지에 저장하고 화면 갱신
button.addEventListener(&quot;click&quot;, function () {
  localStorage.setItem(&quot;name&quot;, input.value);
  result.textContent = input.value;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 브라우저 스토리지 보안 &amp;amp; 공용 PC 필수 보안 수칙&lt;/h2&gt;
&lt;a id=&quot;user-content-3-브라우저-스토리지-보안--공용-pc-필수-보안-수칙&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#3-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80-%EB%B3%B4%EC%95%88--%EA%B3%B5%EC%9A%A9-pc-%ED%95%84%EC%88%98-%EB%B3%B4%EC%95%88-%EC%88%98%EC%B9%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 스토리지는 접근이 매우 간편하지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;보안 측면(XSS 공격, 공용 PC 개인정보 유출 등)에서 각별한 주의&lt;/b&gt;가 필요합니다.&lt;/p&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. 시크릿 모드 (Incognito Mode)의 장점과 원리&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1-시크릿-모드-incognito-mode의-장점과-원리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#3-1-%EC%8B%9C%ED%81%AC%EB%A6%BF-%EB%AA%A8%EB%93%9C-incognito-mode%EC%9D%98-%EC%9E%A5%EC%A0%90%EA%B3%BC-%EC%9B%90%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;모든 흔적 완전 차단&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시크릿 모드에서는 방문 기록, 검색 기록, 쿠키, 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;로컬/세션 스토리지 데이터가 창을 닫는 순간 브라우저 메모리에서 깨끗하게 소멸&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동 로그인 방지&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 일반 모드의 쿠키나 저장된 세션이 적용되지 않으며, 아이디/비밀번호 자동 완성이 비활성화되어 다음 사용자가 내 계정에 접근하는 위험을 원천 차단합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. 공용 PC 사용 시 개발자가 꼭 지켜야 할 3대 보안 습관&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2-공용-pc-사용-시-개발자가-꼭-지켜야-할-3대-보안-습관&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#3-2-%EA%B3%B5%EC%9A%A9-pc-%EC%82%AC%EC%9A%A9-%EC%8B%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EA%BC%AD-%EC%A7%80%EC%BC%9C%EC%95%BC-%ED%95%A0-3%EB%8C%80-%EB%B3%B4%EC%95%88-%EC%8A%B5%EA%B4%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEYJyr/dJMcahmasXV/8vg3Ll9kvCldOBALu4YnOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEYJyr/dJMcahmasXV/8vg3Ll9kvCldOBALu4YnOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEYJyr/dJMcahmasXV/8vg3Ll9kvCldOBALu4YnOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEYJyr%2FdJMcahmasXV%2F8vg3Ll9kvCldOBALu4YnOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;499&quot; height=&quot;156&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;로그인 계정 직접 로그아웃&lt;/b&gt;:&lt;br /&gt;구글 드라이브, 깃허브 등 민감한 서비스는 단순히 탭이나 창만 닫지 말고, 반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;[로그아웃] 버튼을 직접 눌러 서버 세션을 무효화&lt;/b&gt;해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;브라우저 비밀번호 저장 팝업 주의&lt;/b&gt;:&lt;br /&gt;&quot;비밀번호를 저장하시겠습니까?&quot; 팝업이 뜰 때 실수로 '저장'을 누르면 공용 PC의 브라우저 프로필에 평문으로 남을 수 있으므로 반드시 '저장 안 함'을 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발자 도구(F12) 테스트 후 완전 종료&lt;/b&gt;:&lt;br /&gt;테스트나 학습 목적으로 공용 PC의 F12 Application 탭에서 스토리지를 조작했다면, 작업 직후&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 창 전체를 완전히 닫아&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;임시 데이터와 세션을 깔끔히 초기화해야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Fetch API와 비동기(Asynchronous) 통신의 본질&lt;/h2&gt;
&lt;a id=&quot;user-content-4-fetch-api와-비동기asynchronous-통신의-본질&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-fetch-api%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0asynchronous-%ED%86%B5%EC%8B%A0%EC%9D%98-%EB%B3%B8%EC%A7%88&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. Fetch API란 무엇인가?&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-fetch-api란-무엇인가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-1-fetch-api%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저가 자바스크립트에게 제공하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최신 표준 서버 통신용 Web API&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;웹 페이지가 화면 전체를 새로고침하지 않고도 백엔드 서버에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTTP 요청(Request)을 보내고 응답(Response)을 수신&lt;/b&gt;할 수 있게 해줍니다.&lt;/li&gt;
&lt;li&gt;내부적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;비동기(Asynchronous)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식으로 작동합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. 비동기(Asynchronous)의 핵심: 왜&lt;span&gt;&amp;nbsp;&lt;/span&gt;let response = fetch()는 안 될까?&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-비동기asynchronous의-핵심-왜-let-response--fetch는-안-될까&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-2-%EB%B9%84%EB%8F%99%EA%B8%B0asynchronous%EC%9D%98-%ED%95%B5%EC%8B%AC-%EC%99%9C-let-response--fetch%EB%8A%94-%EC%95%88-%EB%90%A0%EA%B9%8C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// ❌ 초보자들이 흔히 생각하는 잘못된 동기식 코드 발상
let response = fetch(&quot;https://api.example.com/posts&quot;);
console.log(response); // 서버 데이터가 아니라 Promise 객체가 출력됨!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;왜 바로 변수에 담을 수 없을까?&lt;/h4&gt;
&lt;a id=&quot;user-content-왜-바로-변수에-담을-수-없을까&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#%EC%99%9C-%EB%B0%94%EB%A1%9C-%EB%B3%80%EC%88%98%EC%97%90-%EB%8B%B4%EC%9D%84-%EC%88%98-%EC%97%86%EC%9D%84%EA%B9%8C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;서버 통신은 물리적으로 시간이 걸리는 작업&lt;/b&gt;:&lt;br /&gt;인터넷 네트워크를 타고 저 멀리 있는 서버까지 요청이 갔다가, 서버가 DB를 조회하고 데이터를 돌려주는 데는 수백 밀리초에서 수 초의 시간이 걸립니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자바스크립트의 싱글 스레드(Single Thread) 특성&lt;/b&gt;:&lt;br /&gt;자바스크립트는 한 번에 한 줄씩 코드를 실행합니다. 만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;fetch()가 완료될 때까지 그 자리에서 멈춰서 기다린다면(&lt;b&gt;블로킹 / 동기 방식&lt;/b&gt;), 서버 응답이 올 때까지 웹페이지의 모든 화면 렌더링, 마우스 클릭, 스크롤이 **꽁꽁 얼어붙는 현상(렉/프리즈)**이 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비동기 처리의 철학&lt;/b&gt;:&lt;br /&gt;자바스크립트는 *&quot;서버에 요청을 일단 던져놓고, 기다리는 동안 아래에 있는 다른 코드와 UI 상호작용을 계속하고 있을게! 서버 응답이 도착하면 그때 등록해 둔&lt;span&gt;&amp;nbsp;&lt;/span&gt;.then()&lt;span&gt;&amp;nbsp;&lt;/span&gt;콜백을 깨워서 처리해 줘!&quot;*라는 방식으로 동작합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;.then()&lt;span&gt;&amp;nbsp;&lt;/span&gt;체이닝의 진실: &quot;순서대로 실행되는데 왜 100% 비동기인가?&quot;&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-then-체이닝의-진실-순서대로-실행되는데-왜-100-비동기인가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-3-then-%EC%B2%B4%EC%9D%B4%EB%8B%9D%EC%9D%98-%EC%A7%84%EC%8B%A4-%EC%88%9C%EC%84%9C%EB%8C%80%EB%A1%9C-%EC%8B%A4%ED%96%89%EB%90%98%EB%8A%94%EB%8D%B0-%EC%99%9C-100-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%9D%B8%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q.&lt;span&gt;&amp;nbsp;&lt;/span&gt;.then()&lt;span&gt;&amp;nbsp;&lt;/span&gt;체이닝 코드를 보면 1번이 끝나야 2번이 실행되는 순서 구조인데, 이건 동기 아닌가요?&lt;/b&gt;&lt;br /&gt;&lt;b&gt;A. 결론부터 말하면 코드 외형만 순서대로 적혀있을 뿐, 실제 내부 메커니즘은 100% 비동기(Asynchronous)입니다!&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2228&quot; data-origin-height=&quot;1134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CZ4is/dJMcaiLVuLC/GQdqfDzL9hYGw7NhXa3K0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CZ4is/dJMcaiLVuLC/GQdqfDzL9hYGw7NhXa3K0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CZ4is/dJMcaiLVuLC/GQdqfDzL9hYGw7NhXa3K0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCZ4is%2FdJMcaiLVuLC%2FGQdqfDzL9hYGw7NhXa3K0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;665&quot; height=&quot;338&quot; data-origin-width=&quot;2228&quot; data-origin-height=&quot;1134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;외형 (코드 모양새)&lt;/b&gt;:&lt;br /&gt;개발자의 가독성과 로직 흐름을 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;.then()으로 순서대로 체이닝(Chaining)하여 작성하므로 마치 동기처럼 읽힙니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실제 내부 동작&lt;/b&gt;:&lt;br /&gt;fetch()를 실행하자마자 자바스크립트는 자리를 비켜주고 다른 일을 하다가,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서버 응답이 도착하는 그 특정 타이밍에 맞춰서만 큐에 들어가 차례대로 실행&lt;/b&gt;되므로 명백한 **비동기 흐름 제어(Asynchronous Control Flow)**입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-4. 만약 통신이 '동기(Synchronous)'였다면 벌어지는 끔찍한 일&lt;/h3&gt;
&lt;a id=&quot;user-content-4-4-만약-통신이-동기synchronous였다면-벌어지는-끔찍한-일&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#4-4-%EB%A7%8C%EC%95%BD-%ED%86%B5%EC%8B%A0%EC%9D%B4-%EB%8F%99%EA%B8%B0synchronous%EC%98%80%EB%8B%A4%EB%A9%B4-%EB%B2%8C%EC%96%B4%EC%A7%80%EB%8A%94-%EB%81%94%EC%B0%8D%ED%95%9C-%EC%9D%BC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 자바스크립트 통신이 동기 방식이었다면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 응답에 3초가 걸릴 경우,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;그 3초 동안 웹 브라우저 전체가 멈춥니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;사용자가 버튼을 클릭해도 눌리지 않고, 스크롤도 안 되며, 브라우저는 &quot;페이지가 응답하지 않습니다&quot; 경고창을 띄우게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비동기 통신 덕분에 데이터를 백그라운드에서 가져오는 동안에도 사용자는 로딩 스피너를 보거나 다른 페이지 요소를 자유롭게 조작할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Fetch API 기본 사용법 (GET 요청 &amp;amp; DOM 렌더링)&lt;/h2&gt;
&lt;a id=&quot;user-content-5-fetch-api-기본-사용법-get-요청--dom-렌더링&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#5-fetch-api-%EA%B8%B0%EB%B3%B8-%EC%82%AC%EC%9A%A9%EB%B2%95-get-%EC%9A%94%EC%B2%AD--dom-%EB%A0%8C%EB%8D%94%EB%A7%81&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. GET 요청 4단계 라이프사이클&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-get-요청-4단계-라이프사이클&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#5-1-get-%EC%9A%94%EC%B2%AD-4%EB%8B%A8%EA%B3%84-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;fetch(&quot;https://jsonplaceholder.typicode.com/posts&quot;)
  // 1단계: 서버에 HTTP GET 요청을 보내고 응답 객체(response) 수신
  .then(response =&amp;gt; {
    // 2단계: 응답 객체에서 본문 데이터만 JSON 형태로 추출(파싱)
    return response.json(); 
  })
  // 3단계: JSON 변환이 완료된 순수 자바스크립트 데이터(data) 수령
  .then(data =&amp;gt; {
    // 4단계: 받아온 실제 데이터를 콘솔에 출력하거나 화면(DOM)에 렌더링!
    console.log(data);
  });&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. [실습 3] 버튼 클릭 시 게시글 5개 조회하여 리스트 렌더링&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-실습-3-버튼-클릭-시-게시글-5개-조회하여-리스트-렌더링&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#5-2-%EC%8B%A4%EC%8A%B5-3-%EB%B2%84%ED%8A%BC-%ED%81%B4%EB%A6%AD-%EC%8B%9C-%EA%B2%8C%EC%8B%9C%EA%B8%80-5%EA%B0%9C-%EC%A1%B0%ED%9A%8C%ED%95%98%EC%97%AC-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EB%A0%8C%EB%8D%94%EB%A7%81&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: &quot;불러오기&quot; 버튼을 누르면 JSONPlaceholder API에서 게시글 데이터를 받아와, 상위 5개의&lt;span&gt;&amp;nbsp;&lt;/span&gt;title을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;ul&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;목록 안에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;li&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;태그로 동적 출력하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html-2&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#html-2&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;button id=&quot;load&quot;&amp;gt;불러오기&amp;lt;/button&amp;gt;
&amp;lt;ul id=&quot;list&quot;&amp;gt;&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-2&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#javascript-2&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const button = document.querySelector(&quot;#load&quot;);
const list = document.querySelector(&quot;#list&quot;);

button.addEventListener(&quot;click&quot;, function () {
  fetch(&quot;https://jsonplaceholder.typicode.com/posts&quot;)
    .then(res =&amp;gt; res.json())
    .then(posts =&amp;gt; {
      // 1. 기존 목록 초기화
      list.innerHTML = &quot;&quot;;

      // 2. 전체 데이터 중 0~4번째(5개)만 잘라서 반복문 순회
      for (const post of posts.slice(0, 5)) {
        const li = document.createElement(&quot;li&quot;); // &amp;lt;li&amp;gt;&amp;lt;/li&amp;gt; 생성
        li.textContent = post.title;             // &amp;lt;li&amp;gt;게시글 제목&amp;lt;/li&amp;gt;
        list.appendChild(li);                    // &amp;lt;ul&amp;gt; 안에 추가
      }
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 데이터 렌더링 최적화 &amp;amp; 얼리 리턴 (Early Return)&lt;/h2&gt;
&lt;a id=&quot;user-content-6-데이터-렌더링-최적화--얼리-리턴-early-return&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#6-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%B5%9C%EC%A0%81%ED%99%94--%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4-early-return&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. 중복 출력 문제 발생과 4가지 해결 방법&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-중복-출력-문제-발생과-4가지-해결-방법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#6-1-%EC%A4%91%EB%B3%B5-%EC%B6%9C%EB%A0%A5-%EB%AC%B8%EC%A0%9C-%EB%B0%9C%EC%83%9D%EA%B3%BC-4%EA%B0%80%EC%A7%80-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  문제 발생&lt;/b&gt;:&lt;br /&gt;위 코드에서 '불러오기' 버튼을 계속 누르면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;posts.slice(0, 5)로 똑같은 0~4번 데이터가 리스트 밑으로 끝없이 중복 추가되는 문제가 발생합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4가지 해결 전략 비교:&lt;/h4&gt;
&lt;/div&gt;
&amp;nbsp; &amp;nbsp;해결 방법&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 코드 예시&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;장점 및 평가
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;1. 이전 출력 내용 초기화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;list.innerHTML = &quot;&quot;;&lt;/td&gt;
&lt;td&gt;구현은 단순하나, 버튼을 누를 때마다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;매번 불필요한 서버 통신을 반복&lt;/b&gt;함 (낭비 발생)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;2.   Early Return (조기 반환)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;if (list.innerHTML !== &quot;&quot;) return;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;가장 우수한 방법!&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이미 데이터가 있으면 함수를 즉시 종료하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 요청 자체를 차단&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;3. 버튼 비활성화 (Disable)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;button.disabled = true;&lt;/td&gt;
&lt;td&gt;클릭 1회 완료 후 버튼을 비활성화하여 추가 클릭을 물리적으로 방지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;4. 페이지네이션 (Sliding Window)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;start += 5; end += 5;&lt;br /&gt;posts.slice(start, end)&lt;/td&gt;
&lt;td&gt;누를 때마다 중복이 아닌 **다음 5개(5&lt;s&gt;9, 10&lt;/s&gt;14...)**를 순차적으로 이어서 보여줌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2. 왜 1번(innerHTML=&quot;&quot;)보다 2번(Early Return)이 훨씬 뛰어난가?&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-왜-1번innerhtml보다-2번early-return이-훨씬-뛰어난가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#6-2-%EC%99%9C-1%EB%B2%88innerhtml%EB%B3%B4%EB%8B%A4-2%EB%B2%88early-return%EC%9D%B4-%ED%9B%A8%EC%94%AC-%EB%9B%B0%EC%96%B4%EB%82%9C%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;stata&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;button.addEventListener(&quot;click&quot;, () =&amp;gt; {
  //   [2번 방법: 얼리 리턴 적용]
  // 리스트 안에 이미 글이 채워져 있다면? ➔ 즉시 함수 종료!
  if (list.innerHTML !== &quot;&quot;) {
    return;
  }

  // 데이터가 비어있을 때만 단 1번 서버 통신 실행!
  fetch(&quot;https://jsonplaceholder.typicode.com/posts&quot;)
    .then(response =&amp;gt; response.json())
    .then(posts =&amp;gt; {
      for (const post of posts.slice(0, 5)) {
        const li = document.createElement(&quot;li&quot;);
        li.textContent = post.title;
        list.appendChild(li);
      }
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #1a7f37;&quot; data-ke-size=&quot;size16&quot;&gt;Tip&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;얼리 리턴(Early Return)이 압도적으로 좋은 이유&lt;/b&gt;:&lt;br /&gt;1번 방식(list.innerHTML = &quot;&quot;)은 화면상으로는 깔끔해 보이지만, 버튼을 누를 때마다 100개의 데이터를 서버에서 새로 다운로드하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;극심한 네트워크 대역폭 낭비와 서버 부하&lt;/b&gt;가 발생합니다.&lt;br /&gt;반면 2번 방식은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;조건 검사 후 즉시 return하여 불필요한 fetch 자체를 원천 차단&lt;/b&gt;하므로 성능, 비용, 안정성 모든 면에서 탁월합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-3. 한 걸음 더: 클라이언트 메모리 캐싱 (Client Caching) 고도화&lt;/h3&gt;
&lt;a id=&quot;user-content-6-3-한-걸음-더-클라이언트-메모리-캐싱-client-caching-고도화&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#6-3-%ED%95%9C-%EA%B1%B8%EC%9D%8C-%EB%8D%94-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%BA%90%EC%8B%B1-client-caching-%EA%B3%A0%EB%8F%84%ED%99%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기존 방식의 비효율&lt;/b&gt;: 버튼을 누를 때마다 매번 서버에 새로 요청. (100개를 다 받아와서 5개만 쓰고 버리는 낭비)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고도화된 새로운 방식 (Client Caching)&lt;/b&gt;:&lt;br /&gt;최초 1회만 서버에서 데이터를 통째로 받아와 자바스크립트 변수(브라우저 메모리)에 저장(Cache)해 두고, 이후 버튼을 누를 때는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서버 통신 없이 메모리에 저장된 배열에서 슬라이스(6~10,&lt;span&gt;&amp;nbsp;&lt;/span&gt;11~15)하여 렌더링&lt;/b&gt;합니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;let cachedPosts = null; // 서버에서 받아온 데이터를 보관할 캐시 변수
let startIndex = 0;
const PAGE_SIZE = 5;

button.addEventListener(&quot;click&quot;, async () =&amp;gt; {
  // 1. 최초 1회만 서버에서 fetch로 가져와 캐시에 저장
  if (!cachedPosts) {
    const res = await fetch(&quot;https://jsonplaceholder.typicode.com/posts&quot;);
    cachedPosts = await res.json();
  }

  // 2. 이미 캐시된 데이터가 있으므로 서버 요청 없이 메모리에서 잘라서 출력!
  const currentSlice = cachedPosts.slice(startIndex, startIndex + PAGE_SIZE);
  
  currentSlice.forEach(post =&amp;gt; {
    const li = document.createElement(&quot;li&quot;);
    li.textContent = `${post.id}. ${post.title}`;
    list.appendChild(li);
  });

  startIndex += PAGE_SIZE; // 다음 5개를 위해 인덱스 전진 (Sliding Window)
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. Fetch API: POST 요청으로 서버에 데이터 전송&lt;/h2&gt;
&lt;a id=&quot;user-content-7-fetch-api-post-요청으로-서버에-데이터-전송&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#7-fetch-api-post-%EC%9A%94%EC%B2%AD%EC%9C%BC%EB%A1%9C-%EC%84%9C%EB%B2%84%EC%97%90-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%86%A1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-1. POST 요청의 3대 필수 요소 (method, headers, body)&lt;/h3&gt;
&lt;a id=&quot;user-content-7-1-post-요청의-3대-필수-요소-method-headers-body&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#7-1-post-%EC%9A%94%EC%B2%AD%EC%9D%98-3%EB%8C%80-%ED%95%84%EC%88%98-%EC%9A%94%EC%86%8C-method-headers-body&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET 요청과 달리, 서버에 새로운 리소스를 생성하거나 데이터를 보낼 때는 두 번째 인자로 설정 객체를 전달합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;method&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;POST&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;지정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;headers&lt;/b&gt;: 전송하는 데이터 포맷이 JSON임을 서버에 알림 ({ &quot;Content-Type&quot;: &quot;application/json&quot; })&lt;/li&gt;
&lt;li&gt;&lt;b&gt;body&lt;/b&gt;: 자바스크립트 객체를 전송 가능한 JSON 문자열로 직렬화 (JSON.stringify({ ... }))&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-2. [실습 4] 이메일 전송 및 JSON 응답 가독성 출력 (null, 2)&lt;/h3&gt;
&lt;a id=&quot;user-content-7-2-실습-4-이메일-전송-및-json-응답-가독성-출력-null-2&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#7-2-%EC%8B%A4%EC%8A%B5-4-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%A0%84%EC%86%A1-%EB%B0%8F-json-%EC%9D%91%EB%8B%B5-%EA%B0%80%EB%8F%85%EC%84%B1-%EC%B6%9C%EB%A0%A5-null-2&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: 이메일 입력창의 값을 서버에 POST 방식으로 전송하고, 서버가 반환한 응답 데이터를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;pre&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;태그 안에 들여쓰기가 적용된 JSON 형태로 출력하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html-3&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#html-3&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;email&quot; id=&quot;email&quot; placeholder=&quot;이메일 입력&quot;&amp;gt;
&amp;lt;button id=&quot;send&quot;&amp;gt;전송&amp;lt;/button&amp;gt;
&amp;lt;pre id=&quot;result&quot;&amp;gt;&amp;lt;/pre&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-3&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#javascript-3&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const input = document.querySelector(&quot;#email&quot;);
const button = document.querySelector(&quot;#send&quot;);
const result = document.querySelector(&quot;#result&quot;);

button.addEventListener(&quot;click&quot;, function () {
  fetch(&quot;https://jsonplaceholder.typicode.com/posts&quot;, {
    method: &quot;POST&quot;,
    headers: {
      &quot;Content-Type&quot;: &quot;application/json&quot; // 내가 보내는 데이터는 JSON입니다!
    },
    body: JSON.stringify({
      email: input.value // 객체를 JSON 문자열로 변환하여 전송
    })
  })
    .then(res =&amp;gt; res.json())
    .then(data =&amp;gt; {
      // JSON.stringify의 3번째 인자 2는 들여쓰기 공백 수 (가독성 향상)
      result.textContent = JSON.stringify(data, null, 2);
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 종합 최종 실습: To-do 앱 &amp;amp; 모던 프레임워크 상태 관리&lt;/h2&gt;
&lt;a id=&quot;user-content-8-종합-최종-실습-to-do-앱--모던-프레임워크-상태-관리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#8-%EC%A2%85%ED%95%A9-%EC%B5%9C%EC%A2%85-%EC%8B%A4%EC%8A%B5-to-do-%EC%95%B1--%EB%AA%A8%EB%8D%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-1. Web API 삼총사(DOM + Storage + Fetch)의 융합&lt;/h3&gt;
&lt;a id=&quot;user-content-8-1-web-api-삼총사dom--storage--fetch의-융합&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#8-1-web-api-%EC%82%BC%EC%B4%9D%EC%82%ACdom--storage--fetch%EC%9D%98-%EC%9C%B5%ED%95%A9&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현대 웹 애플리케이션의 핵심인 To-do 앱은 지금까지 배운 Web API들이 유기적으로 결합되어 동작합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;904&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yJOOx/dJMcadqn9Gn/kk8zgAxnGnzPMboHqMaZzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yJOOx/dJMcadqn9Gn/kk8zgAxnGnzPMboHqMaZzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yJOOx/dJMcadqn9Gn/kk8zgAxnGnzPMboHqMaZzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyJOOx%2FdJMcadqn9Gn%2Fkk8zgAxnGnzPMboHqMaZzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;432&quot; height=&quot;368&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;904&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-2. 바닐라 JS의 한계와 프레임워크(React, Next.js, Vue.js)로의 확장&lt;/h3&gt;
&lt;a id=&quot;user-content-8-2-바닐라-js의-한계와-프레임워크react-nextjs-vuejs로의-확장&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#8-2-%EB%B0%94%EB%8B%90%EB%9D%BC-js%EC%9D%98-%ED%95%9C%EA%B3%84%EC%99%80-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACreact-nextjs-vuejs%EB%A1%9C%EC%9D%98-%ED%99%95%EC%9E%A5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;순수 바닐라 자바스크립트의 한계&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터가 변경될 때마다 개발자가 직접&lt;span&gt;&amp;nbsp;&lt;/span&gt;document.querySelector로 요소를 찾고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;createElement와&lt;span&gt;&amp;nbsp;&lt;/span&gt;appendChild를 일일이 명령형(Imperative)으로 호출해야 합니다.&lt;/li&gt;
&lt;li&gt;규모가 커지면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;어떤 코드가 화면의 어떤 부분을 바꾸고 있는지&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;추적하기가 매우 어려워집니다 (스파게티 코드).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모던 프레임워크(React, Vue, Next.js)의 상태 관리(State Management)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;데이터(상태)가 바뀌면 화면은 알아서 자동으로 다시 그려져라!&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;선언형(Declarative) UI&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;패러다임 도입.&lt;/li&gt;
&lt;li&gt;복잡한 DOM 수동 조작에서 벗어나 비즈니스 로직과 데이터 상태 관리에만 집중할 수 있게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-9--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day4/javascript-web-api-storage-fetch-note.md#9--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│              Web API 심화 (Timer &amp;amp; Storage &amp;amp; Fetch) 치트시트           │
├──────────────────────────────┬─────────────────────────────────────────┤
│ API / 문법                   │ 핵심 요약 및 사용 공식                  │
├──────────────────────────────┼─────────────────────────────────────────┤
│ setInterval(fn, ms)          │ ms 간격으로 fn 함수 무한 반복 실행       │
├──────────────────────────────┼─────────────────────────────────────────┤
│ clearInterval(timerId)       │ 실행 중인 setInterval 반복 즉시 중단    │
├──────────────────────────────┼─────────────────────────────────────────┤
│ if (timerId !== null) return;│ 타이머 중복 실행 방지 가드 클로즈       │
├──────────────────────────────┼─────────────────────────────────────────┤
│ localStorage                 │ 브라우저 닫아도 영구 유지 (동일 도메인) │
├──────────────────────────────┼─────────────────────────────────────────┤
│ sessionStorage               │ 현재 탭 닫으면 즉시 삭제 (탭 간 격리)   │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Storage.setItem(&quot;k&quot;, &quot;v&quot;)    │ Key - Value 데이터 저장 (문자열만 가능) │
├──────────────────────────────┼─────────────────────────────────────────┤
│ JSON.stringify(obj)          │ JS 객체를 스토리지 저장용 JSON 문자열로 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ JSON.parse(str)              │ 스토리지의 JSON 문자열을 JS 객체로 복원 │
├──────────────────────────────┼─────────────────────────────────────────┤
│ fetch(url)                   │ 서버와 비동기 HTTP 통신 수행            │
├──────────────────────────────┼─────────────────────────────────────────┤
│ 왜 비동기인가?               │ 서버 응답 대기 중 화면 멈춤(렉) 방지    │
├──────────────────────────────┼─────────────────────────────────────────┤
│ .then(res =&amp;gt; res.json())     │ 서버 응답 바디를 JSON 파싱하여 전달     │
├──────────────────────────────┼─────────────────────────────────────────┤
│ if (list.innerHTML !== &quot;&quot;)   │ 렌더링 중복 방지 &amp;amp; 불필요한 fetch 차단  │
│ return;                      │ (얼리 리턴 최적화)                      │
├──────────────────────────────┼─────────────────────────────────────────┤
│ Client Caching               │ 최초 1회만 fetch 후 메모리에 저장       │
│                              │ 이후 slice()로 서버 요청 횟수 절약      │
├──────────────────────────────┼─────────────────────────────────────────┤
│ fetch POST 필수 3속성        │ method: 'POST',                         │
│                              │ headers: {'Content-Type': 'app/json'},  │
│                              │ body: JSON.stringify({...})             │
├──────────────────────────────┼─────────────────────────────────────────┤
│ JSON.stringify(d, null, 2)   │ 2칸 들여쓰기로 보기 좋게 JSON 출력      │
└──────────────────────────────┴─────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/33</guid>
      <comments>https://write31991.tistory.com/33#entry33comment</comments>
      <pubDate>Wed, 21 Oct 2026 10:29:48 +0900</pubDate>
    </item>
    <item>
      <title>HTML/CSS &amp;amp; Javascript 7일차</title>
      <link>https://write31991.tistory.com/32</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h1&gt;  JavaScript DOM 조작, 이벤트 &amp;amp; Web API 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content--javascript-dom-조작-이벤트--web-api-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#-javascript-dom-%EC%A1%B0%EC%9E%91-%EC%9D%B4%EB%B2%A4%ED%8A%B8--web-api-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 화면을 동적으로 제어하는 **함수의 반환값 규칙(return 생략 시 undefined)**부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DOM의 본질과 트리 구조&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HTML vs JS의 명확한 역할 분담&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DOM 선택 &amp;amp; 스타일&amp;middot;속성 조작&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트 리스너 &amp;amp; 화살표 함수&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;얼리 리턴(Early-Return) 패턴&lt;/b&gt;, 그리고 브라우저가 제공하는 **Web API 5대 분류와 Timer API(카운트다운 실습)**까지 총정리한 실전 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#1-%ED%95%A8%EC%88%98%EC%9D%98-%EB%B0%98%ED%99%98-%EA%B7%9C%EC%B9%99-return%EC%9D%84-%EC%83%9D%EB%9E%B5%ED%95%98%EB%A9%B4-%EB%AC%B4%EC%8A%A8-%EC%9D%BC%EC%9D%B4-%EC%9D%BC%EC%96%B4%EB%82%A0%EA%B9%8C&quot;&gt;함수의 반환 규칙: return을 생략하면 무슨 일이 일어날까?&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#1-1-%EB%AA%A8%EB%93%A0-%ED%95%A8%EC%88%98%EB%8A%94-%EB%B0%98%EB%93%9C%EC%8B%9C-%EA%B0%92%EC%9D%84-%EB%B0%98%ED%99%98%ED%95%9C%EB%8B%A4&quot;&gt;1-1. 모든 함수는 &quot;반드시&quot; 값을 반환한다&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#1-2-return-%EC%83%9D%EB%9E%B5%EA%B3%BC-undefined-javascript-vs-python-%EB%B9%84%EA%B5%90&quot;&gt;1-2. return 생략과 undefined (JavaScript vs Python 비교)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#2-javascript%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%99%94%EB%A9%B4%EC%9D%84-%EB%B0%94%EA%BE%B8%EB%8A%94%EA%B0%80-dom%EC%9D%98-%ED%83%84%EC%83%9D&quot;&gt;JavaScript는 어떻게 화면을 바꾸는가? (DOM의 탄생)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#2-1-html%EC%9D%84-%EC%A7%81%EC%A0%91-%EC%88%98%EC%A0%95%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B4-%EC%95%84%EB%8B%88%EB%8B%A4&quot;&gt;2-1. HTML을 직접 수정하는 것이 아니다!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#2-2-domdocument-object-model%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%ED%8A%B8%EB%A6%AC-%EA%B5%AC%EC%A1%B0&quot;&gt;2-2. DOM(Document Object Model)의 정의와 트리 구조&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#2-3-%EC%9B%B9-%ED%8E%98%EC%9D%B4%EC%A7%80%EC%9D%98-%EC%83%81%ED%83%9C%EC%99%80-%EC%83%88%EB%A1%9C%EA%B3%A0%EC%B9%A8reload%EC%9D%98-%EC%9D%98%EB%AF%B8&quot;&gt;2-3. 웹 페이지의 '상태'와 새로고침(Reload)의 의미&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#3-%EC%97%AD%ED%95%A0-%EB%B6%84%EB%8B%B4%EC%9D%98-%EB%8C%80%EC%9B%90%EC%B9%99-html-vs-javascript&quot;&gt;역할 분담의 대원칙: HTML vs JavaScript&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#3-1--html-%EC%A0%95%EC%A0%81--%EA%B3%B5%ED%86%B5%EC%A0%81%EC%9D%B8-%EB%BC%88%EB%8C%80&quot;&gt;3-1.   HTML: 정적 &amp;amp; 공통적인 뼈대&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#3-2--javascript-%EB%8F%99%EC%A0%81--%EB%B3%80%EA%B2%BD%EB%90%98%EB%8A%94-%EC%83%81%ED%83%9C%EB%A1%9C%EC%A7%81&quot;&gt;3-2. ⚡ JavaScript: 동적 &amp;amp; 변경되는 상태&amp;middot;로직&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#3-3-%EC%97%AD%ED%95%A0-%EB%B6%84%EB%8B%B4-%ED%95%9C-%EC%A4%84-%EC%9A%94%EC%95%BD-%EB%B2%95%EC%B9%99&quot;&gt;3-3. 역할 분담 한 줄 요약 법칙&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#4-dom-%EC%9A%94%EC%86%8C-%EC%84%A0%ED%83%9D%ED%95%98%EA%B8%B0-selector-methods&quot;&gt;DOM 요소 선택하기 (Selector Methods)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#4-1-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%EC%84%A0%ED%83%9D%EC%9E%90-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%B9%84%EA%B5%90&quot;&gt;4-1. 3대 핵심 선택자 메서드 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#4-2-queryselector-vs-queryselectorall-%EC%8B%A4%EC%A0%84-%EB%AC%B8%EB%B2%95&quot;&gt;4-2.&amp;nbsp;querySelector&amp;nbsp;vs&amp;nbsp;querySelectorAll&amp;nbsp;실전 문법&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-dom-%EC%A1%B0%EC%9E%91-%EB%82%B4%EC%9A%A9-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%86%8D%EC%84%B1-%EB%8F%99%EC%A0%81-%EC%9A%94%EC%86%8C-%EC%83%9D%EC%84%B1&quot;&gt;DOM 조작 (내용, 스타일, 속성, 동적 요소 생성)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-1-%ED%85%8D%EC%8A%A4%ED%8A%B8%EC%99%80-html-%EB%82%B4%EC%9A%A9-%EB%B3%80%EA%B2%BD-textcontent-vs-innerhtml&quot;&gt;5-1. 텍스트와 HTML 내용 변경 (textContent&amp;nbsp;vs&amp;nbsp;innerHTML)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-2-%EC%9D%B8%EB%9D%BC%EC%9D%B8-%EC%8A%A4%ED%83%80%EC%9D%BC-%EB%B3%80%EA%B2%BD-stylecolor-stylefontsize-%EB%93%B1&quot;&gt;5-2. 인라인 스타일 변경 (style.color,&amp;nbsp;style.fontSize&amp;nbsp;등)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-3-%ED%83%9C%EA%B7%B8-%EC%86%8D%EC%84%B1attribute-%EB%B3%80%EA%B2%BD-linkhref-imgsrc-%EB%93%B1&quot;&gt;5-3. 태그 속성(Attribute) 변경 (link.href,&amp;nbsp;img.src&amp;nbsp;등)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-4-%EB%8F%99%EC%A0%81-%EC%9A%94%EC%86%8C-%EC%83%9D%EC%84%B1%EA%B3%BC-%EB%AC%B8%EC%84%9C-%EC%B6%94%EA%B0%80-createelement--appendchild&quot;&gt;5-4. 동적 요소 생성과 문서 추가 (createElement&amp;nbsp;&amp;amp;&amp;nbsp;appendChild)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-%EC%9D%B4%EB%B2%A4%ED%8A%B8event%EC%99%80-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A6%AC%EC%8A%A4%EB%84%88event-listener&quot;&gt;이벤트(Event)와 이벤트 리스너(Event Listener)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-1-%EC%9D%B4%EB%B2%A4%ED%8A%B8event%EB%9E%80-%EC%82%AC%EC%9A%A9%EC%9E%90-%ED%96%89%EB%8F%99-vs-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91&quot;&gt;6-1. 이벤트(Event)란? (사용자 행동 vs 브라우저 동작)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-2-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A6%AC%EC%8A%A4%EB%84%88%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%99%80-%EB%8F%99%EC%9E%91-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98&quot;&gt;6-2. 이벤트 리스너를 사용하는 이유와 동작 메커니즘&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-3-%EC%B4%88%EB%B3%B4%EC%9E%90%EA%B0%80-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%B4-%ED%95%98%EB%8A%94-%EC%B9%98%EB%AA%85%EC%A0%81-%EC%8B%A4%EC%88%98-func-vs-func&quot;&gt;6-3. 초보자가 가장 많이 하는 치명적 실수:&amp;nbsp;func&amp;nbsp;vs&amp;nbsp;func()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-4-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%ED%95%B8%EB%93%A4%EB%9F%AC-%EC%9E%91%EC%84%B1%EB%B2%95%EC%9D%98-%EC%A7%84%ED%99%94-%EA%B8%B0%EB%AA%85%ED%95%A8%EC%88%98--%EC%9D%B5%EB%AA%85%ED%95%A8%EC%88%98--%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98&quot;&gt;6-4. 이벤트 핸들러 작성법의 진화 (기명함수 ➔ 익명함수 ➔ 화살표 함수)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#7-%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98-arrow-function&quot;&gt;모던 자바스크립트: 화살표 함수 (Arrow Function)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#7-1-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98%EC%9D%98-%ED%83%84%EC%83%9D-%EB%B0%B0%EA%B2%BD%EA%B3%BC-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95&quot;&gt;7-1. 화살표 함수의 탄생 배경과 기본 문법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#7-2-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98-%EB%AC%B8%EB%B2%95-%EC%B6%95%EC%95%BD-3%EB%8B%A8%EA%B3%84&quot;&gt;7-2. 화살표 함수 문법 축약 3단계&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#8--%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4-early-return-%EC%A1%B0%EA%B8%B0-%EB%B0%98%ED%99%98-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&quot;&gt;  얼리 리턴 (Early-Return, 조기 반환) 디자인 패턴&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#8-1-%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%B2%98%EB%A6%AC-%EB%B9%84%EC%9C%A0&quot;&gt;8-1. 얼리 리턴의 정의와 머신러닝 데이터 전처리 비유&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#8-2-%EC%99%9C-%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4%EC%9D%84-%EC%8D%A8%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80-%EC%95%88%EC%A0%95%EC%84%B1--deep-nesting-%ED%83%88%EC%B6%9C&quot;&gt;8-2. 왜 얼리 리턴을 써야 하는가? (안정성 &amp;amp; Deep Nesting 탈출)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#8-3-%EC%8B%A4%EC%A0%84-before-vs-after-%EC%BD%94%EB%93%9C-%EB%B9%84%EA%B5%90&quot;&gt;8-3. 실전 Before vs After 코드 비교&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#9-web-api%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;Web API란 무엇인가?&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#9-1-javascript-%EC%96%B8%EC%96%B4%EC%99%80-web-api%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90&quot;&gt;9-1. JavaScript 언어와 Web API의 차이점&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#9-2-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%A0%9C%EA%B3%B5-web-api-5%EB%8C%80-%ED%95%B5%EC%8B%AC-%EB%B6%84%EB%A5%98&quot;&gt;9-2. 브라우저 제공 Web API 5대 핵심 분류&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#10-timer-api-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4-settimeout-setinterval-timerid&quot;&gt;Timer API 완벽 이해 (setTimeout,&amp;nbsp;setInterval,&amp;nbsp;timerId)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#10-1-1%ED%9A%8C%EC%84%B1-%ED%83%80%EC%9D%B4%EB%A8%B8-settimeout&quot;&gt;10-1. 1회성 타이머:&amp;nbsp;setTimeout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#10-2-%EB%B0%98%EB%B3%B5-%ED%83%80%EC%9D%B4%EB%A8%B8-setinterval%EA%B3%BC-%EC%A4%91%EB%8B%A8-clearinterval&quot;&gt;10-2. 반복 타이머:&amp;nbsp;setInterval과 중단&amp;nbsp;clearInterval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#10-3-timerid%EC%9D%98-%EC%97%AD%ED%95%A0%EA%B3%BC-%EC%A4%91%EB%B3%B5-%EC%8B%A4%ED%96%89-%EB%B2%84%EA%B7%B8-%EB%B0%A9%EC%A7%80-%EA%B0%80%EB%93%9C-%ED%81%B4%EB%A1%9C%EC%A6%88&quot;&gt;10-3.&amp;nbsp;timerId의 역할과 중복 실행 버그 방지 가드 클로즈&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#11--%EA%B0%95%EC%9D%98-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%93%9C-%EC%8B%A4%EC%A0%84-%EC%8B%A4%EC%8A%B5-%EA%B3%BC%EC%A0%9C-%ED%92%80%EC%9D%B4-%EB%AA%A8%EC%9D%8C&quot;&gt;  강의 슬라이드 실전 실습 과제 풀이 모음&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-1-%EB%B2%84%ED%8A%BC-%ED%81%B4%EB%A6%AD-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%BD%98%EC%86%94-%EC%B6%9C%EB%A0%A5&quot;&gt;실습 1: 버튼 클릭 이벤트 콘솔 출력&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-2-%EB%B2%84%ED%8A%BC-%ED%81%B4%EB%A6%AD-%EC%8B%9C-%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B0%8F-%EC%83%89%EC%83%81-%EB%B3%80%EA%B2%BD&quot;&gt;실습 2: 버튼 클릭 시 텍스트 및 색상 변경&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-3-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EC%8B%A4%EC%8B%9C%EA%B0%84-%EA%B8%B8%EC%9D%B4-%EA%B0%90%EC%A7%80-%EB%B0%8F-%EC%9C%A0%ED%9A%A8%EC%84%B1-%ED%94%BC%EB%93%9C%EB%B0%B1&quot;&gt;실습 3: 비밀번호 실시간 길이 감지 및 유효성 피드백&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-4-%EB%A7%88%EC%9A%B0%EC%8A%A4-%EA%B0%90%EC%A7%80-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%ED%98%B8%EB%B2%84-%EC%8B%9C-%EC%83%89%EC%83%81-%EC%A0%84%ED%99%98&quot;&gt;실습 4: 마우스 감지 이벤트 (호버 시 색상 전환)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-5-%EB%8F%99%EC%A0%81-%EC%9E%85%EB%A0%A5%EA%B0%92-%EC%B2%98%EB%A6%AC-%EB%B0%8F-%ED%99%94%EB%A9%B4-%EB%A0%8C%EB%8D%94%EB%A7%81-dom-%EC%B6%94%EA%B0%80&quot;&gt;실습 5: 동적 입력값 처리 및 화면 렌더링 (DOM 추가)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-6-timer-api-5%EC%B4%88-%EC%B9%B4%EC%9A%B4%ED%8A%B8%EB%8B%A4%EC%9A%B4-%ED%83%80%EC%9D%B4%EB%A8%B8-%EC%99%84%EC%84%B1&quot;&gt;실습 6: Timer API 5초 카운트다운 타이머 완성&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#12--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 함수의 반환 규칙: return을 생략하면 무슨 일이 일어날까?&lt;/h2&gt;
&lt;a id=&quot;user-content-1-함수의-반환-규칙-return을-생략하면-무슨-일이-일어날까&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#1-%ED%95%A8%EC%88%98%EC%9D%98-%EB%B0%98%ED%99%98-%EA%B7%9C%EC%B9%99-return%EC%9D%84-%EC%83%9D%EB%9E%B5%ED%95%98%EB%A9%B4-%EB%AC%B4%EC%8A%A8-%EC%9D%BC%EC%9D%B4-%EC%9D%BC%EC%96%B4%EB%82%A0%EA%B9%8C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. 모든 함수는 &quot;반드시&quot; 값을 반환한다&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-모든-함수는-반드시-값을-반환한다&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#1-1-%EB%AA%A8%EB%93%A0-%ED%95%A8%EC%88%98%EB%8A%94-%EB%B0%98%EB%93%9C%EC%8B%9C-%EA%B0%92%EC%9D%84-%EB%B0%98%ED%99%98%ED%95%9C%EB%8B%A4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트의 함수는 호출되면 **어떤 상황에서든 반드시 결과값 하나를 반환(Return)**하도록 언어 차원에서 설계되어 있습니다.&lt;/li&gt;
&lt;li&gt;개발자가 코드 내에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;return&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드를 명시하지 않더라도, 자바스크립트 엔진은 내부적으로 **return undefined;**를 자동으로 붙여서 실행을 마칩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;1166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FK3wp/dJMcackFglp/IUUuVROskHiexMr2ua9icK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FK3wp/dJMcackFglp/IUUuVROskHiexMr2ua9icK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FK3wp/dJMcackFglp/IUUuVROskHiexMr2ua9icK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFK3wp%2FdJMcackFglp%2FIUUuVROskHiexMr2ua9icK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;220&quot; height=&quot;497&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;1166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. return 생략과 undefined (JavaScript vs Python 비교)&lt;/h3&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 'Hello' 를 출력하는 함수
function sayHello() {
  console.log(&quot;hello&quot;);
  // ⚠️ return을 명시하지 않았지만, 내부적으로 아래 코드가 숨겨져 있음!
  // return undefined;
}

// sayHello()의 반환값을 변수 hello에 할당
let hello = sayHello(); // 1) 콘솔에 &quot;hello&quot;가 출력됨

// hello 변수에 무엇이 담겼는지 확인
console.log(hello);     // 2) undefined 가 출력됨!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  언어별 return 생략 시 반환값 비교&lt;/h4&gt;
&lt;a id=&quot;user-content--언어별-return-생략-시-반환값-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#-%EC%96%B8%EC%96%B4%EB%B3%84-return-%EC%83%9D%EB%9E%B5-%EC%8B%9C-%EB%B0%98%ED%99%98%EA%B0%92-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 언어&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return 생략 시 자동 반환값&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 14.4186%;&quot;&gt;&lt;b&gt;JavaScript&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.6279%;&quot;&gt;undefined&lt;/td&gt;
&lt;td style=&quot;width: 58.7209%;&quot;&gt;&quot;값이 아직 정의되지 않음&quot;을 나타내는 JS 기본 원시 타입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 14.4186%;&quot;&gt;&lt;b&gt;Python&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.6279%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 58.7209%;&quot;&gt;파이썬의&lt;span&gt;&amp;nbsp;&lt;/span&gt;NoneType&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체를 기본 반환 (def foo(): pass&lt;span&gt;&amp;nbsp;&lt;/span&gt;호출 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;None&lt;span&gt;&amp;nbsp;&lt;/span&gt;리턴)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #8250df;&quot; data-ke-size=&quot;size16&quot;&gt;Important&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;콘솔 출력(console.log)과 반환(return)의 차이&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;console.log()는 단순히 개발자 모니터(화면)에 글자를 띄워주는 **&quot;출력 행위&quot;**일 뿐입니다.&lt;/li&gt;
&lt;li&gt;return은 함수를 호출한 자리에 데이터를 쥐어주는 **&quot;값의 전달&quot;**입니다.&lt;br /&gt;return이 없는 함수는 외부 변수에 담았을 때 언제나&lt;span&gt;&amp;nbsp;&lt;/span&gt;undefined가 할당됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. JavaScript는 어떻게 화면을 바꾸는가? (DOM의 탄생)&lt;/h2&gt;
&lt;a id=&quot;user-content-2-javascript는-어떻게-화면을-바꾸는가-dom의-탄생&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#2-javascript%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%99%94%EB%A9%B4%EC%9D%84-%EB%B0%94%EA%BE%B8%EB%8A%94%EA%B0%80-dom%EC%9D%98-%ED%83%84%EC%83%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. HTML을 직접 수정하는 것이 아니다!&lt;/h3&gt;
&lt;a id=&quot;user-content-2-1-html을-직접-수정하는-것이-아니다&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#2-1-html%EC%9D%84-%EC%A7%81%EC%A0%91-%EC%88%98%EC%A0%95%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B4-%EC%95%84%EB%8B%88%EB%8B%A4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;많은 입문자들이 *&quot;자바스크립트가&lt;span&gt;&amp;nbsp;&lt;/span&gt;.html&lt;span&gt;&amp;nbsp;&lt;/span&gt;텍스트 파일을 직접 열어서 코드를 수정하나?&quot;*라고 오해합니다.&lt;br /&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자바스크립트는 하드디스크나 서버에 있는 HTML 파일을 직접 수정하는 것이 아닙니다.&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 1.16279%;&quot; colspan=&quot;2&quot;&gt;&lt;span&gt;&lt;b&gt;Unable to render rich display&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Parse error on line 3:&lt;br /&gt;...JavaScript&quot;] --&amp;gt;|조작 (Modify)| B B --&lt;br /&gt;-----------------------^&lt;br /&gt;Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'&lt;br /&gt;&lt;br /&gt;For more information, see&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&quot;&gt;https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams#creating-mermaid-diagrams&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;coq&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;graph LR
    A[&quot;  index.html&amp;lt;br/&amp;gt;(정적 파일)&quot;] --&amp;gt;|브라우저가 읽고 파싱| B[&quot;  DOM (객체 트리)&amp;lt;br/&amp;gt;(메모리 상의 객체 구조)&quot;]
    C[&quot;⚡ JavaScript&quot;] --&amp;gt;|조작 (Modify)| B
    B --&amp;gt;|화면 렌더링| D[&quot;  사용자 모니터 화면&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;브라우저가 원본 HTML 파일을 읽어서 컴퓨터 메모리 안에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DOM(Document Object Model) 객체 트리&lt;/b&gt;를 생성합니다.&lt;/li&gt;
&lt;li&gt;JavaScript는 이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메모리 상에 존재하는 DOM 객체를 조작&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;브라우저는 변경된 DOM 객체를 감지하고 화면을 즉시 다시 그려냅니다(Re-rendering).&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. DOM(Document Object Model)의 정의와 트리 구조&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-domdocument-object-model의-정의와-트리-구조&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#2-2-domdocument-object-model%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%ED%8A%B8%EB%A6%AC-%EA%B5%AC%EC%A1%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DOM이란?&lt;/b&gt;: 브라우저가 HTML 문서를 해석하여,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript와 같은 프로그래밍 언어가 제어하고 다룰 수 있도록 만든 객체(Object) 구조&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;웹 페이지 = 거대한 트리(Tree) 구조&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 꼭대기(뿌리):&lt;span&gt;&amp;nbsp;&lt;/span&gt;document&lt;/li&gt;
&lt;li&gt;부모 노드:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;html&amp;gt;&lt;/li&gt;
&lt;li&gt;자식 노드:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;head&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;body&amp;gt;&lt;/li&gt;
&lt;li&gt;잎사귀(Leaf) 노드:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;h1&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;p&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;button&amp;gt;, 텍스트, 속성 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1298&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jdmkr/dJMcafojziX/bQ2LMiaihz3dpsxusPiOm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jdmkr/dJMcafojziX/bQ2LMiaihz3dpsxusPiOm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jdmkr/dJMcafojziX/bQ2LMiaihz3dpsxusPiOm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJdmkr%2FdJMcafojziX%2FbQ2LMiaihz3dpsxusPiOm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;547&quot; height=&quot;311&quot; data-origin-width=&quot;1298&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. 웹 페이지의 '상태'와 새로고침(Reload)의 의미&lt;/h3&gt;
&lt;a id=&quot;user-content-2-3-웹-페이지의-상태와-새로고침reload의-의미&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#2-3-%EC%9B%B9-%ED%8E%98%EC%9D%B4%EC%A7%80%EC%9D%98-%EC%83%81%ED%83%9C%EC%99%80-%EC%83%88%EB%A1%9C%EA%B3%A0%EC%B9%A8reload%EC%9D%98-%EC%9D%98%EB%AF%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;**DOM은 '웹 페이지의 현재 상태'**입니다.&lt;br /&gt;JavaScript로 글자 색을 빨간색으로 바꾸고 글씨를 바꿨더라도, 그것은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;오직 브라우저 메모리 안의 DOM에만 반영된 상태&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;사용자가 웹 브라우저에서 **새로고침(F5 / reload)**을 누르면:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;메모리에 있던 기존 DOM이 완전히 소멸합니다.&lt;/li&gt;
&lt;li&gt;원본&lt;span&gt;&amp;nbsp;&lt;/span&gt;index.html&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일을 서버나 로컬에서 다시 읽어옵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새로운 DOM을 처음부터 다시 생성&lt;/b&gt;하므로 모든 화면 조작 상태가 초기화됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-size: 1.62em; letter-spacing: -1px; background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;3. 역할 분담의 대원칙: HTML vs JavaScript&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;어떤 코드를 HTML에 넣고, 어떤 코드를 JavaScript에 넣어야 할까?&quot;&lt;/p&gt;
&lt;div data-plain=&quot;graph LR
    subgraph HTML_Zone[&amp;quot;  HTML (정적 &amp;amp; 공통)&amp;quot;]
        H1[&amp;quot;기본 레이아웃 뼈대&amp;quot;]
        H2[&amp;quot;공통 텍스트 구조&amp;quot;]
        H3[&amp;quot;변하지 않는 초기 UI 틀&amp;quot;]
    end
    
    subgraph JS_Zone[&amp;quot;⚡ JavaScript (동적 &amp;amp; 변경)&amp;quot;]
        J1[&amp;quot;사용자 인터랙션 (클릭/입력)&amp;quot;]
        J2[&amp;quot;실시간 데이터 검증&amp;quot;]
        J3[&amp;quot;상태 변화 &amp;amp; DOM 조작&amp;quot;]
    end&quot; data-json=&quot;{&amp;quot;data&amp;quot;:&amp;quot;graph LR\n    subgraph HTML_Zone[\&amp;quot;  HTML (정적 &amp;amp; 공통)\&amp;quot;]\n        H1[\&amp;quot;기본 레이아웃 뼈대\&amp;quot;]\n        H2[\&amp;quot;공통 텍스트 구조\&amp;quot;]\n        H3[\&amp;quot;변하지 않는 초기 UI 틀\&amp;quot;]\n    end\n    \n    subgraph JS_Zone[\&amp;quot;⚡ JavaScript (동적 &amp;amp; 변경)\&amp;quot;]\n        J1[\&amp;quot;사용자 인터랙션 (클릭/입력)\&amp;quot;]\n        J2[\&amp;quot;실시간 데이터 검증\&amp;quot;]\n        J3[\&amp;quot;상태 변화 &amp;amp; DOM 조작\&amp;quot;]\n    end\n&amp;quot;}&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;844&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k5qs9/dJMcagACQlN/67Wte2icgZyoBDZdhasz9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k5qs9/dJMcagACQlN/67Wte2icgZyoBDZdhasz9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k5qs9/dJMcagACQlN/67Wte2icgZyoBDZdhasz9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk5qs9%2FdJMcagACQlN%2F67Wte2icgZyoBDZdhasz9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;145&quot; height=&quot;267&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;844&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5qbjz/dJMcadRmWHr/YLmcPIkrKH92JF2aw9wMC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5qbjz/dJMcadRmWHr/YLmcPIkrKH92JF2aw9wMC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5qbjz/dJMcadRmWHr/YLmcPIkrKH92JF2aw9wMC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5qbjz%2FdJMcadRmWHr%2FYLmcPIkrKH92JF2aw9wMC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;149&quot; height=&quot;245&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;764&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1.   HTML: 정적 &amp;amp; 공통적인 뼈대&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1--html-정적--공통적인-뼈대&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#3-1--html-%EC%A0%95%EC%A0%81--%EA%B3%B5%ED%86%B5%EC%A0%81%EC%9D%B8-%EB%BC%88%EB%8C%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 웹 페이지의 뼈대와 공통적인 구조를 담당.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 누구든, 버튼을 어떻게 누르든&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변하지 않고 항상 그 자리에 그대로 있는 공통적이고 정적인 부분&lt;/b&gt;은 HTML 파일에 작성합니다.&lt;/li&gt;
&lt;li&gt;예시: 헤더, 사이드바 틀, 기본 입력 양식 태그(&amp;lt;input&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;button&amp;gt;), 푸터 레이아웃.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. ⚡ JavaScript: 동적 &amp;amp; 변경되는 상태&amp;middot;로직&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2--javascript-동적--변경되는-상태로직&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#3-2--javascript-%EB%8F%99%EC%A0%81--%EB%B3%80%EA%B2%BD%EB%90%98%EB%8A%94-%EC%83%81%ED%83%9C%EB%A1%9C%EC%A7%81&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 사용자의 행동(클릭, 키 입력, 마우스 이동 등)에 따라 변화를 가하는 동적 제어와 비즈니스 로직을 담당.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자의 인터랙션에 따라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실시간으로 바뀌거나(상태 변화)&lt;/b&gt;, 개발자가 조건문/반복문/연산 로직으로 제어해야 하는 부분은 JavaScript(DOM 조작 및 이벤트)에 작성합니다.&lt;/li&gt;
&lt;li&gt;예시: 로그인 버튼 클릭 시 글자 색상 변경, 비밀번호 입력값 실시간 자릿수 검사, 5초 카운트다운 타이머 등.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-3. 역할 분담 한 줄 요약 법칙&lt;/h3&gt;
&lt;a id=&quot;user-content-3-3-역할-분담-한-줄-요약-법칙&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#3-3-%EC%97%AD%ED%95%A0-%EB%B6%84%EB%8B%B4-%ED%95%9C-%EC%A4%84-%EC%9A%94%EC%95%BD-%EB%B2%95%EC%B9%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;Note&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;골든 룰 (Golden Rule)&lt;/b&gt;:&lt;br /&gt;&lt;b&gt;&quot;화면의 기본 틀과 공통 속성은 HTML에! 사용자의 행동이나 상황에 따라 동적으로 변하는 상태와 로직은 JS(DOM)에!&quot;&lt;/b&gt;&lt;br /&gt;이 기준을 잡으면 컴포넌트나 웹 코드를 작성할 때 역할이 명쾌해집니다.&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. DOM 요소 선택하기 (Selector Methods)&lt;/h2&gt;
&lt;a id=&quot;user-content-4-dom-요소-선택하기-selector-methods&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#4-dom-%EC%9A%94%EC%86%8C-%EC%84%A0%ED%83%9D%ED%95%98%EA%B8%B0-selector-methods&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JavaScript가 화면 요소를 바꾸려면, 가장 먼저 **&quot;어떤 요소를 바꿀 것인가?&quot;**를 지정(선택)해야 합니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 3대 핵심 선택자 메서드 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-3대-핵심-선택자-메서드-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#4-1-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%EC%84%A0%ED%83%9D%EC%9E%90-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 메서드명&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;인자 형식&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;반환값&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 매칭 대상 x&amp;nbsp; &amp;nbsp; &amp;nbsp; 주요 특징 및 권장 용도&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.349%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 19.7674%;&quot;&gt;&lt;b&gt;document.getElementById()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.4884%;&quot;&gt;&quot;아이디명&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(ex:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;text&quot;)&lt;/td&gt;
&lt;td style=&quot;width: 13.6047%;&quot;&gt;단일 Element&lt;/td&gt;
&lt;td style=&quot;width: 11.1628%;&quot;&gt;null&lt;/td&gt;
&lt;td style=&quot;width: 32.2093%;&quot;&gt;고유 ID로 1개 요소를 빠르게 찾을 때 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;width: 19.7674%;&quot;&gt;&lt;b&gt;document.querySelector()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.4884%;&quot;&gt;CSS 선택자&lt;span&gt;&amp;nbsp;&lt;/span&gt;(ex:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;#text&quot;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;.item&quot;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;p&quot;)&lt;/td&gt;
&lt;td style=&quot;width: 13.6047%;&quot;&gt;단일 Element&lt;/td&gt;
&lt;td style=&quot;width: 11.1628%;&quot;&gt;null&lt;/td&gt;
&lt;td style=&quot;width: 32.2093%;&quot;&gt;&lt;b&gt;실무 최다 사용!&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가장 첫 번째로 일치하는 요소 1개 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;width: 19.7674%;&quot;&gt;&lt;b&gt;document.querySelectorAll()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.4884%;&quot;&gt;CSS 선택자&lt;span&gt;&amp;nbsp;&lt;/span&gt;(ex:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;.item&quot;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;ul &amp;gt; li&quot;)&lt;/td&gt;
&lt;td style=&quot;width: 13.6047%;&quot;&gt;NodeList&lt;span&gt;&amp;nbsp;&lt;/span&gt;(유사 배열)&lt;/td&gt;
&lt;td style=&quot;width: 11.1628%;&quot;&gt;빈 NodeList ([])&lt;/td&gt;
&lt;td style=&quot;width: 32.2093%;&quot;&gt;조건에 맞는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모든 요소를 그룹으로 선택&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(forEach&lt;span&gt;&amp;nbsp;&lt;/span&gt;순회 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;querySelector&lt;span&gt;&amp;nbsp;&lt;/span&gt;vs&lt;span&gt;&amp;nbsp;&lt;/span&gt;querySelectorAll&lt;span&gt;&amp;nbsp;&lt;/span&gt;실전 문법&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-queryselector-vs-queryselectorall-실전-문법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#4-2-queryselector-vs-queryselectorall-%EC%8B%A4%EC%A0%84-%EB%AC%B8%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;!-- HTML 구조 예시 --&amp;gt;
&amp;lt;h1 id=&quot;text&quot;&amp;gt;Hello&amp;lt;/h1&amp;gt;
&amp;lt;div class=&quot;item&quot;&amp;gt;사과&amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;item&quot;&amp;gt;바나나&amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;item&quot;&amp;gt;포도&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 1. querySelector: 단 1개의 요소만 선택
const singleHeading = document.querySelector(&quot;#text&quot;);  // id가 text인 요소
const firstItem     = document.querySelector(&quot;.item&quot;);  // 클래스가 item인 것 중 '첫 번째' (사과)

console.log(singleHeading.textContent); // &quot;Hello&quot;
console.log(firstItem.textContent);     // &quot;사과&quot;

// 2. querySelectorAll: 일치하는 모든 요소를 NodeList로 선택
const allItems = document.querySelectorAll(&quot;.item&quot;);

console.log(allItems.length); // 3 (사과, 바나나, 포도)

// NodeList는 forEach 메서드로 간편하게 순회 가능!
allItems.forEach((el, index) =&amp;gt; {
  console.log(`${index + 1}번째 과일:`, el.textContent);
});
// 1번째 과일: 사과
// 2번째 과일: 바나나
// 3번째 과일: 포도&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. DOM 조작 (내용, 스타일, 속성, 동적 요소 생성)&lt;/h2&gt;
&lt;a id=&quot;user-content-5-dom-조작-내용-스타일-속성-동적-요소-생성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-dom-%EC%A1%B0%EC%9E%91-%EB%82%B4%EC%9A%A9-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%86%8D%EC%84%B1-%EB%8F%99%EC%A0%81-%EC%9A%94%EC%86%8C-%EC%83%9D%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;요소를 선택했다면, 그 요소의 텍스트, HTML 구조, CSS 디자인 스타일, 속성을 마음대로 변경할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. 텍스트와 HTML 내용 변경 (textContent&lt;span&gt;&amp;nbsp;&lt;/span&gt;vs&lt;span&gt;&amp;nbsp;&lt;/span&gt;innerHTML)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-텍스트와-html-내용-변경-textcontent-vs-innerhtml&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-1-%ED%85%8D%EC%8A%A4%ED%8A%B8%EC%99%80-html-%EB%82%B4%EC%9A%A9-%EB%B3%80%EA%B2%BD-textcontent-vs-innerhtml&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const el = document.getElementById(&quot;text&quot;);

// 1. textContent: 순수한 텍스트만 읽거나 변경 (보안상 안전, XSS 방지)
el.textContent = &quot;Hello, JavaScript&quot;; 
console.log(el.textContent.trim()); // 공백 제거 후 텍스트 출력

// 2. innerHTML: HTML 태그까지 포함하여 파싱하고 화면을 변경
// 기존 내부 요소를 비우거나 새 태그를 통째로 주입할 때 사용
el.innerHTML = &quot;&amp;lt;span style='color: blue;'&amp;gt;Hello, Blue JS!&amp;lt;/span&amp;gt;&quot;;

// 요소 내부를 깨끗이 비울 때도 자주 활용:
// el.innerHTML = &quot;&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. 인라인 스타일 변경 (style.color,&lt;span&gt;&amp;nbsp;&lt;/span&gt;style.fontSize&lt;span&gt;&amp;nbsp;&lt;/span&gt;등)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-인라인-스타일-변경-stylecolor-stylefontsize-등&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-2-%EC%9D%B8%EB%9D%BC%EC%9D%B8-%EC%8A%A4%ED%83%80%EC%9D%BC-%EB%B3%80%EA%B2%BD-stylecolor-stylefontsize-%EB%93%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선택한 요소의&lt;span&gt;&amp;nbsp;&lt;/span&gt;.style&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체 속성에 접근하여 CSS 스타일을 직접 변경합니다.&lt;/li&gt;
&lt;li&gt;CSS 속성명에 하이픈(-)이 있는 속성은 JavaScript에서 **카멜 표기법(camelCase)**으로 작성합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;font-size&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;fontSize&lt;/li&gt;
&lt;li&gt;background-color&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;backgroundColor&lt;/li&gt;
&lt;li&gt;border-radius&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;borderRadius&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;dart&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const el = document.querySelector(&quot;#text&quot;);

el.textContent = &quot;Hello, DOM&quot;;
el.style.color = &quot;red&quot;;             // 글자색 변경
el.style.fontSize = &quot;20px&quot;;          // 폰트 크기 변경
el.style.backgroundColor = &quot;yellow&quot;; // 배경색 변경
el.style.border = &quot;1px solid red&quot;;   // 테두리 추가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 태그 속성(Attribute) 변경 (link.href,&lt;span&gt;&amp;nbsp;&lt;/span&gt;img.src&lt;span&gt;&amp;nbsp;&lt;/span&gt;등)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3-태그-속성attribute-변경-linkhref-imgsrc-등&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-3-%ED%83%9C%EA%B7%B8-%EC%86%8D%EC%84%B1attribute-%EB%B3%80%EA%B2%BD-linkhref-imgsrc-%EB%93%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 태그가 가진 고유 속성(href,&lt;span&gt;&amp;nbsp;&lt;/span&gt;src,&lt;span&gt;&amp;nbsp;&lt;/span&gt;placeholder,&lt;span&gt;&amp;nbsp;&lt;/span&gt;disabled,&lt;span&gt;&amp;nbsp;&lt;/span&gt;type&lt;span&gt;&amp;nbsp;&lt;/span&gt;등)을 직접 변경할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;dart&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// &amp;lt;a&amp;gt; 태그의 링크 목적지 변경
const link = document.querySelector(&quot;a&quot;);
link.href = &quot;https://google.com&quot;;
link.target = &quot;_blank&quot;; // 새 탭에서 열기

// &amp;lt;input&amp;gt; 태그의 속성 변경
const input = document.querySelector(&quot;#name-input&quot;);
input.placeholder = &quot;새로운 이름을 입력해주세요&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-4. 동적 요소 생성과 문서 추가 (createElement&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;amp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;appendChild)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-4-동적-요소-생성과-문서-추가-createelement--appendchild&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#5-4-%EB%8F%99%EC%A0%81-%EC%9A%94%EC%86%8C-%EC%83%9D%EC%84%B1%EA%B3%BC-%EB%AC%B8%EC%84%9C-%EC%B6%94%EA%B0%80-createelement--appendchild&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;새로운 태그 요소를 자바스크립트로 메모리상에 생성하고, 원하는 부모 태그 아래에 자식으로 이어 붙입니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;dart&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 1. 메모리 상에 새로운 &amp;lt;p&amp;gt; 태그 노드 생성
const p = document.createElement(&quot;p&quot;); // &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;

// 2. 생성한 요소에 내용 채우기
p.textContent = &quot;새롭게 생성된 문단입니다.&quot;; // &amp;lt;p&amp;gt;새롭게 생성된 문단입니다.&amp;lt;/p&amp;gt;

// 3. 실제 DOM 트리(화면)에 붙이기
// document.body 또는 특정 부모 컨테이너(result 등)에 appendChild 실행
const resultBox = document.querySelector(&quot;#result&quot;);
resultBox.appendChild(p);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 이벤트(Event)와 이벤트 리스너(Event Listener)&lt;/h2&gt;
&lt;a id=&quot;user-content-6-이벤트event와-이벤트-리스너event-listener&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-%EC%9D%B4%EB%B2%A4%ED%8A%B8event%EC%99%80-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A6%AC%EC%8A%A4%EB%84%88event-listener&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. 이벤트(Event)란? (사용자 행동 vs 브라우저 동작)&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-이벤트event란-사용자-행동-vs-브라우저-동작&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-1-%EC%9D%B4%EB%B2%A4%ED%8A%B8event%EB%9E%80-%EC%82%AC%EC%9A%A9%EC%9E%90-%ED%96%89%EB%8F%99-vs-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이벤트(Event)&lt;/b&gt;: 웹 페이지 안에서 일어나는 모든 상태 변화나 사건.&lt;/li&gt;
&lt;li&gt;주로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자의 상호작용 행동&lt;/b&gt;에 의해 발생하지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;브라우저 자체의 라이프사이클 동작&lt;/b&gt;도 포함됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKUdXp/dJMcafBKlFo/YSQEmx9vQ75slts0d5fyf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKUdXp/dJMcafBKlFo/YSQEmx9vQ75slts0d5fyf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKUdXp/dJMcafBKlFo/YSQEmx9vQ75slts0d5fyf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKUdXp%2FdJMcafBKlFo%2FYSQEmx9vQ75slts0d5fyf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2562&quot; height=&quot;584&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2. 이벤트 리스너를 사용하는 이유와 동작 메커니즘&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-이벤트-리스너를-사용하는-이유와-동작-메커니즘&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-2-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A6%AC%EC%8A%A4%EB%84%88%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%99%80-%EB%8F%99%EC%9E%91-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이벤트 리스너(Event Listener)&lt;/b&gt;: 특정 요소에서 지정한 이벤트가 언제 발생하는지 귀 기울여 감시하다가,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;해당 사건이 발생하면 지정해 둔 함수(콜백 함수)를 자동으로 호출해 주는 시스템&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용하는 3대 이유&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자의 행동을 감지하여 실시간 상호작용(Interaction) 구현.&lt;/li&gt;
&lt;li&gt;죽어있는 정적인 HTML 문서를 살아 숨 쉬는 동적 웹 애플리케이션으로 변환.&lt;/li&gt;
&lt;li&gt;화면(UI)과 비즈니스 로직을 상황에 맞춰 동적으로 제어.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 기본 문법: 타겟요소.addEventListener(&quot;이벤트종류&quot;, 실행할함수);
const btn = document.querySelector(&quot;button&quot;);

btn.addEventListener(&quot;click&quot;, function () {
  console.log(&quot;버튼이 클릭됨!&quot;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-3. 초보자가 가장 많이 하는 치명적 실수:&lt;span&gt;&amp;nbsp;&lt;/span&gt;func&lt;span&gt;&amp;nbsp;&lt;/span&gt;vs&lt;span&gt;&amp;nbsp;&lt;/span&gt;func()&lt;/h3&gt;
&lt;a id=&quot;user-content-6-3-초보자가-가장-많이-하는-치명적-실수-func-vs-func&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-3-%EC%B4%88%EB%B3%B4%EC%9E%90%EA%B0%80-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%B4-%ED%95%98%EB%8A%94-%EC%B9%98%EB%AA%85%EC%A0%81-%EC%8B%A4%EC%88%98-func-vs-func&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;function buttonAlert() {
  alert(&quot;버튼이 클릭됨&quot;);
}

const btn = document.querySelector(&quot;button&quot;);

// ✅ 올바른 코드: 함수 '이름(참조)'만 전달!
btn.addEventListener(&quot;click&quot;, buttonAlert);
// 설명: &quot;클릭이라는 사건이 발생했을 때, 그때 buttonAlert 함수를 실행해줘!&quot;

// ❌ 치명적인 실수 코드: 함수 뒤에 괄호 ()를 붙여 호출해버림!
btn.addEventListener(&quot;click&quot;, buttonAlert());&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #9a6700;&quot; data-ke-size=&quot;size16&quot;&gt;Warning&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;왜&lt;span&gt;&amp;nbsp;&lt;/span&gt;buttonAlert()로 작성하면 안 되는가?&lt;/b&gt;&lt;br /&gt;buttonAlert()처럼 괄호를 붙이면, 이벤트 리스너가 등록되는 시점(코드 로딩 즉시)에 함수가 바로 1회 실행되어 버립니다!&lt;br /&gt;게다가&lt;span&gt;&amp;nbsp;&lt;/span&gt;buttonAlert&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수는 return 값이 없으므로 반환값인&lt;span&gt;&amp;nbsp;&lt;/span&gt;undefined가&lt;span&gt;&amp;nbsp;&lt;/span&gt;addEventListener의 두 번째 인자로 전달됩니다.&lt;br /&gt;즉, 브라우저는 내부적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;btn.addEventListener(&quot;click&quot;, undefined)로 인식하여,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실제 버튼을 클릭했을 때 아무런 동작도 하지 않게 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-4. 이벤트 핸들러 작성법의 진화 (기명함수 ➔ 익명함수 ➔ 화살표 함수)&lt;/h3&gt;
&lt;a id=&quot;user-content-6-4-이벤트-핸들러-작성법의-진화-기명함수--익명함수--화살표-함수&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#6-4-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%ED%95%B8%EB%93%A4%EB%9F%AC-%EC%9E%91%EC%84%B1%EB%B2%95%EC%9D%98-%EC%A7%84%ED%99%94-%EA%B8%B0%EB%AA%85%ED%95%A8%EC%88%98--%EC%9D%B5%EB%AA%85%ED%95%A8%EC%88%98--%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const btn = document.querySelector(&quot;button&quot;);

// 1단계: 외부 기명 함수 전달 (재사용할 때 적합)
function handleClick() {
  alert(&quot;클릭됨&quot;);
}
btn.addEventListener(&quot;click&quot;, handleClick);

// 2단계: 단독 사용 시 안에서 익명 함수 정의
btn.addEventListener(&quot;click&quot;, function () {
  alert(&quot;클릭됨&quot;);
});

// 3단계: 화살표 함수 (Arrow Function)로 전환
btn.addEventListener(&quot;click&quot;, () =&amp;gt; {
  alert(&quot;클릭됨&quot;);
});

// 4단계: 실행할 코드가 한 줄이면 중괄호 { } 생략 (최종 모던 스타일)
btn.addEventListener(&quot;click&quot;, () =&amp;gt; alert(&quot;클릭됨&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 모던 자바스크립트: 화살표 함수 (Arrow Function)&lt;/h2&gt;
&lt;a id=&quot;user-content-7-모던-자바스크립트-화살표-함수-arrow-function&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#7-%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98-arrow-function&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-1. 화살표 함수의 탄생 배경과 기본 문법&lt;/h3&gt;
&lt;a id=&quot;user-content-7-1-화살표-함수의-탄생-배경과-기본-문법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#7-1-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98%EC%9D%98-%ED%83%84%EC%83%9D-%EB%B0%B0%EA%B2%BD%EA%B3%BC-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ES6(2015)에서 도입된 문법으로, 길고 번거로운&lt;span&gt;&amp;nbsp;&lt;/span&gt;function&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드 대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;=&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기호를 사용하여 함수를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;더 짧고 간결하게 정의&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;특히 이벤트 리스너나 배열 순회 메서드(forEach,&lt;span&gt;&amp;nbsp;&lt;/span&gt;map,&lt;span&gt;&amp;nbsp;&lt;/span&gt;filter)의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;콜백 함수&lt;/b&gt;로 압도적으로 많이 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7-2. 화살표 함수 문법 축약 3단계&lt;/h3&gt;
&lt;a id=&quot;user-content-7-2-화살표-함수-문법-축약-3단계&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#7-2-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98-%EB%AC%B8%EB%B2%95-%EC%B6%95%EC%95%BD-3%EB%8B%A8%EA%B3%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// [기존 전통적 함수 선언]
function add(a, b) {
  return a + b;
}

// 1단계: function 대신 화살표(=&amp;gt;) 기본 표기
const add1 = (a, b) =&amp;gt; {
  return a + b;
};

// 2단계: 본문이 '단일 return 문'인 경우 중괄호 { }와 return 키워드 동시 생략!
const add2 = (a, b) =&amp;gt; a + b;

// 3단계: 매개변수가 1개뿐인 경우 소괄호 ( )도 생략 가능!
const double = x =&amp;gt; x * 2;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이벤트 리스너에서의 화살표 함수 활용 비교:&lt;/h4&gt;
&lt;a id=&quot;user-content-이벤트-리스너에서의-화살표-함수-활용-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A6%AC%EC%8A%A4%EB%84%88%EC%97%90%EC%84%9C%EC%9D%98-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98-%ED%99%9C%EC%9A%A9-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 기본 익명 함수
btn.addEventListener(&quot;click&quot;, function () {
  console.log(&quot;클릭됨&quot;);
});

// 화살표 함수
btn.addEventListener(&quot;click&quot;, () =&amp;gt; {
  console.log(&quot;클릭됨&quot;);
});

// 한 줄 축약 화살표 함수
btn.addEventListener(&quot;click&quot;, () =&amp;gt; console.log(&quot;클릭됨&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8.   얼리 리턴 (Early-Return, 조기 반환) 디자인 패턴&lt;/h2&gt;
&lt;a id=&quot;user-content-8--얼리-리턴-early-return-조기-반환-디자인-패턴&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#8--%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4-early-return-%EC%A1%B0%EA%B8%B0-%EB%B0%98%ED%99%98-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-1. 얼리 리턴의 정의와 머신러닝 데이터 전처리 비유&lt;/h3&gt;
&lt;a id=&quot;user-content-8-1-얼리-리턴의-정의와-머신러닝-데이터-전처리-비유&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#8-1-%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%B2%98%EB%A6%AC-%EB%B9%84%EC%9C%A0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 함수나 이벤트 핸들러가 본격적인 핵심 로직을 실행하기 전,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가장 앞단에서 데이터 유효성 검사(Data Validation)를 수행하여 조건에 맞지 않는 잘못된 입력값을 사전에 차단하고 함수를 즉시 종료(return;)하는 패턴&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;1376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPLASM/dJMcacFaJH0/Vtybl5N1PI6CsYgPJ9Wkk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPLASM/dJMcacFaJH0/Vtybl5N1PI6CsYgPJ9Wkk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPLASM/dJMcacFaJH0/Vtybl5N1PI6CsYgPJ9Wkk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPLASM%2FdJMcacFaJH0%2FVtybl5N1PI6CsYgPJ9Wkk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;315&quot; height=&quot;531&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;1376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;Note&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;머신러닝(AI) 관점에서의 비유&lt;/b&gt;:&lt;br /&gt;머신러닝 모델에 학습 데이터를 주입하기 전, **데이터 전처리(Data Preprocessing)**를 거쳐 결측치(Null)나 이상치(Outlier)를 먼저 걸러내는 것과 완벽히 동일합니다.&lt;br /&gt;쓰레기 데이터(비정상 값)가 핵심 모델에 들어가서 계산 에러나 오작동을 일으키는 것을 입구에서 원천 봉쇄하는 것입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-2. 왜 얼리 리턴을 써야 하는가? (안정성 &amp;amp; Deep Nesting 탈출)&lt;/h3&gt;
&lt;a id=&quot;user-content-8-2-왜-얼리-리턴을-써야-하는가-안정성--deep-nesting-탈출&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#8-2-%EC%99%9C-%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4%EC%9D%84-%EC%8D%A8%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80-%EC%95%88%EC%A0%95%EC%84%B1--deep-nesting-%ED%83%88%EC%B6%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;안정성 확보 (Bug Prevention)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 문자열(&quot;&quot;),&lt;span&gt;&amp;nbsp;&lt;/span&gt;null, 음수, 비정상 포맷 값이 메인 로직으로 흘러 들어가 화면이 깨지거나 런타임 오류가 터지는 현상을 사전에 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가독성 향상 (Deep Nesting 방지)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조건마다 안쪽으로 깊숙이 들여쓰기(if { if { if { ... } } })하는 '피라미드 지옥(Pyramid of Doom)' 대신, 예외 상황을 초반에 잘라내어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;코드의 깊이(Indent Level)를 1단계로 평탄하게 유지&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8-3. 실전 Before vs After 코드 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-8-3-실전-before-vs-after-코드-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#8-3-%EC%8B%A4%EC%A0%84-before-vs-after-%EC%BD%94%EB%93%9C-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;❌ Before: if-else 중첩 방식 (코드가 오른쪽으로 계속 밀려남)&lt;/h4&gt;
&lt;a id=&quot;user-content--before-if-else-중첩-방식-코드가-오른쪽으로-계속-밀려남&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#-before-if-else-%EC%A4%91%EC%B2%A9-%EB%B0%A9%EC%8B%9D-%EC%BD%94%EB%93%9C%EA%B0%80-%EC%98%A4%EB%A5%B8%EC%AA%BD%EC%9C%BC%EB%A1%9C-%EA%B3%84%EC%86%8D-%EB%B0%80%EB%A0%A4%EB%82%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;lua&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;function handleSubmit() {
  if (input.value !== &quot;&quot;) {
    if (input.value.length &amp;gt;= 4) {
      // 핵심 로직 실행...
      console.log(&quot;저장 성공!&quot;);
    } else {
      alert(&quot;4자리 이상 입력해주세요.&quot;);
    }
  } else {
    alert(&quot;값을 입력해주세요.&quot;);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ After: 얼리 리턴(Early-Return) 패턴 (평탄하고 읽기 쉬움)&lt;/h4&gt;
&lt;a id=&quot;user-content--after-얼리-리턴early-return-패턴-평탄하고-읽기-쉬움&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#-after-%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4early-return-%ED%8C%A8%ED%84%B4-%ED%8F%89%ED%83%84%ED%95%98%EA%B3%A0-%EC%9D%BD%EA%B8%B0-%EC%89%AC%EC%9B%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;function handleSubmit() {
  // 1. 빈 값 예외 처리 ➔ 즉시 종료
  if (input.value.trim() === &quot;&quot;) {
    alert(&quot;이름을 입력하세요.&quot;);
    return; // 함수 강제 종료! 아래 코드는 거들떠보지도 않음
  }

  // 2. 글자수 예외 처리 ➔ 즉시 종료
  if (input.value.length &amp;lt; 4) {
    alert(&quot;4자리 이상 입력하세요.&quot;);
    return;
  }

  // 3. 모든 검문을 통과한 안전한 데이터만 핵심 로직 수행!
  console.log(&quot;저장 성공:&quot;, input.value);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. Web API란 무엇인가?&lt;/h2&gt;
&lt;a id=&quot;user-content-9-web-api란-무엇인가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#9-web-api%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-1. JavaScript 언어와 Web API의 차이점&lt;/h3&gt;
&lt;a id=&quot;user-content-9-1-javascript-언어와-web-api의-차이점&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#9-1-javascript-%EC%96%B8%EC%96%B4%EC%99%80-web-api%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;순수 JavaScript 언어 스펙(ECMAScript)&lt;/b&gt;: 변수, 조건문, 함수, 객체, 배열 등 순수한 문법과 계산 엔진 기능만 가지고 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Web API&lt;/b&gt;: **웹 브라우저 환경이 자바스크립트 엔진에게 선물로 제공하는 도구 상자(기능 모음)**입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저가 제공하므로 웹 페이지가 브라우저 기능(화면 그리기, 타이머, 로컬 저장소, 서버 네트워크 통신 등)과 상호작용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2290&quot; data-origin-height=&quot;964&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6EyUv/dJMcab0xFWO/95CVGCaOvhRbOgNKBjxDc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6EyUv/dJMcab0xFWO/95CVGCaOvhRbOgNKBjxDc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6EyUv/dJMcab0xFWO/95CVGCaOvhRbOgNKBjxDc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6EyUv%2FdJMcab0xFWO%2F95CVGCaOvhRbOgNKBjxDc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2290&quot; height=&quot;964&quot; data-origin-width=&quot;2290&quot; data-origin-height=&quot;964&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9-2. 브라우저 제공 Web API 5대 핵심 분류&lt;/h3&gt;
&lt;a id=&quot;user-content-9-2-브라우저-제공-web-api-5대-핵심-분류&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#9-2-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%A0%9C%EA%B3%B5-web-api-5%EB%8C%80-%ED%95%B5%EC%8B%AC-%EB%B6%84%EB%A5%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;API 분류&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;대표 메서드 / 객체&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;주요 역할 및 사용 목적&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;1. DOM API&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;document.querySelector,&lt;span&gt;&amp;nbsp;&lt;/span&gt;element.textContent,&lt;span&gt;&amp;nbsp;&lt;/span&gt;createElement&lt;/td&gt;
&lt;td&gt;HTML 요소를 선택하고, 내용을 바꾸고, 새 요소를 화면에 조작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;2. Event API&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;element.addEventListener&lt;/td&gt;
&lt;td&gt;클릭, 입력, 키보드, 마우스 등 사용자의 모든 인터랙션 감지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;3. Timer API&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;setTimeout,&lt;span&gt;&amp;nbsp;&lt;/span&gt;setInterval,&lt;span&gt;&amp;nbsp;&lt;/span&gt;clearTimeout,&lt;span&gt;&amp;nbsp;&lt;/span&gt;clearInterval&lt;/td&gt;
&lt;td&gt;시간 지연 후 실행, 주기적 반복 실행 등 시간 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;4. Storage API&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;localStorage,&lt;span&gt;&amp;nbsp;&lt;/span&gt;sessionStorage&lt;/td&gt;
&lt;td&gt;브라우저에 데이터를 반영구적 또는 세션 동안 보관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;5. Fetch API&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;fetch(&quot;&lt;a href=&quot;https://api.example.com/data&quot;&gt;https://api.example.com/data&lt;/a&gt;&quot;)&lt;/td&gt;
&lt;td&gt;새로고침 없이 백엔드 서버와 비동기로 데이터(JSON)를 송수신&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. Timer API 완벽 이해 (setTimeout,&lt;span&gt;&amp;nbsp;&lt;/span&gt;setInterval,&lt;span&gt;&amp;nbsp;&lt;/span&gt;timerId)&lt;/h2&gt;
&lt;a id=&quot;user-content-10-timer-api-완벽-이해-settimeout-setinterval-timerid&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#10-timer-api-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4-settimeout-setinterval-timerid&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10-1. 1회성 타이머:&lt;span&gt;&amp;nbsp;&lt;/span&gt;setTimeout&lt;/h3&gt;
&lt;a id=&quot;user-content-10-1-1회성-타이머-settimeout&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#10-1-1%ED%9A%8C%EC%84%B1-%ED%83%80%EC%9D%B4%EB%A8%B8-settimeout&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 지정한 시간(밀리초, 1000ms = 1초)이 지난 뒤에, 지정한 콜백 함수를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;딱 한 번만 실행&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 3초(3000ms) 뒤에 콘솔 출력
setTimeout(function () {
  console.log(&quot;3초 후 실행&quot;);
}, 3000);

// 화살표 함수 한 줄 축약형
setTimeout(() =&amp;gt; console.log(&quot;3초 후 실행&quot;), 3000);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11.   강의 슬라이드 실전 실습 과제 풀이 모음&lt;/h2&gt;
&lt;a id=&quot;user-content-11--강의-슬라이드-실전-실습-과제-풀이-모음&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#11--%EA%B0%95%EC%9D%98-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%93%9C-%EC%8B%A4%EC%A0%84-%EC%8B%A4%EC%8A%B5-%EA%B3%BC%EC%A0%9C-%ED%92%80%EC%9D%B4-%EB%AA%A8%EC%9D%8C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;강의 슬라이드에 등장한 모든 실습 과제의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문제, HTML 뼈대, JavaScript 완성 코드, 핵심 해설&lt;/b&gt;을 완벽하게 정리했습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실습 1: 버튼 클릭 이벤트 콘솔 출력&lt;/h3&gt;
&lt;a id=&quot;user-content-실습-1-버튼-클릭-이벤트-콘솔-출력&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-1-%EB%B2%84%ED%8A%BC-%ED%81%B4%EB%A6%AD-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%BD%98%EC%86%94-%EC%B6%9C%EB%A0%A5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: 버튼을 클릭하면 브라우저 콘솔에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;버튼 클릭됨&quot;을 출력하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#html&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;button id=&quot;btn&quot;&amp;gt;클릭&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#javascript&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;livescript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const btn = document.querySelector(&quot;#btn&quot;);

btn.addEventListener(&quot;click&quot;, function () {
  console.log(&quot;버튼 클릭됨&quot;);
});

//   모던 화살표 함수 버전:
// btn.addEventListener(&quot;click&quot;, () =&amp;gt; console.log(&quot;버튼 클릭됨&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실습 2: 버튼 클릭 시 텍스트 및 색상 변경&lt;/h3&gt;
&lt;a id=&quot;user-content-실습-2-버튼-클릭-시-텍스트-및-색상-변경&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-2-%EB%B2%84%ED%8A%BC-%ED%81%B4%EB%A6%AD-%EC%8B%9C-%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B0%8F-%EC%83%89%EC%83%81-%EB%B3%80%EA%B2%BD&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: 버튼을 클릭하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;h1&lt;span&gt;&amp;nbsp;&lt;/span&gt;태그의 텍스트를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;Hello JavaScript&quot;로 바꾸고, 글자 색상은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;빨간색&lt;/b&gt;으로 변경하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html-1&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#html-1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;h1 class=&quot;text&quot;&amp;gt;Hello&amp;lt;/h1&amp;gt;
&amp;lt;button id=&quot;change&quot;&amp;gt;변경&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-1&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#javascript-1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const h1 = document.querySelector(&quot;.text&quot;);
const button = document.querySelector(&quot;#change&quot;);

button.addEventListener(&quot;click&quot;, function () {
  // 1. 텍스트 내용 변경
  h1.textContent = &quot;Hello JavaScript&quot;;
  // 2. 인라인 글자 색상 스타일 변경
  h1.style.color = &quot;red&quot;;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실습 3: 비밀번호 실시간 길이 감지 및 유효성 피드백&lt;/h3&gt;
&lt;a id=&quot;user-content-실습-3-비밀번호-실시간-길이-감지-및-유효성-피드백&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-3-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EC%8B%A4%EC%8B%9C%EA%B0%84-%EA%B8%B8%EC%9D%B4-%EA%B0%90%EC%A7%80-%EB%B0%8F-%EC%9C%A0%ED%9A%A8%EC%84%B1-%ED%94%BC%EB%93%9C%EB%B0%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: 사용자가 비밀번호를 입력할 때마다 실시간으로 길이를 체크하여, 4자리 미만이면 빨간색으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;4자리 이상 입력하세요.&quot;, 4자리 이상이면 파란색으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;사용 가능한 비밀번호입니다.&quot;를 출력하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html-2&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#html-2&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;password&quot; id=&quot;pw-input&quot; placeholder=&quot;비밀번호 입력&quot;&amp;gt;
&amp;lt;p id=&quot;result&quot;&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-2&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#javascript-2&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const input = document.querySelector(&quot;#pw-input&quot;);
const result = document.querySelector(&quot;#result&quot;);

function validatePassword() {
  if (input.value.length &amp;lt; 4) {
    result.textContent = &quot;4자리 이상 입력하세요.&quot;;
    result.style.color = &quot;red&quot;;
  } else {
    result.textContent = &quot;사용 가능한 비밀번호입니다.&quot;;
    result.style.color = &quot;blue&quot;;
  }
}

// input 이벤트: 키를 누르거나 입력값이 변할 때마다 실시간 호출
input.addEventListener(&quot;input&quot;, validatePassword);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실습 4: 마우스 감지 이벤트 (호버 시 색상 전환)&lt;/h3&gt;
&lt;a id=&quot;user-content-실습-4-마우스-감지-이벤트-호버-시-색상-전환&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-4-%EB%A7%88%EC%9A%B0%EC%8A%A4-%EA%B0%90%EC%A7%80-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%ED%98%B8%EB%B2%84-%EC%8B%9C-%EC%83%89%EC%83%81-%EC%A0%84%ED%99%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: 박스 위에 마우스를 올리면 텍스트가 오렌지색(또는 배경이 skyblue), 마우스를 밖으로 내리면 원래대로 복구되게 만드세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html-3&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#html-3&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;p id=&quot;box&quot;&amp;gt;마우스를 올려보세요&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript (버전 A: 텍스트 및 테두리 변경)&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-버전-a-텍스트-및-테두리-변경&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#javascript-%EB%B2%84%EC%A0%84-a-%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B0%8F-%ED%85%8C%EB%91%90%EB%A6%AC-%EB%B3%80%EA%B2%BD&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;maxima&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const box = document.querySelector(&quot;#box&quot;);

function highlightText() {
  box.style.color = &quot;orange&quot;;
  box.style.border = &quot;1px solid orange&quot;;
}

function resetText() {
  box.style.color = &quot;black&quot;;
  box.style.border = &quot;none&quot;;
}

box.addEventListener(&quot;mouseover&quot;, highlightText);
box.addEventListener(&quot;mouseout&quot;, resetText);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript (버전 B: 화살표 함수를 활용한 배경색 변경)&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-버전-b-화살표-함수를-활용한-배경색-변경&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#javascript-%EB%B2%84%EC%A0%84-b-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B0%B0%EA%B2%BD%EC%83%89-%EB%B3%80%EA%B2%BD&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const box = document.querySelector(&quot;#box&quot;);

function changeBackgroundColor(color) {
  box.style.backgroundColor = color;
}

box.addEventListener(&quot;mouseover&quot;, () =&amp;gt; changeBackgroundColor(&quot;skyblue&quot;));
box.addEventListener(&quot;mouseout&quot;, () =&amp;gt; changeBackgroundColor(&quot;orange&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실습 5: 동적 입력값 처리 및 화면 렌더링 (DOM 추가)&lt;/h3&gt;
&lt;a id=&quot;user-content-실습-5-동적-입력값-처리-및-화면-렌더링-dom-추가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-5-%EB%8F%99%EC%A0%81-%EC%9E%85%EB%A0%A5%EA%B0%92-%EC%B2%98%EB%A6%AC-%EB%B0%8F-%ED%99%94%EB%A9%B4-%EB%A0%8C%EB%8D%94%EB%A7%81-dom-%EC%B6%94%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: 사용자가 텍스트를 입력하고 확인 버튼을 누르면 환영 문구를 담은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;p&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;태그를 동적으로 생성하여 결과 영역에 추가하세요. (빈 값 입력 시 얼리 리턴 처리)&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html-4&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#html-4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; id=&quot;name-input&quot; placeholder=&quot;이름을 입력하세요&quot;&amp;gt;
&amp;lt;button id=&quot;submit-btn&quot;&amp;gt;확인&amp;lt;/button&amp;gt;
&amp;lt;div id=&quot;result&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript (얼리 리턴 &amp;amp; createElement 결합)&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-얼리-리턴--createelement-결합&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#javascript-%EC%96%BC%EB%A6%AC-%EB%A6%AC%ED%84%B4--createelement-%EA%B2%B0%ED%95%A9&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;dart&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const input = document.querySelector(&quot;#name-input&quot;);
const button = document.querySelector(&quot;#submit-btn&quot;);
const result = document.querySelector(&quot;#result&quot;);

function printName() {
  // 1. [얼리 리턴] 빈 값 검증: 공백 제거 후 빈 문자열이면 즉시 차단
  if (input.value.trim() === &quot;&quot;) {
    alert(&quot;이름을 입력하세요&quot;);
    return;
  }

  // 2. 기존 결과 영역 초기화
  result.innerHTML = &quot;&quot;;

  // 3. 동적으로 새 &amp;lt;p&amp;gt; 태그 생성 및 내용 주입
  const welcomeText = &quot;환영합니다, &quot; + input.value + &quot; 님&quot;;
  const p = document.createElement(&quot;p&quot;);
  p.textContent = welcomeText;

  // 4. 화면(DOM)에 자식 요소로 추가
  result.appendChild(p);

  // 5. 사용 편의를 위해 입력창 비우기
  input.value = &quot;&quot;;
}

button.addEventListener(&quot;click&quot;, printName);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실습 6: Timer API 5초 카운트다운 타이머 완성&lt;/h3&gt;
&lt;a id=&quot;user-content-실습-6-timer-api-5초-카운트다운-타이머-완성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#%EC%8B%A4%EC%8A%B5-6-timer-api-5%EC%B4%88-%EC%B9%B4%EC%9A%B4%ED%8A%B8%EB%8B%A4%EC%9A%B4-%ED%83%80%EC%9D%B4%EB%A8%B8-%EC%99%84%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과제&lt;/b&gt;: &quot;카운트다운 시작&quot; 버튼을 누르면 5부터 1초마다 1씩 감소하고, 0이 되는 순간 카운트를 멈추고 화면에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;끝&quot;을 출력하는 타이머를 만드세요. (중복 클릭 방지 포함)&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;HTML&lt;/h4&gt;
&lt;a id=&quot;user-content-html-5&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#html-5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;button id=&quot;start&quot;&amp;gt;카운트다운 시작&amp;lt;/button&amp;gt;
&amp;lt;p id=&quot;result&quot;&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript (중복 방지 가드 &amp;amp; 타이머 클리어)&lt;/h4&gt;
&lt;a id=&quot;user-content-javascript-중복-방지-가드--타이머-클리어&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#javascript-%EC%A4%91%EB%B3%B5-%EB%B0%A9%EC%A7%80-%EA%B0%80%EB%93%9C--%ED%83%80%EC%9D%B4%EB%A8%B8-%ED%81%B4%EB%A6%AC%EC%96%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;const startBtn = document.querySelector(&quot;#start&quot;);
const timeEl = document.querySelector(&quot;#result&quot;);

let time = 5;
let timerId = null; // 실행 중인 타이머 번호를 보관하는 변수

startBtn.addEventListener(&quot;click&quot;, function () {
  //   1. 중복 실행 방지 가드 클로즈:
  // 이미 타이머가 실행 중(timerId !== null)이면 추가 클릭을 완벽히 무시!
  if (timerId !== null) return;

  // 초기 시작 숫자 화면에 즉시 표시
  timeEl.textContent = time;

  // 2. 1초(1000ms)마다 동작하는 인터벌 등록
  timerId = setInterval(function () {
    time--; // 1초마다 1씩 감소

    if (time === 0) {
      // 0초 도달 시 종료 처리
      timeEl.textContent = &quot;끝&quot;;
      clearInterval(timerId); // 타이머 반복 중단!
      timerId = null;         // 상태를 초기화하여 다시 시작할 수 있게 함
      time = 5;               // 다음 실행을 위해 시간 리셋
    } else {
      // 아직 시간이 남아있으면 남은 초 표시
      timeEl.textContent = time;
    }
  }, 1000);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-12--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day3/javascript-dom-event-webapi.md#12--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;qml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│                      DOM &amp;amp; Event &amp;amp; Web API 치트시트                    │
├────────────────────────────────┬───────────────────────────────────────┤
│ 개념 / 메서드                  │ 핵심 기능 및 설명                     │
├────────────────────────────────┼───────────────────────────────────────┤
│ return 생략                    │ 모든 JS 함수는 return 없으면          │
│                                │ 자동으로 undefined 를 반환한다!       │
├────────────────────────────────┼───────────────────────────────────────┤
│ DOM (Document Object Model)    │ 브라우저가 HTML을 파싱해 JS가 다룰 수 │
│                                │ 있게 만든 메모리 상의 '객체 트리'     │
├────────────────────────────────┼───────────────────────────────────────┤
│ HTML vs JS 역할 분담           │ 뼈대/공통 틀 = HTML                  │
│                                │ 동적 상태/인터랙션/로직 = JS(DOM)     │
├────────────────────────────────┼───────────────────────────────────────┤
│ document.querySelector(selector)│ CSS 선택자로 일치하는 첫 번째 요소 반환│
├────────────────────────────────┼───────────────────────────────────────┤
│ document.querySelectorAll(...) │ 일치하는 모든 요소를 NodeList로 반환  │
├────────────────────────────────┼───────────────────────────────────────┤
│ el.textContent = &quot;내용&quot;        │ 태그 내부 순수 텍스트 안전하게 변경   │
├────────────────────────────────┼───────────────────────────────────────┤
│ el.style.camelCase = &quot;값&quot;      │ 인라인 CSS 스타일 실시간 조작         │
├────────────────────────────────┼───────────────────────────────────────┤
│ document.createElement(&quot;태그&quot;) │ 메모리 상에 새로운 DOM 태그 객체 생성 │
├────────────────────────────────┼───────────────────────────────────────┤
│ parent.appendChild(child)      │ 생성한 태그를 화면(부모 노드)에 부착  │
├────────────────────────────────┼───────────────────────────────────────┤
│ addEventListener(&quot;click&quot;, fn)  │ 이벤트 발생 시 실행할 콜백 함수 등록   │
│                                │ ⚠️ 절대 fn() 처럼 괄호 붙이지 말 것! │
├────────────────────────────────┼───────────────────────────────────────┤
│ () =&amp;gt; { ... } (화살표 함수)   │ function 키워드를 줄인 모던 간결 문법 │
├────────────────────────────────┼───────────────────────────────────────┤
│ Early-Return (조기 반환)       │ 입구에서 유효성 검사 후 즉시 return;  │
│                                │ (Deep Nesting 방지 및 안정성 극대화)  │
├────────────────────────────────┼───────────────────────────────────────┤
│ Web API 5대장                  │ DOM, Event, Timer, Storage, Fetch     │
├────────────────────────────────┼───────────────────────────────────────┤
│ setTimeout(fn, ms)             │ ms(밀리초) 뒤에 fn 함수 딱 1회 실행   │
├────────────────────────────────┼───────────────────────────────────────┤
│ setInterval(fn, ms)            │ ms(밀리초) 간격으로 fn 함수 무한 반복 │
├────────────────────────────────┼───────────────────────────────────────┤
│ clearInterval(timerId)         │ 실행 중인 setInterval 반복 즉시 중단  │
├────────────────────────────────┼───────────────────────────────────────┤
│ if (timerId !== null) return;  │ 버튼 연타 시 타이머 중복 생성 방지    │
└────────────────────────────────┴───────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/32</guid>
      <comments>https://write31991.tistory.com/32#entry32comment</comments>
      <pubDate>Mon, 19 Oct 2026 16:49:01 +0900</pubDate>
    </item>
    <item>
      <title>HTML/CSS &amp;amp; Javascript 6일차</title>
      <link>https://write31991.tistory.com/31</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-has-sidebar=&quot;true&quot; data-component=&quot;SplitPageLayout&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div data-is-hidden-narrow=&quot;false&quot; data-component=&quot;SplitPageLayout.Content&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div id=&quot;repos-split-pane-content&quot; data-selector=&quot;repos-split-pane-content&quot;&gt;
&lt;div data-hpc=&quot;true&quot;&gt;
&lt;div&gt;
&lt;h1&gt;⚡ JavaScript 핵심 기초 문법 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content--javascript-핵심-기초-문법-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#-javascript-%ED%95%B5%EC%8B%AC-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹의 심장 **JavaScript의 정의와 4가지 실행 방법(Node.js 포함)**부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변수(let vs const)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;5대 기본 자료형과 Falsy 6대장&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;엄격한 비교(===)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;조건문 &amp;amp; 논리 연산 실전 과제&lt;/b&gt;, 그리고 **반복문과 배열 순회(for...of)**까지 총정리한 실전 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#1-javascript%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;JavaScript란 무엇인가?&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#1-1-%EC%9B%B9%EC%9D%98-3%EB%8C%80-%EC%9A%94%EC%86%8C-html-css-js%EC%9D%98-%EC%97%AD%ED%95%A0&quot;&gt;1-1. 웹의 3대 요소 (HTML, CSS, JS의 역할)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#1-2-javascript-%EC%8B%A4%ED%96%89-%EB%B0%A9%EB%B2%95-4%EA%B0%80%EC%A7%80&quot;&gt;1-2. JavaScript 실행 방법 4가지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#1-3-nodejs%EB%9E%80--%ED%84%B0%EB%AF%B8%EB%84%90-%ED%99%98%EA%B2%BD%EC%9D%98-4%EB%8C%80-%EC%9E%A5%EC%A0%90&quot;&gt;1-3. Node.js란? &amp;amp; 터미널 환경의 4대 장점&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#2-%EB%B3%80%EC%88%98-variable%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC-let-vs-const&quot;&gt;변수 (Variable)와 메모리: let vs const&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#2-1-%EB%B3%80%EC%88%98%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-%EA%B0%92-%EC%A0%80%EC%9E%A5&quot;&gt;2-1. 변수의 본질과 값 저장&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#2-2-let-vs-const-%ED%95%B5%EC%8B%AC-%EB%B9%84%EA%B5%90&quot;&gt;2-2. let vs const 핵심 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#2-3-%EB%B3%80%EC%88%98-%EC%84%A0%EC%96%B8-%EB%B0%A9%EC%8B%9D-%EB%B9%84%EA%B5%90-javascript-vs-python&quot;&gt;2-3. 변수 선언 방식 비교 (JavaScript vs Python)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#3-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95-data-types--null-vs-undefined&quot;&gt;기본 자료형 (Data Types) &amp;amp; null vs undefined&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#3-1-5%EB%8C%80-%ED%95%B5%EC%8B%AC-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95&quot;&gt;3-1. 5대 핵심 기본 자료형&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#3-2-null-vs-undefined%EC%9D%98-%EB%AA%85%ED%99%95%ED%95%9C-%EC%B0%A8%EC%9D%B4&quot;&gt;3-2. null vs undefined의 명확한 차이&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#4-%EC%97%B0%EC%82%B0%EC%9E%90-operators--%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98%EC%9D%98-%ED%95%A8%EC%A0%95&quot;&gt;연산자 (Operators) &amp;amp; 타입 변환의 함정&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#4-1-%EC%82%B0%EC%88%A0--%EB%B9%84%EA%B5%90--%EB%85%BC%EB%A6%AC-%EC%97%B0%EC%82%B0%EC%9E%90&quot;&gt;4-1. 산술 &amp;amp; 비교 &amp;amp; 논리 연산자&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#4-2-%EB%8F%99%EB%93%B1-vs-%EC%9D%BC%EC%B9%98-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%99%9C-%EB%A5%BC-%EC%8D%A8%EC%95%BC-%ED%95%A0%EA%B9%8C&quot;&gt;4-2. 동등(==) vs 일치(===) 연산자 (왜 ===를 써야 할까?)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#4-3-%EC%95%94%EB%AC%B5%EC%A0%81-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98-javascript-vs-python&quot;&gt;4-3. 암묵적 타입 변환 (JavaScript vs Python)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-%EC%A1%B0%EA%B1%B4%EB%AC%B8-if--else--truthy-vs-falsy&quot;&gt;조건문 (if / else) &amp;amp; Truthy vs Falsy&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-1-if--else-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95&quot;&gt;5-1. if / else 기본 문법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-2-falsy-6%EB%8C%80%EC%9E%A5-%EB%AC%B4%EC%A1%B0%EA%B1%B4-%EC%95%94%EA%B8%B0--truthy-%EA%B0%92&quot;&gt;5-2. Falsy 6대장 (무조건 암기!) &amp;amp; Truthy 값&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-3-%EC%8B%A4%EC%A0%84-%EC%8B%A4%EC%8A%B5-1-%EC%BD%98%EC%86%94-%EC%82%AC%EC%B9%99%EC%97%B0%EC%82%B0-%EA%B3%84%EC%82%B0%EA%B8%B0&quot;&gt;5-3. 실전 실습 1: 콘솔 사칙연산 계산기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-4-%EC%8B%A4%EC%A0%84-%EC%8B%A4%EC%8A%B5-2-%EB%B3%B5%ED%95%A9-%EC%A1%B0%EA%B1%B4-%ED%95%A9%EA%B2%A9-%ED%8C%90%EC%A0%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8&quot;&gt;5-4. 실전 실습 2: 복합 조건 합격 판정 프로그램&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#6-%EB%B0%98%EB%B3%B5%EB%AC%B8-loop-for-vs-while--%EB%B0%B0%EC%97%B4-array&quot;&gt;반복문 (Loop: for vs while) &amp;amp; 배열 (Array)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#6-1-for-%EB%B0%98%EB%B3%B5%EB%AC%B8%EA%B3%BC-while-%EB%B0%98%EB%B3%B5%EB%AC%B8-%EB%B9%84%EA%B5%90&quot;&gt;6-1. for 반복문과 while 반복문 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#6-2-%EB%B0%B0%EC%97%B4array%EC%9D%98-%EA%B5%AC%EC%A1%B0%EC%99%80-at-1-%EC%B5%9C%EC%8B%A0-%EC%9D%B8%EB%8D%B1%EC%8B%B1&quot;&gt;6-2. 배열(Array)의 구조와 at(-1) 최신 인덱싱&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#6-3-%ED%98%84%EB%8C%80%EC%A0%81-%EB%B0%B0%EC%97%B4-%EC%88%9C%ED%9A%8C-forof&quot;&gt;6-3. 현대적 배열 순회: for...of&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#7-%EA%B8%B0%EC%B6%9C-%EA%B0%9C%EB%85%90-%EC%A0%90%EA%B2%80-%ED%80%B4%EC%A6%88-4%EC%84%A0-%ED%92%80%EC%9D%B4&quot;&gt;기출 개념 점검 퀴즈 4선 풀이&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#8--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. JavaScript란 무엇인가?&lt;/h2&gt;
&lt;a id=&quot;user-content-1-javascript란-무엇인가&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#1-javascript%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. 웹의 3대 요소 (HTML, CSS, JS의 역할)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-웹의-3대-요소-html-css-js의-역할&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#1-1-%EC%9B%B9%EC%9D%98-3%EB%8C%80-%EC%9A%94%EC%86%8C-html-css-js%EC%9D%98-%EC%97%AD%ED%95%A0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;JavaScript&lt;/b&gt;: 웹 브라우저에서 동적으로 살아 숨 쉬는 기능을 구현하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인터프리터 프로그래밍 언어&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;사용자의 버튼 클릭 감지, 폼 입력값 검증, 서버와의 실시간 데이터 교환, 애니메이션 등 **&quot;동적 상호작용(Behavior)&quot;**을 전담합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2Lac1/dJMcahMYZ4V/RiLQvk4il2PkJXssUySfHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2Lac1/dJMcahMYZ4V/RiLQvk4il2PkJXssUySfHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2Lac1/dJMcahMYZ4V/RiLQvk4il2PkJXssUySfHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2Lac1%2FdJMcahMYZ4V%2FRiLQvk4il2PkJXssUySfHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;146&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-size: 1.44em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;1-2. JavaScript 실행 방법 4가지&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&amp;nbsp; &amp;nbsp;방법&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;실행 위치 및 방식&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;코드 예시&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;주요 용도
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;1. 브라우저 콘솔 (Console)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;크롬 개발자 도구(F12) ➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;Console&lt;span&gt;&amp;nbsp;&lt;/span&gt;탭&lt;/td&gt;
&lt;td&gt;console.log(1 + 2);&lt;/td&gt;
&lt;td&gt;즉시 실행, 빠른 문법 연습, 에러 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;2. 인라인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;script&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;태그&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;HTML 문서 내부&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;head&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;body&amp;gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;script&amp;gt; console.log(&quot;Hello&quot;); &amp;lt;/script&amp;gt;&lt;/td&gt;
&lt;td&gt;HTML과 한 파일에서 간단한 스크립트 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;3. 외부 JS 파일 분리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;별도의&lt;span&gt;&amp;nbsp;&lt;/span&gt;.js&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일을 생성해 HTML에 링크&lt;/td&gt;
&lt;td&gt;&amp;lt;script src=&quot;app.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;실무 표준!&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;코드의 모듈화와 유지보수성 극대화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;4. Node.js 터미널 실행&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;터미널 CLI 환경에서 직접 실행&lt;/td&gt;
&lt;td&gt;$ node app.js&lt;/td&gt;
&lt;td&gt;&lt;b&gt;브라우저 없이&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;백엔드/컴퓨터 환경에서 JS 단독 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3. Node.js란? &amp;amp; 터미널 환경의 4대 장점&lt;/h3&gt;
&lt;a id=&quot;user-content-1-3-nodejs란--터미널-환경의-4대-장점&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#1-3-nodejs%EB%9E%80--%ED%84%B0%EB%AF%B8%EB%84%90-%ED%99%98%EA%B2%BD%EC%9D%98-4%EB%8C%80-%EC%9E%A5%EC%A0%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Node.js&lt;/b&gt;: 웹 브라우저 안에서만 갇혀 살던 JavaScript를 **컴퓨터 OS(운영체제) 환경에서 독립적으로 실행할 수 있게 꺼내준 런타임 엔진(V8 기반)**입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Node.js의 4대 장점&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;환경이 단순&lt;/b&gt;: HTML, CSS 파일 없이 순수 JavaScript 문법만 집중 실행 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행이 초간단&lt;/b&gt;: 터미널에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;node app.js&lt;span&gt;&amp;nbsp;&lt;/span&gt;한 줄로 즉시 실행.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에러 추적 명확&lt;/b&gt;: 터미널에 스택 트레이스(Stack Trace)가 출력되어 몇 번째 줄에서 왜 에러가 났는지 원인 파악이 쉬움.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;초보자에게 친절&lt;/b&gt;: 문법적 오류를 브라우저 새로고침 없이 즉각 확인 가능.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;Note&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로그램을 설치(Install)한다는 것의 본질&lt;/b&gt;:&lt;br /&gt;웹에서 다운로드 ➔ 내 하드디스크에 저장 ➔ 실행 파일(바이너리)을 OS에 등록(이식) ➔ 터미널에서 명령어로 실행 시 컴퓨터 CPU가 코드를 한 줄씩 해석하여 동작!&lt;br /&gt;설치 확인 명령어:&lt;span&gt;&amp;nbsp;&lt;/span&gt;node -v,&lt;span&gt;&amp;nbsp;&lt;/span&gt;npm -v,&lt;span&gt;&amp;nbsp;&lt;/span&gt;git --version&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 변수 (Variable)와 메모리: let vs const&lt;/h2&gt;
&lt;a id=&quot;user-content-2-변수-variable와-메모리-let-vs-const&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#2-%EB%B3%80%EC%88%98-variable%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC-let-vs-const&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 변수의 본질과 값 저장&lt;/h3&gt;
&lt;a id=&quot;user-content-2-1-변수의-본질과-값-저장&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#2-1-%EB%B3%80%EC%88%98%EC%9D%98-%EB%B3%B8%EC%A7%88%EA%B3%BC-%EA%B0%92-%EC%A0%80%EC%9E%A5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;변수(Variable)&lt;/b&gt;: 데이터를 컴퓨터 메모리 공간에 저장하고, 그 공간에 **이름(식별자)**을 붙여 나중에 언제든&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;재사용&lt;/b&gt;할 수 있도록 하는 상자.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;let age = 20;            // age라는 이름의 상자에 숫자 20을 저장
const username = &quot;Alex&quot;; // username이라는 상자에 문자열 &quot;Alex&quot;를 고정 저장

console.log(age);        // 20 출력
console.log(username);   // Alex 출력&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. let vs const 핵심 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-let-vs-const-핵심-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#2-2-let-vs-const-%ED%95%B5%EC%8B%AC-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ece1I/dJMcacLTUGz/m8oJI7Tky3nd3vp4geLnGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ece1I/dJMcacLTUGz/m8oJI7Tky3nd3vp4geLnGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ece1I/dJMcacLTUGz/m8oJI7Tky3nd3vp4geLnGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEce1I%2FdJMcacLTUGz%2Fm8oJI7Tky3nd3vp4geLnGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;367&quot; height=&quot;267&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 1. let: 값 변경(재할당) 가능
let count = 1;
count = 2; // ✅ 정상 작동

// 2. const: 값 변경(재할당) 절대 불가 (상수 / Constant)
const pi = 3.14;
pi = 3.15; // ❌ TypeError: Assignment to constant variable!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #1a7f37;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #1a7f37;&quot; data-ke-size=&quot;size16&quot;&gt;Tip&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실무 꿀팁&lt;/b&gt;:&lt;br /&gt;기본적으로 모든 변수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;const를 기본값으로 사용&lt;/b&gt;하고, 오직 반복문의 카운터(i)나 상태가 명확히 바뀌어야 하는 변수만 **let**을 사용하세요. (과거의&lt;span&gt;&amp;nbsp;&lt;/span&gt;var는 스코프 오염 문제로 절대 사용하지 않습니다!)&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. 변수 선언 방식 비교 (JavaScript vs Python)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-3-변수-선언-방식-비교-javascript-vs-python&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#2-3-%EB%B3%80%EC%88%98-%EC%84%A0%EC%96%B8-%EB%B0%A9%EC%8B%9D-%EB%B9%84%EA%B5%90-javascript-vs-python&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&amp;nbsp; &amp;nbsp;언어&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 값 없이 변수 선언만 하는 문법&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;값 생략 시 초기 상태
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;Python&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;email&lt;span&gt;&amp;nbsp;&lt;/span&gt;❌ (에러 발생! 무조건&lt;span&gt;&amp;nbsp;&lt;/span&gt;email = None처럼 값을 줘야 함)&lt;/td&gt;
&lt;td&gt;초기값 필수 요구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;JavaScript&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;let email;&lt;span&gt;&amp;nbsp;&lt;/span&gt;⭕ (선언만 가능!)&lt;/td&gt;
&lt;td&gt;자동으로 **undefined**가 할당됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 기본 자료형 (Data Types) &amp;amp; null vs undefined&lt;/h2&gt;
&lt;a id=&quot;user-content-3-기본-자료형-data-types--null-vs-undefined&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#3-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95-data-types--null-vs-undefined&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. 5대 핵심 기본 자료형&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1-5대-핵심-기본-자료형&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#3-1-5%EB%8C%80-%ED%95%B5%EC%8B%AC-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 1. number: 정수와 실수 구분 없이 모두 number 타입
let a = 10;
let b = 3.14;
console.log(typeof a); // &quot;number&quot;

// 2. string: 큰따옴표(&quot; &quot;)나 작은따옴표(' ')로 감싼 문자열
let username = &quot;Alex&quot;;
console.log(typeof username); // &quot;string&quot;

// 3. boolean: 참(true) 또는 거짓(false)
let isStudent = true;
console.log(typeof isStudent); // &quot;boolean&quot;

// 4. null: 값이 의도적으로 비어 있음을 개발자가 명시한 상태
let selectedUser = null;
console.log(typeof selectedUser); // ⚠️ &quot;object&quot; (자바스크립트 초기 설계의 역사적 버그)

// 5. undefined: 변수 선언 후 아직 값이 할당되지 않아 비어있는 상태
let score;
console.log(typeof score); // &quot;undefined&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. null vs undefined의 명확한 차이&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2-null-vs-undefined의-명확한-차이&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#3-2-null-vs-undefined%EC%9D%98-%EB%AA%85%ED%99%95%ED%95%9C-%EC%B0%A8%EC%9D%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;nix&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────┐
│  let a = null;        ──▶ &quot;개발자가 의도적으로 비워둠&quot;    │
│  let b;               ──▶ &quot;아직 값을 안 정해서 자동으로 빔&quot; │
└────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
비교 항목nullundefined
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;의도적인 빈 값&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(휴지가 다 써서 빈 휴지걸이)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;아직 정의되지 않음&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(휴지걸이 자체가 없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;할당 주체&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;개발자&lt;/b&gt;가 직접 코드에 대입&lt;/td&gt;
&lt;td&gt;&lt;b&gt;자바스크립트 엔진&lt;/b&gt;이 자동으로 부여&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;typeof 결과&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&quot;object&quot;&lt;/td&gt;
&lt;td&gt;&quot;undefined&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;let a = null;
let b; // undefined

console.log(a == b);  // true  (느슨한 비교: 둘 다 빈 값이므로 같다고 인정)
console.log(a === b); // false (엄격한 비교: 타입이 object vs undefined로 다름!)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 연산자 (Operators) &amp;amp; 타입 변환의 함정&lt;/h2&gt;
&lt;a id=&quot;user-content-4-연산자-operators--타입-변환의-함정&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#4-%EC%97%B0%EC%82%B0%EC%9E%90-operators--%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98%EC%9D%98-%ED%95%A8%EC%A0%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 산술 &amp;amp; 비교 &amp;amp; 논리 연산자&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-산술--비교--논리-연산자&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#4-1-%EC%82%B0%EC%88%A0--%EB%B9%84%EA%B5%90--%EB%85%BC%EB%A6%AC-%EC%97%B0%EC%82%B0%EC%9E%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 1. 산술 연산자 (+, -, *, /)
let x = 10, y = 3;
console.log(x + y); // 13 (더하기)
console.log(x - y); // 7  (빼기)
console.log(x * y); // 30 (곱하기)
console.log(x / y); // 3.3333... (나누기)

// 2. 비교 연산자 (&amp;gt;, &amp;lt;, &amp;gt;=, &amp;lt;=) ➔ 결과는 무조건 boolean
console.log(10 &amp;gt; 5);   // true
console.log(10 &amp;lt;= 9);  // false

// 3. 논리 연산자 (&amp;amp;&amp;amp;, ||, !)
let age = 20, hasId = true;
console.log(age &amp;gt;= 19 &amp;amp;&amp;amp; hasId); // true (AND: 둘 다 참이어야 함)
console.log(age &amp;lt; 19 || hasId);  // true (OR: 둘 중 하나만 참이면 됨)
console.log(!hasId);             // false (NOT: 참/거짓 반전)

// 4. 문자열 연산자 (+)
let firstName = &quot;Alex&quot;, lastName = &quot;Kim&quot;;
console.log(firstName + &quot; &quot; + lastName); // &quot;Alex Kim&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. 동등(==) vs 일치(===) 연산자 (왜 ===를 써야 할까?)&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-동등-vs-일치-연산자-왜-를-써야-할까&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#4-2-%EB%8F%99%EB%93%B1-vs-%EC%9D%BC%EC%B9%98-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%99%9C-%EB%A5%BC-%EC%8D%A8%EC%95%BC-%ED%95%A0%EA%B9%8C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;==&lt;span&gt;&amp;nbsp;&lt;/span&gt;(동등 연산자)&lt;/b&gt;: 비교할 때 자바스크립트가 스스로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타입을 강제로 일치시킨 후 값만 비교&lt;/b&gt;합니다 (위험!).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;===&lt;span&gt;&amp;nbsp;&lt;/span&gt;(일치 연산자 - 권장)&lt;/b&gt;: **값과 데이터 타입이 모두 같아야만&lt;span&gt;&amp;nbsp;&lt;/span&gt;true**로 판정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;lua&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;console.log(10 == &quot;10&quot;);  // true  ⚠️ (숫자 10과 문자열 &quot;10&quot;을 같다고 판정!)
console.log(10 === &quot;10&quot;); // false ✅ (타입이 number vs string으로 다르므로 다름!)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3. 암묵적 타입 변환 (JavaScript vs Python)&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-암묵적-타입-변환-javascript-vs-python&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#4-3-%EC%95%94%EB%AC%B5%EC%A0%81-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98-javascript-vs-python&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;문자열 + 숫자 덧셈 시&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;JavaScript&lt;/b&gt;: 숫자를 자동으로 문자열로 바꿔서 연결해 버립니다! (&quot;10&quot; + 1 ➔ &quot;101&quot;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Python&lt;/b&gt;: 서로 다른 타입 덧셈을 허용하지 않고&lt;span&gt;&amp;nbsp;&lt;/span&gt;TypeError를 발생시킵니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 조건문 (if / else) &amp;amp; Truthy vs Falsy&lt;/h2&gt;
&lt;a id=&quot;user-content-5-조건문-if--else--truthy-vs-falsy&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-%EC%A1%B0%EA%B1%B4%EB%AC%B8-if--else--truthy-vs-falsy&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. if / else 기본 문법&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-if--else-기본-문법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-1-if--else-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;let age = 20;

if (age &amp;gt;= 19) {
  console.log(&quot;성인입니다.&quot;);
} else {
  console.log(&quot;미성년자입니다.&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. Falsy 6대장 (무조건 암기!) &amp;amp; Truthy 값&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-falsy-6대장-무조건-암기--truthy-값&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-2-falsy-6%EB%8C%80%EC%9E%A5-%EB%AC%B4%EC%A1%B0%EA%B1%B4-%EC%95%94%EA%B8%B0--truthy-%EA%B0%92&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 조건문(if) 괄호 안에 boolean이 아닌 일반 값을 넣었을 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자동으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;false로 취급되는 값은 전 우주에서 딱 6개뿐&lt;/b&gt;입니다:&lt;/p&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;❌ Falsy 값 (거짓으로 평가되는 6가지):&lt;/h4&gt;
&lt;a id=&quot;user-content--falsy-값-거짓으로-평가되는-6가지&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#-falsy-%EA%B0%92-%EA%B1%B0%EC%A7%93%EC%9C%BC%EB%A1%9C-%ED%8F%89%EA%B0%80%EB%90%98%EB%8A%94-6%EA%B0%80%EC%A7%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;false&lt;/li&gt;
&lt;li&gt;0&lt;span&gt;&amp;nbsp;&lt;/span&gt;(숫자 영)&lt;/li&gt;
&lt;li&gt;&quot;&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(빈 문자열)&lt;/li&gt;
&lt;li&gt;null&lt;/li&gt;
&lt;li&gt;undefined&lt;/li&gt;
&lt;li&gt;NaN&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Not a Number)&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;⭕ Truthy 값 (Falsy 6개를 제외한 세상의 모든 값!):&lt;/h4&gt;
&lt;a id=&quot;user-content--truthy-값-falsy-6개를-제외한-세상의-모든-값&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#-truthy-%EA%B0%92-falsy-6%EA%B0%9C%EB%A5%BC-%EC%A0%9C%EC%99%B8%ED%95%9C-%EC%84%B8%EC%83%81%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B0%92&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;⚠️&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;빈 배열&lt;span&gt;&amp;nbsp;&lt;/span&gt;[]은 Truthy!&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(배열 객체는 존재하므로 참!)&lt;/li&gt;
&lt;li&gt;⚠️&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;빈 객체&lt;span&gt;&amp;nbsp;&lt;/span&gt;{}도 Truthy!&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;⚠️&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문자열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;0&quot;도 Truthy!&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(글자가 1개 들어있는 문자열이므로 참!)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 실전 실습 1: 콘솔 사칙연산 계산기&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3-실전-실습-1-콘솔-사칙연산-계산기&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-3-%EC%8B%A4%EC%A0%84-%EC%8B%A4%EC%8A%B5-1-%EC%BD%98%EC%86%94-%EC%82%AC%EC%B9%99%EC%97%B0%EC%82%B0-%EA%B3%84%EC%82%B0%EA%B8%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;요구사항&lt;/b&gt;: 숫자 두 개와 연산자 기호(+,&lt;span&gt;&amp;nbsp;&lt;/span&gt;-,&lt;span&gt;&amp;nbsp;&lt;/span&gt;*,&lt;span&gt;&amp;nbsp;&lt;/span&gt;/)를 변수로 받아 결과 출력하기&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;nix&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;let a = 10;
let b = 5;
let operator = &quot;+&quot;; // &quot;+&quot;, &quot;-&quot;, &quot;*&quot;, &quot;/&quot; 중 선택

if (operator === &quot;+&quot;) {
  console.log(a + b);
} else if (operator === &quot;-&quot;) {
  console.log(a - b);
} else if (operator === &quot;*&quot;) {
  console.log(a * b);
} else if (operator === &quot;/&quot;) {
  console.log(a / b);
} else {
  console.log(&quot;지원하지 않는 연산자입니다.&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-4. 실전 실습 2: 복합 조건 합격 판정 프로그램&lt;/h3&gt;
&lt;a id=&quot;user-content-5-4-실전-실습-2-복합-조건-합격-판정-프로그램&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#5-4-%EC%8B%A4%EC%A0%84-%EC%8B%A4%EC%8A%B5-2-%EB%B3%B5%ED%95%A9-%EC%A1%B0%EA%B1%B4-%ED%95%A9%EA%B2%A9-%ED%8C%90%EC%A0%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;합격 조건&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;점수(score) 70 이상&lt;/li&gt;
&lt;li&gt;출석률(attendance) 80 이상&lt;/li&gt;
&lt;li&gt;과제 제출 여부(submitted)&lt;span&gt;&amp;nbsp;&lt;/span&gt;true&lt;/li&gt;
&lt;li&gt;&lt;b&gt;[단서 조항]&lt;/b&gt;: 단, 점수가 90점 이상이면 출석률은 미달이어도 합격!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;let score = 88;
let attendance = 75;
let submitted = true;

// 과제는 필수 제출 + (기본 기준 통과 또는 90점 이상 슈퍼패스)
if (submitted &amp;amp;&amp;amp; ((score &amp;gt;= 70 &amp;amp;&amp;amp; attendance &amp;gt;= 80) || score &amp;gt;= 90)) {
  console.log(&quot;최종 합격&quot;);
} else {
  console.log(&quot;불합격&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 반복문 (Loop: for vs while) &amp;amp; 배열 (Array)&lt;/h2&gt;
&lt;a id=&quot;user-content-6-반복문-loop-for-vs-while--배열-array&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#6-%EB%B0%98%EB%B3%B5%EB%AC%B8-loop-for-vs-while--%EB%B0%B0%EC%97%B4-array&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. for 반복문과 while 반복문 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-for-반복문과-while-반복문-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#6-1-for-%EB%B0%98%EB%B3%B5%EB%AC%B8%EA%B3%BC-while-%EB%B0%98%EB%B3%B5%EB%AC%B8-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;// 1. for 반복문 (반복 횟수가 정해져 있을 때 표준 사용)
// for (초기값; 조건식; 증감식)
for (let i = 1; i &amp;lt;= 3; i++) {
  console.log(i); // 1, 2, 3 출력
}

// 2. while 반복문 (특정 조건이 true인 동안 계속 반복 / 무한루프 주의!)
let i = 0;
while (i &amp;lt; 3) {
  console.log(i); // 0, 1, 2 출력
  i++;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2. 배열(Array)의 구조와 at(-1) 최신 인덱싱&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-배열array의-구조와-at-1-최신-인덱싱&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#6-2-%EB%B0%B0%EC%97%B4array%EC%9D%98-%EA%B5%AC%EC%A1%B0%EC%99%80-at-1-%EC%B5%9C%EC%8B%A0-%EC%9D%B8%EB%8D%B1%EC%8B%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 개의 값을 하나의 변수에 순서(0부터 시작하는 Index)대로 묶어 보관하는 자료형.&lt;/li&gt;
&lt;li&gt;요소마다 서로 다른 타입을 담을 수도 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;let numbers = [10, 20, 30];

console.log(numbers[0]);      // 10 (첫 번째 요소)
console.log(numbers.at(-1));   // 30 (⭐ 맨 마지막 요소를 가리키는 모던 JS 문법!)
console.log(numbers[3]);       // undefined (존재하지 않는 4번째 인덱스 접근 시)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-3. 현대적 배열 순회:&lt;span&gt;&amp;nbsp;&lt;/span&gt;for...of&lt;/h3&gt;
&lt;a id=&quot;user-content-6-3-현대적-배열-순회-forof&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#6-3-%ED%98%84%EB%8C%80%EC%A0%81-%EB%B0%B0%EC%97%B4-%EC%88%9C%ED%9A%8C-forof&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 안의 알맹이 데이터를 하나씩 꺼내어 순서대로 처리할 때 가장 간결하고 직관적인 반복문:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;let scores = [80, 90, 70];

for (const score of scores) {
  console.log(score); // 80 -&amp;gt; 90 -&amp;gt; 70 순차 출력
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 기출 개념 점검 퀴즈 4선 풀이&lt;/h2&gt;
&lt;a id=&quot;user-content-7-기출-개념-점검-퀴즈-4선-풀이&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#7-%EA%B8%B0%EC%B6%9C-%EA%B0%9C%EB%85%90-%EC%A0%90%EA%B2%80-%ED%80%B4%EC%A6%88-4%EC%84%A0-%ED%92%80%EC%9D%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q1. 다음 중 Node.js의 역할로 가장 적절한 것은?&lt;/h3&gt;
&lt;a id=&quot;user-content-q1-다음-중-nodejs의-역할로-가장-적절한-것은&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#q1-%EB%8B%A4%EC%9D%8C-%EC%A4%91-nodejs%EC%9D%98-%EC%97%AD%ED%95%A0%EB%A1%9C-%EA%B0%80%EC%9E%A5-%EC%A0%81%EC%A0%88%ED%95%9C-%EA%B2%83%EC%9D%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;① HTML을 꾸민다&lt;/li&gt;
&lt;li&gt;② JavaScript를 브라우저에서만 실행한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;③ 브라우저 없이 JavaScript를 실행한다 (정답 ✅)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;④ CSS를 컴파일한다&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해설&lt;/b&gt;: Node.js는 브라우저 외부 환경(컴퓨터 콘솔/서버)에서 JS를 독자적으로 실행할 수 있게 해주는 런타임 환경입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q2. 다음 코드의 출력 결과는?&lt;span&gt;&amp;nbsp;&lt;/span&gt;console.log(10 + &quot;5&quot;);&lt;/h3&gt;
&lt;a id=&quot;user-content-q2-다음-코드의-출력-결과는-consolelog10--5&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#q2-%EB%8B%A4%EC%9D%8C-%EC%BD%94%EB%93%9C%EC%9D%98-%EC%B6%9C%EB%A0%A5-%EA%B2%B0%EA%B3%BC%EB%8A%94-consolelog10--5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;①&lt;span&gt;&amp;nbsp;&lt;/span&gt;15&lt;/li&gt;
&lt;li&gt;②&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;15&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;③&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;105&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(정답 ✅)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;④ 에러 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해설&lt;/b&gt;: 숫자와 문자열을&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;연산하면 자바스크립트는 숫자를 문자열로 변환하여 두 문자열을 결합(&quot;10&quot; + &quot;5&quot; = &quot;105&quot;)합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q3. 다음 중 Falsy(거짓 같은 값)가 아닌 것은?&lt;/h3&gt;
&lt;a id=&quot;user-content-q3-다음-중-falsy거짓-같은-값가-아닌-것은&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#q3-%EB%8B%A4%EC%9D%8C-%EC%A4%91-falsy%EA%B1%B0%EC%A7%93-%EA%B0%99%EC%9D%80-%EA%B0%92%EA%B0%80-%EC%95%84%EB%8B%8C-%EA%B2%83%EC%9D%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;①&lt;span&gt;&amp;nbsp;&lt;/span&gt;0&lt;/li&gt;
&lt;li&gt;②&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;③&lt;span&gt;&amp;nbsp;&lt;/span&gt;[]&lt;span&gt;&amp;nbsp;&lt;/span&gt;(정답 ✅)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;④&lt;span&gt;&amp;nbsp;&lt;/span&gt;null&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해설&lt;/b&gt;: Falsy 6가지는&lt;span&gt;&amp;nbsp;&lt;/span&gt;false, 0, &quot;&quot;, null, undefined, NaN입니다. 빈 배열&lt;span&gt;&amp;nbsp;&lt;/span&gt;[]과 빈 객체&lt;span&gt;&amp;nbsp;&lt;/span&gt;{}는 메모리에 객체 상자가 생성된 상태이므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Truthy&lt;/b&gt;로 평가됩니다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;==&lt;span&gt;&amp;nbsp;&lt;/span&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;===&lt;span&gt;&amp;nbsp;&lt;/span&gt;의 차이로 옳은 설명은?&lt;/h3&gt;
&lt;a id=&quot;user-content-q4--와--의-차이로-옳은-설명은&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#q4--%EC%99%80--%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%A1%9C-%EC%98%B3%EC%9D%80-%EC%84%A4%EB%AA%85%EC%9D%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;① 차이가 없다&lt;/li&gt;
&lt;li&gt;②&lt;span&gt;&amp;nbsp;&lt;/span&gt;==&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 타입까지 비교한다&lt;/li&gt;
&lt;li&gt;③&lt;span&gt;&amp;nbsp;&lt;/span&gt;===&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 값만 비교한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;④&lt;span&gt;&amp;nbsp;&lt;/span&gt;===&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 값과 타입을 모두 비교한다 (정답 ✅)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해설&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;==는 자동 형변환이 일어나 값만 비교하지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;===는 데이터 타입까지 일치해야만 참으로 처리하는 엄격한 일치 연산자입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-8--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day2/javascript.md#8--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;livescript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;1. 변수 선언 공식
   - 기본은 무조건 const 사용!
   - 값이 나중에 바뀌는 경우(카운터 등)에만 let 사용

2. 엄격 비교 원칙
   - (X) if (a == b)   --&amp;gt; 암묵적 형변환 버그 위험
   - (O) if (a === b)  --&amp;gt; 값 + 타입 완벽 일치 검사

3. Falsy 6대장 외우기
   false, 0, &quot;&quot;, null, undefined, NaN
   (⚠️ [], {} 은 Falsy가 아니라 Truthy다!)

4. 배열 마지막 원소 접근
   arr.at(-1)  // arr[arr.length - 1]의 세련된 현대식 표현

5. 배열 순회 표준
   for (const item of items) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/31</guid>
      <comments>https://write31991.tistory.com/31#entry31comment</comments>
      <pubDate>Fri, 16 Oct 2026 17:53:10 +0900</pubDate>
    </item>
    <item>
      <title>HTML/CSS &amp;amp; Javascript 5일차</title>
      <link>https://write31991.tistory.com/30</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-has-sidebar=&quot;true&quot; data-component=&quot;SplitPageLayout&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div data-is-hidden-narrow=&quot;false&quot; data-component=&quot;SplitPageLayout.Content&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div id=&quot;repos-split-pane-content&quot; data-selector=&quot;repos-split-pane-content&quot;&gt;
&lt;div data-hpc=&quot;true&quot;&gt;
&lt;div&gt;
&lt;h1&gt;  CSS Grid &amp;amp; 부트스트랩(Bootstrap) UI 프레임워크 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content--css-grid--부트스트랩bootstrap-ui-프레임워크-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#-css-grid--%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9bootstrap-ui-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 바둑판 레이아웃 **CSS Grid(fr 단위&amp;middot;grid-template-areas&amp;middot;호버 효과)**부터 트위터의 오픈소스 UI 프레임워크&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부트스트랩 5(12칸 그리드&amp;middot;반응형 Navbar&amp;middot;모달 팝업)&lt;/b&gt;, 그리고 실무 한계점과 VS Code 팁까지 총정리한 실전 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#1-css-grid-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-2%EC%B0%A8%EC%9B%90-%EA%B5%AC%EC%A1%B0-%EC%84%A4%EA%B3%84&quot;&gt;CSS Grid 레이아웃: 2차원 구조 설계&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#1-1-grid%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EA%B8%B0%EC%88%A0%EB%B3%84-%EB%B9%84%EA%B5%90&quot;&gt;1-1. Grid의 정의와 레이아웃 기술별 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#1-2-grid-container-%EB%B6%80%EB%AA%A8%EC%99%80-grid-item-%EC%9E%90%EC%8B%9D&quot;&gt;1-2. Grid Container (부모)와 Grid Item (자식)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-grid-%ED%95%B5%EC%8B%AC-%EB%AC%B8%EB%B2%95--%EB%8B%A8%EC%9C%84-%EC%A0%95%EB%B3%B5&quot;&gt;Grid 핵심 문법 &amp;amp; 단위 정복&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-1-%EC%97%B4column-%EB%A7%8C%EB%93%A4%EA%B8%B0-repeat%EA%B3%BC-fr-%EB%8B%A8%EC%9C%84&quot;&gt;2-1. 열(Column) 만들기: repeat()과 fr 단위&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-2-%ED%96%89row-%EB%A7%8C%EB%93%A4%EA%B8%B0--gap-%EA%B0%84%EA%B2%A9-%EC%84%A4%EC%A0%95&quot;&gt;2-2. 행(Row) 만들기 &amp;amp; gap 간격 설정&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-3-%EC%B6%94%EC%B2%9C-grid-%EC%8B%A4%EC%A0%84-%EC%97%B0%EC%8A%B5-%EA%B2%8C%EC%9E%84-grid-garden&quot;&gt;2-3. [추천] Grid 실전 연습 게임: Grid Garden&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#3-%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1-grid-template-areas-%EB%B0%98%EC%9D%91%ED%98%95-%EA%B0%A4%EB%9F%AC%EB%A6%AC&quot;&gt;실전 프로젝트 1: grid-template-areas 반응형 갤러리&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#3-1-%EC%A7%81%EA%B4%80%EC%A0%81%EC%9D%B8-%EC%98%81%EC%97%AD-%EB%B0%B0%EC%B9%98-grid-template-areas&quot;&gt;3-1. 직관적인 영역 배치 (grid-template-areas)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#3-2-object-fit-cover%EC%99%80-%EA%B0%90%EC%84%B1-%ED%9D%91%EB%B0%B1-%ED%98%B8%EB%B2%84-%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98&quot;&gt;3-2. object-fit: cover와 감성 흑백 호버 인터랙션&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#3-3-%EA%B0%A4%EB%9F%AC%EB%A6%AC-%EC%99%84%EC%84%B1-%EC%A0%84%EC%B2%B4-%EC%BD%94%EB%93%9C-%EB%B6%84%EC%84%9D&quot;&gt;3-3. 갤러리 완성 전체 코드 분석&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9-bootstrap-5-ui-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC&quot;&gt;부트스트랩 (Bootstrap 5) UI 프레임워크&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-1-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9D%B4%EB%9E%80&quot;&gt;4-1. 부트스트랩이란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-2-cdn-%EC%84%A4%EC%B9%98-%EB%B0%8F-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-css--js-%EB%B2%88%EB%93%A4&quot;&gt;4-2. CDN 설치 및 환경 설정 (CSS &amp;amp; JS 번들)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-3-%ED%95%B5%EC%8B%AC-%EC%9C%A0%ED%8B%B8%EB%A6%AC%ED%8B%B0-flex-badge-button&quot;&gt;4-3. 핵심 유틸리티: Flex, Badge, Button&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-4-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9D%98-12%EC%B9%B8-grid-%EC%8B%9C%EC%8A%A4%ED%85%9C-container--row--col&quot;&gt;4-4. 부트스트랩의 12칸 Grid 시스템 (container ➔ row ➔ col)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#5-%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9-%ED%95%B5%EC%8B%AC-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-3%EC%84%A0&quot;&gt;실전 프로젝트 2: 부트스트랩 핵심 컴포넌트 3선&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#5-1-%EC%8B%A4%EC%8A%B5-1-3%EB%8B%A8-%EC%B9%B4%EB%93%9Ccard-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-col-md-4&quot;&gt;5-1. 실습 1: 3단 카드(Card) 레이아웃 (col-md-4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#5-2-%EC%8B%A4%EC%8A%B5-2-%EB%B0%98%EC%9D%91%ED%98%95-%ED%96%84%EB%B2%84%EA%B1%B0-%EB%A9%94%EB%89%B4-navigation-bar&quot;&gt;5-2. 실습 2: 반응형 햄버거 메뉴 Navigation Bar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#5-3-%EC%8B%A4%EC%8A%B5-3-%EC%9D%B8%ED%84%B0%EB%9E%99%ED%8B%B0%EB%B8%8C-modal-%EB%AA%A8%EB%8B%AC-%ED%8C%9D%EC%97%85%EC%B0%BD&quot;&gt;5-3. 실습 3: 인터랙티브 Modal (모달 팝업창)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#6-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9D%98-%EC%8B%A4%EB%AC%B4%EC%A0%81-%ED%95%9C%EA%B3%84--%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%BF%80%ED%8C%81&quot;&gt;부트스트랩의 실무적 한계 &amp;amp; 개발 환경 꿀팁&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#6-1-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9D%98-%EB%8B%A8%EC%A0%90%EA%B3%BC-tailwind-css-%EC%A0%84%ED%99%98-%ED%8A%B8%EB%A0%8C%EB%93%9C&quot;&gt;6-1. 부트스트랩의 단점과 Tailwind CSS 전환 트렌드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#6-2-vs-code-%ED%95%84%EC%88%98-%EC%84%A4%EC%A0%95-format-on-save-%EC%9E%90%EB%8F%99-%EB%93%A4%EC%97%AC%EC%93%B0%EA%B8%B0-%EC%A0%95%EB%A0%AC&quot;&gt;6-2. VS Code 필수 설정: Format On Save (자동 들여쓰기 정렬)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#7--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. CSS Grid 레이아웃: 2차원 구조 설계&lt;/h2&gt;
&lt;a id=&quot;user-content-1-css-grid-레이아웃-2차원-구조-설계&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#1-css-grid-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-2%EC%B0%A8%EC%9B%90-%EA%B5%AC%EC%A1%B0-%EC%84%A4%EA%B3%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. Grid의 정의와 레이아웃 기술별 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-grid의-정의와-레이아웃-기술별-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#1-1-grid%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EA%B8%B0%EC%88%A0%EB%B3%84-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CSS Grid&lt;/b&gt;: **행(Row, 가로 줄)**과 **열(Column, 세로 줄)**을 동시에 제어하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;2차원 바둑판식 레이아웃 시스템&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;페이지 전체의 거대한 골격 구조(뼈대) 자체를 설계할 때 가장 강력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GNIIN/dJMcagAz54f/PDtJqOXHBvI0VuLG3KxgVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GNIIN/dJMcagAz54f/PDtJqOXHBvI0VuLG3KxgVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GNIIN/dJMcagAz54f/PDtJqOXHBvI0VuLG3KxgVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGNIIN%2FdJMcagAz54f%2FPDtJqOXHBvI0VuLG3KxgVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;232&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; 기술.&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;차원&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;주요 목적&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 한계 및 적합한 상황&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;position&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;배지, 고정 헤더, 모달 팝업 등 특정 좌표 배치&lt;/td&gt;
&lt;td&gt;요소 간의 관계가 끊어지므로 전체 페이지 틀을 잡기엔 부적합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;flexbox&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;1차원&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;네비게이션 바 메뉴, 카드 내부 아이템 등 한 줄 정렬&lt;/td&gt;
&lt;td&gt;가로와 세로 줄을 동시에 맞추는 격자 바둑판 구조에는 비효율적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;Grid&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;2차원&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;대시보드, 매거진 갤러리, 쇼핑몰 상품 목록 격자&lt;/td&gt;
&lt;td&gt;&lt;b&gt;화면 전체 구조를 행과 열로 구획화할 때 최적&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. Grid Container (부모)와 Grid Item (자식)&lt;/h3&gt;
&lt;a id=&quot;user-content-1-2-grid-container-부모와-grid-item-자식&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#1-2-grid-container-%EB%B6%80%EB%AA%A8%EC%99%80-grid-item-%EC%9E%90%EC%8B%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Grid Container&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;display: grid;가 선언된 부모 요소 (바둑판 틀).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Grid Item&lt;/b&gt;: 컨테이너 바로 아래의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;직계 자식 요소들&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(바둑알).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;원칙&lt;/b&gt;: 모든 배치와 칸 나누기는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부모(Container)의 CSS 속성&lt;/b&gt;을 기준으로 결정됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt; &amp;lt;!-- Grid Container --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;A&amp;lt;/div&amp;gt; &amp;lt;!-- Grid Item --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;B&amp;lt;/div&amp;gt; &amp;lt;!-- Grid Item --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;C&amp;lt;/div&amp;gt; &amp;lt;!-- Grid Item --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;D&amp;lt;/div&amp;gt; &amp;lt;!-- Grid Item --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;E&amp;lt;/div&amp;gt; &amp;lt;!-- Grid Item --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;F&amp;lt;/div&amp;gt; &amp;lt;!-- Grid Item --&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Grid 핵심 문법 &amp;amp; 단위 정복&lt;/h2&gt;
&lt;a id=&quot;user-content-2-grid-핵심-문법--단위-정복&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-grid-%ED%95%B5%EC%8B%AC-%EB%AC%B8%EB%B2%95--%EB%8B%A8%EC%9C%84-%EC%A0%95%EB%B3%B5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 열(Column) 만들기: repeat()과 fr 단위&lt;/h3&gt;
&lt;a id=&quot;user-content-2-1-열column-만들기-repeat과-fr-단위&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-1-%EC%97%B4column-%EB%A7%8C%EB%93%A4%EA%B8%B0-repeat%EA%B3%BC-fr-%EB%8B%A8%EC%9C%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;grid-template-columns: 세로 열의 개수와 너비를 지정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.container {
  display: grid;

  /* 방법 1: 백분율로 4칸 분할 (25%씩 4개) */
  grid-template-columns: 25% 25% 25% 25%;

  /* 방법 2: repeat(반복횟수, 크기) 함수 사용 (위와 완벽히 동일) */
  grid-template-columns: repeat(4, 25%);

  /* 방법 3: fr(Fraction, 비율) 단위 사용 (1 : 2 : 1 비율로 유연 분할) */
  grid-template-columns: 1fr 2fr 1fr;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;lt; Note &amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;fr(Fraction) 단위란?&lt;/b&gt;&lt;br /&gt;그리드 컨테이너의 남은 여백 공간을 **비율(분수)**대로 나누어 갖는 그리드 전용 유연 단위입니다.&lt;br /&gt;1fr 2fr 1fr은 전체 가로폭을&lt;span&gt;&amp;nbsp;&lt;/span&gt;1 + 2 + 1 = 4등분하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;25% : 50% : 25%로 유연하게 배분합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. 행(Row) 만들기 &amp;amp; gap 간격 설정&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-행row-만들기--gap-간격-설정&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-2-%ED%96%89row-%EB%A7%8C%EB%93%A4%EA%B8%B0--gap-%EA%B0%84%EA%B2%A9-%EC%84%A4%EC%A0%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;grid-template-rows: 가로 행의 높이를 지정.&lt;/li&gt;
&lt;li&gt;grid-auto-rows: 명시되지 않고 자동으로 늘어나는 행들의 기본 높이 지정.&lt;/li&gt;
&lt;li&gt;gap: 그리드 아이템 사이의 여백 간격.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  
  /* 1행과 2행의 높이를 각각 80px로 고정 */
  grid-template-rows: 80px 80px;

  /* 아이템이 많아져 3행, 4행이 생길 때의 자동 높이 설정 */
  grid-auto-rows: 80px;

  /* 가로세로 아이템 사이 간격 10px */
  gap: 10px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. [추천] Grid 실전 연습 게임: Grid Garden&lt;/h3&gt;
&lt;a id=&quot;user-content-2-3-추천-grid-실전-연습-게임-grid-garden&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-3-%EC%B6%94%EC%B2%9C-grid-%EC%8B%A4%EC%A0%84-%EC%97%B0%EC%8A%B5-%EA%B2%8C%EC%9E%84-grid-garden&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;당근에 물을 주고 잡초를 뽑으며 Grid 속성을 단계별로 마스터하는 유명 학습 게임:&lt;/li&gt;
&lt;li&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;링크&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://cssgridgarden.com/#ko&quot;&gt;https://cssgridgarden.com/#ko&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 실전 프로젝트 1: grid-template-areas 반응형 갤러리&lt;/h2&gt;
&lt;a id=&quot;user-content-3-실전-프로젝트-1-grid-template-areas-반응형-갤러리&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#3-%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1-grid-template-areas-%EB%B0%98%EC%9D%91%ED%98%95-%EA%B0%A4%EB%9F%AC%EB%A6%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. 직관적인 영역 배치 (grid-template-areas)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1-직관적인-영역-배치-grid-template-areas&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#3-1-%EC%A7%81%EA%B4%80%EC%A0%81%EC%9D%B8-%EC%98%81%EC%97%AD-%EB%B0%B0%EC%B9%98-grid-template-areas&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자 선 번호 대신, **눈에 보이는 문자열 지도(ASCII Art 형태)**로 각 영역의 이름을 배치하는 가장 직관적인 그리드 기법입니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.container {
  display: grid;
  gap: 0.8rem;
  grid-template-columns: 1fr 1fr 1fr;         /* 3열 구조 */
  grid-template-rows: repeat(4, 200px);       /* 4행 (각 200px 높이) */

  /* 직관적인 바둑판 영역 지도 정의 */
  grid-template-areas:
    &quot;img1 img3 img3&quot;
    &quot;img1 img4 img6&quot;
    &quot;img2 img2 img6&quot;
    &quot;img5 img5 img5&quot;;
}

/* 각 아이템에 해당 영역 이름 부여 */
.img1 { grid-area: img1; }
.img2 { grid-area: img2; }
.img3 { grid-area: img3; }
.img4 { grid-area: img4; }
.img5 { grid-area: img5; }
.img6 { grid-area: img6; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;gcode&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌───────────┬───────────────────────┐
│   img1    │         img3          │  (img3은 2칸 차지)
├───────────┼───────────┬───────────┤
│   img1    │   img4    │   img6    │  (img1은 세로로 2칸)
├───────────┴───────────┼───────────┤
│         img2          │   img6    │  (img2는 가로 2칸, img6 세로 2칸)
├───────────────────────┴───────────┤
│               img5                │  (img5는 가로 전체 3칸 차지)
└───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;object-fit: cover와 감성 흑백 호버 인터랙션&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2-object-fit-cover와-감성-흑백-호버-인터랙션&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#3-2-object-fit-cover%EC%99%80-%EA%B0%90%EC%84%B1-%ED%9D%91%EB%B0%B1-%ED%98%B8%EB%B2%84-%EC%9D%B8%ED%84%B0%EB%9E%99%EC%85%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1)&lt;span&gt;&amp;nbsp;&lt;/span&gt;object-fit: cover;&lt;/h4&gt;
&lt;a id=&quot;user-content-1-object-fit-cover&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#1-object-fit-cover&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지의 가로세로 비율이 제각각이어도,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;원본 비율을 왜곡(찌그러짐) 없이 유지하며 지정된 박스에 꽉 채워주는 마법의 속성&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(넘치는 영역은 자연스럽게 잘림).&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;container:hover img:not(:hover)&lt;span&gt;&amp;nbsp;&lt;/span&gt;(포커스 호버 기법)&lt;/h4&gt;
&lt;a id=&quot;user-content-2-containerhover-imgnothover-포커스-호버-기법&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#2-containerhover-imgnothover-%ED%8F%AC%EC%BB%A4%EC%8A%A4-%ED%98%B8%EB%B2%84-%EA%B8%B0%EB%B2%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너에 마우스를 올렸을 때, **&quot;마우스가 올라가지 않은 나머지 모든 이미지들(:not(:hover))&quot;**에게만 흑백 필터와 투명도를 적용하여, 마우스가 닿은 사진 하나만 화려하게 돋보이게 만듭니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 기본 이미지 세팅 */
img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0.6rem;
  transition: 0.5s ease; /* 부드러운 전환 효과 */
}

/* 갤러리에 호버 시, 호버되지 않은 다른 이미지들은 흑백 + 반투명 처리 */
.container:hover img:not(:hover) {
  filter: grayscale(1); /* 100% 흑백 처리 */
  opacity: 0.5;         /* 반투명 처리 */
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-3. 갤러리 완성 전체 코드 분석&lt;/h3&gt;
&lt;a id=&quot;user-content-3-3-갤러리-완성-전체-코드-분석&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#3-3-%EA%B0%A4%EB%9F%AC%EB%A6%AC-%EC%99%84%EC%84%B1-%EC%A0%84%EC%B2%B4-%EC%BD%94%EB%93%9C-%EB%B6%84%EC%84%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;CSS Grid Gallery&amp;lt;/title&amp;gt;
  &amp;lt;style&amp;gt;
    .container {
      padding: 5% 10%;
      display: grid;
      gap: 0.8rem;
      grid-template-columns: 1fr 1fr 1fr;
      grid-template-rows: repeat(4, 200px);
      grid-template-areas:
        &quot;img1 img4 img4&quot;
        &quot;img1 img6 img3&quot;
        &quot;img2 img2 img3&quot;
        &quot;img5 img5 img5&quot;;
    }

    img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      border-radius: 0.6rem;
      transition: 0.5s;
    }

    .container:hover img:not(:hover) {
      filter: grayscale(1);
      opacity: 0.5;
    }

    .img1 { grid-area: img1; }
    .img2 { grid-area: img2; }
    .img3 { grid-area: img3; }
    .img4 { grid-area: img4; }
    .img5 { grid-area: img5; }
    .img6 { grid-area: img6; }
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div class=&quot;container&quot;&amp;gt;
    &amp;lt;div class=&quot;item img1&quot;&amp;gt;&amp;lt;img src=&quot;https://images.unsplash.com/photo-1787676560679-c6aefbac8767?w=900&quot; alt=&quot;사진1&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;item img2&quot;&amp;gt;&amp;lt;img src=&quot;https://images.unsplash.com/photo-1791921597945-adcedaed3115?w=900&quot; alt=&quot;사진2&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;item img3&quot;&amp;gt;&amp;lt;img src=&quot;https://images.unsplash.com/photo-1790274742524-5cc9cb0c10c3?w=900&quot; alt=&quot;사진3&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;item img4&quot;&amp;gt;&amp;lt;img src=&quot;https://images.unsplash.com/photo-1791889785364-39e79a18cd41?w=900&quot; alt=&quot;사진4&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;item img5&quot;&amp;gt;&amp;lt;img src=&quot;https://plus.unsplash.com/premium_photo-1791721702449-0db98c16f694?w=900&quot; alt=&quot;사진5&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;item img6&quot;&amp;gt;&amp;lt;img src=&quot;https://images.unsplash.com/photo-1791826119443-1bbbc2e35929?w=900&quot; alt=&quot;사진6&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 부트스트랩 (Bootstrap 5) UI 프레임워크&lt;/h2&gt;
&lt;a id=&quot;user-content-4-부트스트랩-bootstrap-5-ui-프레임워크&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9-bootstrap-5-ui-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 부트스트랩이란?&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-부트스트랩이란&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-1-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9D%B4%EB%9E%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;트위터(Twitter)에서 개발한 오픈소스 CSS &amp;amp; JavaScript UI 라이브러리 프레임워크&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;버튼, 카드, 팝업, 반응형 네비게이션 바 등 자주 쓰이는 UI 컴포넌트가 미리 다 만들어져 있어 **&quot;클래스 이름만 붙이면 완성도 높은 디자인이 완성&quot;**됩니다.&lt;/li&gt;
&lt;li&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;개발자가 복잡한 CSS를 직접 처음부터 작성하지 않아도 된다!&quot;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. CDN 설치 및 환경 설정 (CSS &amp;amp; JS 번들)&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-cdn-설치-및-환경-설정-css--js-번들&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-2-cdn-%EC%84%A4%EC%B9%98-%EB%B0%8F-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-css--js-%EB%B2%88%EB%93%A4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도의 npm 설치 없이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;head&amp;gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;body&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;끝에 링크 한 줄씩만 추가하면 즉시 가동됩니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;title&amp;gt;Bootstrap 실습&amp;lt;/title&amp;gt;
  &amp;lt;!-- 1. 부트스트랩 CSS CDN (스타일 적용) --&amp;gt;
  &amp;lt;link href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css&quot; rel=&quot;stylesheet&quot;&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

  &amp;lt;!-- 본문 내용 --&amp;gt;

  &amp;lt;!-- 2. 부트스트랩 JS 번들 CDN (모달 팝업, 햄버거 토글 등 동적 기능 필수) --&amp;gt;
  &amp;lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3. 핵심 유틸리티: Flex, Badge, Button&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-핵심-유틸리티-flex-badge-button&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-3-%ED%95%B5%EC%8B%AC-%EC%9C%A0%ED%8B%B8%EB%A6%AC%ED%8B%B0-flex-badge-button&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;!-- 1. Flex &amp;amp; 배지 (알림 뱃지) --&amp;gt;
&amp;lt;div class=&quot;d-flex justify-content-center align-items-center gap-2&quot;&amp;gt;
  &amp;lt;div&amp;gt;알림 목록&amp;lt;/div&amp;gt;
  &amp;lt;span class=&quot;badge bg-danger&quot;&amp;gt;5&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- 2. 사전 정의된 컬러풀 버튼들 --&amp;gt;
&amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;확인 (파란색)&amp;lt;/button&amp;gt;
&amp;lt;button class=&quot;btn btn-danger&quot;&amp;gt;취소 (빨간색)&amp;lt;/button&amp;gt;
&amp;lt;button class=&quot;btn btn-info&quot;&amp;gt;보류 (하늘색)&amp;lt;/button&amp;gt;
&amp;lt;button class=&quot;btn btn-secondary&quot;&amp;gt;닫기 (회색)&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-4. 부트스트랩의 12칸 Grid 시스템 (container ➔ row ➔ col)&lt;/h3&gt;
&lt;a id=&quot;user-content-4-4-부트스트랩의-12칸-grid-시스템-container--row--col&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#4-4-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9D%98-12%EC%B9%B8-grid-%EC%8B%9C%EC%8A%A4%ED%85%9C-container--row--col&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부트스트랩 그리드는 **화면 가로를 무조건 12개의 균등한 칸(Column)**으로 분할하여 계산합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│                   container (중앙 정렬 컨테이너)                         │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │                        row (행)                                  │  │
│  │  ┌───────────────────────────┬────────────────────────────────┐  │  │
│  │  │      col-6 (6칸 = 50%)    │       col-6 (6칸 = 50%)        │  │  │
│  │  └───────────────────────────┴────────────────────────────────┘  │  │
│  └──────────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공식:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;한 줄의&lt;span&gt;&amp;nbsp;&lt;/span&gt;col&lt;span&gt;&amp;nbsp;&lt;/span&gt;숫자 합이&lt;span&gt;&amp;nbsp;&lt;/span&gt;12가 되도록 조합&lt;/b&gt;합니다. (예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;col-6 + col-6,&lt;span&gt;&amp;nbsp;&lt;/span&gt;col-4 + col-4 + col-4)&lt;/li&gt;
&lt;li&gt;반응형 접두사:&lt;span&gt;&amp;nbsp;&lt;/span&gt;col-md-4&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔ 중간 화면(태블릿/PC) 이상에서는 4칸(3개씩), 작은 모바일에서는 12칸(1개씩 100%) 자동 전환!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 실전 프로젝트 2: 부트스트랩 핵심 컴포넌트 3선&lt;/h2&gt;
&lt;a id=&quot;user-content-5-실전-프로젝트-2-부트스트랩-핵심-컴포넌트-3선&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#5-%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9-%ED%95%B5%EC%8B%AC-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-3%EC%84%A0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. 실습 1: 3단 카드(Card) 레이아웃 (col-md-4)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-실습-1-3단-카드card-레이아웃-col-md-4&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#5-1-%EC%8B%A4%EC%8A%B5-1-3%EB%8B%A8-%EC%B9%B4%EB%93%9Ccard-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-col-md-4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 줄에 카드가 3개씩 나란히 놓이는 반응형 대시보드 카드 레이아웃:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container mt-5&quot;&amp;gt;
  &amp;lt;div class=&quot;row&quot;&amp;gt;
    &amp;lt;!-- 카드 1 (12칸 중 4칸 차지 = 1/3 크기) --&amp;gt;
    &amp;lt;div class=&quot;col-md-4 mb-3&quot;&amp;gt;
      &amp;lt;div class=&quot;card p-3 shadow-sm&quot;&amp;gt;
        &amp;lt;div class=&quot;card-body&quot;&amp;gt;
          &amp;lt;h5 class=&quot;card-title&quot;&amp;gt;기본 카드 1&amp;lt;/h5&amp;gt;
          &amp;lt;p class=&quot;card-text&quot;&amp;gt;설명 텍스트가 들어가는 본문 영역입니다.&amp;lt;/p&amp;gt;
          &amp;lt;a href=&quot;#&quot; class=&quot;btn btn-primary&quot;&amp;gt;상세보기&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;!-- 카드 2 --&amp;gt;
    &amp;lt;div class=&quot;col-md-4 mb-3&quot;&amp;gt;
      &amp;lt;div class=&quot;card p-3 shadow-sm&quot;&amp;gt;
        &amp;lt;div class=&quot;card-body&quot;&amp;gt;
          &amp;lt;h5 class=&quot;card-title&quot;&amp;gt;기본 카드 2&amp;lt;/h5&amp;gt;
          &amp;lt;p class=&quot;card-text&quot;&amp;gt;설명 텍스트가 들어가는 본문 영역입니다.&amp;lt;/p&amp;gt;
          &amp;lt;a href=&quot;#&quot; class=&quot;btn btn-primary&quot;&amp;gt;상세보기&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;!-- 카드 3 --&amp;gt;
    &amp;lt;div class=&quot;col-md-4 mb-3&quot;&amp;gt;
      &amp;lt;div class=&quot;card p-3 shadow-sm&quot;&amp;gt;
        &amp;lt;div class=&quot;card-body&quot;&amp;gt;
          &amp;lt;h5 class=&quot;card-title&quot;&amp;gt;기본 카드 3&amp;lt;/h5&amp;gt;
          &amp;lt;p class=&quot;card-text&quot;&amp;gt;설명 텍스트가 들어가는 본문 영역입니다.&amp;lt;/p&amp;gt;
          &amp;lt;a href=&quot;#&quot; class=&quot;btn btn-primary&quot;&amp;gt;상세보기&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. 실습 2: 반응형 햄버거 메뉴 Navigation Bar&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-실습-2-반응형-햄버거-메뉴-navigation-bar&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#5-2-%EC%8B%A4%EC%8A%B5-2-%EB%B0%98%EC%9D%91%ED%98%95-%ED%96%84%EB%B2%84%EA%B1%B0-%EB%A9%94%EB%89%B4-navigation-bar&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 코드를 직접 한 줄도 작성하지 않고, 오직&lt;span&gt;&amp;nbsp;&lt;/span&gt;data-bs-*&lt;span&gt;&amp;nbsp;&lt;/span&gt;속성만으로 모바일 햄버거 메뉴 열림/닫힘을 구현합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;nav class=&quot;navbar navbar-expand-lg navbar-dark bg-dark&quot;&amp;gt;
  &amp;lt;div class=&quot;container&quot;&amp;gt;
    &amp;lt;!-- 브랜드 로고 --&amp;gt;
    &amp;lt;a class=&quot;navbar-brand text-white&quot; href=&quot;#&quot;&amp;gt;MySite&amp;lt;/a&amp;gt;

    &amp;lt;!-- 모바일용 햄버거 토글 버튼 --&amp;gt;
    &amp;lt;button
      class=&quot;navbar-toggler&quot;
      type=&quot;button&quot;
      data-bs-toggle=&quot;collapse&quot;
      data-bs-target=&quot;#navMenu&quot;
    &amp;gt;
      &amp;lt;span class=&quot;navbar-toggler-icon&quot;&amp;gt;&amp;lt;/span&amp;gt;
    &amp;lt;/button&amp;gt;

    &amp;lt;!-- 메뉴 리스트 (화면 작을 땐 접히고, PC에선 펼쳐짐) --&amp;gt;
    &amp;lt;div class=&quot;collapse navbar-collapse&quot; id=&quot;navMenu&quot;&amp;gt;
      &amp;lt;ul class=&quot;navbar-nav ms-auto&quot;&amp;gt;
        &amp;lt;li class=&quot;nav-item&quot;&amp;gt;&amp;lt;a class=&quot;nav-link active&quot; href=&quot;#&quot;&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class=&quot;nav-item&quot;&amp;gt;&amp;lt;a class=&quot;nav-link&quot; href=&quot;#&quot;&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class=&quot;nav-item&quot;&amp;gt;&amp;lt;a class=&quot;nav-link&quot; href=&quot;#&quot;&amp;gt;Contact&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/nav&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 실습 3: 인터랙티브 Modal (모달 팝업창)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3-실습-3-인터랙티브-modal-모달-팝업창&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#5-3-%EC%8B%A4%EC%8A%B5-3-%EC%9D%B8%ED%84%B0%EB%9E%99%ED%8B%B0%EB%B8%8C-modal-%EB%AA%A8%EB%8B%AC-%ED%8C%9D%EC%97%85%EC%B0%BD&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 누르면 화면 중앙에 뜨는 다이얼로그 팝업의 3단계 구조입니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;!-- 1. 모달을 띄우는 트리거 버튼 --&amp;gt;
&amp;lt;div class=&quot;container mt-5 text-center&quot;&amp;gt;
  &amp;lt;button
    class=&quot;btn btn-primary&quot;
    data-bs-toggle=&quot;modal&quot;
    data-bs-target=&quot;#exampleModal&quot;
  &amp;gt;
    삭제 확인 모달 열기
  &amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- 2. 모달 팝업 본체 --&amp;gt;
&amp;lt;div class=&quot;modal fade&quot; id=&quot;exampleModal&quot; tabindex=&quot;-1&quot;&amp;gt;
  &amp;lt;div class=&quot;modal-dialog modal-dialog-centered&quot;&amp;gt;
    &amp;lt;div class=&quot;modal-content&quot;&amp;gt;
      
      &amp;lt;!-- 헤더 (제목 + 닫기 X 버튼) --&amp;gt;
      &amp;lt;div class=&quot;modal-header&quot;&amp;gt;
        &amp;lt;h5 class=&quot;modal-title&quot;&amp;gt;경고 알림&amp;lt;/h5&amp;gt;
        &amp;lt;button type=&quot;button&quot; class=&quot;btn-close&quot; data-bs-dismiss=&quot;modal&quot;&amp;gt;&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;!-- 바디 (본문 메시지) --&amp;gt;
      &amp;lt;div class=&quot;modal-body&quot;&amp;gt;
        정말로 영구 삭제하시겠습니까?
      &amp;lt;/div&amp;gt;

      &amp;lt;!-- 푸터 (취소/확인 버튼) --&amp;gt;
      &amp;lt;div class=&quot;modal-footer&quot;&amp;gt;
        &amp;lt;button type=&quot;button&quot; class=&quot;btn btn-secondary&quot; data-bs-dismiss=&quot;modal&quot;&amp;gt;취소&amp;lt;/button&amp;gt;
        &amp;lt;button type=&quot;button&quot; class=&quot;btn btn-danger&quot;&amp;gt;삭제 확정&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 부트스트랩의 실무적 한계 &amp;amp; 개발 환경 꿀팁&lt;/h2&gt;
&lt;a id=&quot;user-content-6-부트스트랩의-실무적-한계--개발-환경-꿀팁&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#6-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9D%98-%EC%8B%A4%EB%AC%B4%EC%A0%81-%ED%95%9C%EA%B3%84--%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%BF%80%ED%8C%81&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. 부트스트랩의 단점과 Tailwind CSS 전환 트렌드&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-부트스트랩의-단점과-tailwind-css-전환-트렌드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#6-1-%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9%EC%9D%98-%EB%8B%A8%EC%A0%90%EA%B3%BC-tailwind-css-%EC%A0%84%ED%99%98-%ED%8A%B8%EB%A0%8C%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;클래스 남용과 HTML 가독성 저하&lt;/b&gt;: 수많은 클래스가 태그에 덕지덕지 붙어 HTML 구조 파악이 어려워질 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디자인 커스텀의 한계&lt;/b&gt;: 이미 만들어진 스타일이 확고하여, 기업만의 개성 넘치는 독창적인 UI를 만들려면 부트스트랩의 기본 CSS를 강제로 덮어써야 하는 번거로움이 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최신 트렌드&lt;/b&gt;: 최근 실무 웹 서비스에서는 부트스트랩 대신 훨씬 자유도가 높고 최적화된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Tailwind CSS&lt;/b&gt;를 채택하는 경우가 매우 많습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2. VS Code 필수 설정: Format On Save (자동 들여쓰기 정렬)&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-vs-code-필수-설정-format-on-save-자동-들여쓰기-정렬&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#6-2-vs-code-%ED%95%84%EC%88%98-%EC%84%A4%EC%A0%95-format-on-save-%EC%9E%90%EB%8F%99-%EB%93%A4%EC%97%AC%EC%93%B0%EA%B8%B0-%EC%A0%95%EB%A0%AC&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 작성하고 저장(Ctrl + S&lt;span&gt;&amp;nbsp;&lt;/span&gt;/&lt;span&gt;&amp;nbsp;&lt;/span&gt;Cmd + S)할 때마다 삐뚤빼뚤한 들여쓰기와 태그 닫기를 에디터가 자동으로 칼같이 정렬해 주는 필수 설정입니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;VS Code에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Ctrl + ,&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Mac은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Cmd + ,&lt;/b&gt;) 단축키를 눌러&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;설정(Settings)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;창을 엽니다.&lt;/li&gt;
&lt;li&gt;검색창에 **format on save**를 입력합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Editor: Format On Save&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;항목의 체크박스를 **체크(✅)**합니다!&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-7--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/JS/day1/css-grid-bootstrap.md#7--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;haml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;1. CSS Grid 핵심
   - 2차원(가로/세로 동시) 레이아웃 시스템
   - repeat(3, 1fr) ➔ 3등분 자동 배분
   - gap: 10px ➔ 칸 사이 간격
   - grid-template-areas ➔ 시각적 바둑판 지도 배치
   - object-fit: cover ➔ 이미지 비율 찌그러짐 방지

2. Bootstrap 5 핵심
   - 12칸 그리드: container ➔ row ➔ col-md-4 (3칸씩)
   - data-bs-toggle=&quot;collapse/modal&quot; ➔ JS 없이 팝업/토글 제어
   - 모달 구조: modal ➔ modal-dialog ➔ modal-content (header/body/footer)

3. 개발 꿀팁
   - Grid 연습 게임: https://cssgridgarden.com/#ko
   - VS Code 저장 시 자동 정렬: Settings ➔ 'Format On Save' 체크&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/30</guid>
      <comments>https://write31991.tistory.com/30#entry30comment</comments>
      <pubDate>Thu, 15 Oct 2026 16:19:32 +0900</pubDate>
    </item>
    <item>
      <title>HTML/CSS &amp;amp; Javascript 4일차</title>
      <link>https://write31991.tistory.com/29</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h1&gt;  CSS 레이아웃 &amp;amp; 반응형 웹 마스터: Position, Flexbox &amp;amp; Media Query 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content--css-레이아웃--반응형-웹-마스터-position-flexbox--media-query-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#-css-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83--%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%A7%88%EC%8A%A4%ED%84%B0-position-flexbox--media-query-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;background-color: #ffffff; color: #59636e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Normal Flow의 한계 극복부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Position 4대 속성(static/relative/absolute/fixed)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Flexbox 1차원 레이아웃(주축&amp;middot;교차축&amp;middot;flex: 1)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Media Query 반응형 디자인&lt;/b&gt;, 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실전 반응형 네비게이션 바(Navbar) 구현&lt;/b&gt;까지 총정리한 실전 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#1-normal-flow-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EC%84%9C-%ED%9D%90%EB%A6%84%EC%99%80-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1&quot;&gt;Normal Flow (기본 문서 흐름)와 레이아웃의 필요성&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#1-1-normal-flow%EB%9E%80&quot;&gt;1-1. Normal Flow란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#1-2-normal-flow%EC%9D%98-%EB%B0%B0%EC%B9%98-%EA%B7%9C%EC%B9%99%EA%B3%BC-%ED%95%9C%EA%B3%84%EC%A0%90&quot;&gt;1-2. Normal Flow의 배치 규칙과 한계점&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-css-position-%EC%86%8D%EC%84%B1-%EC%9E%90%EC%9C%A0%EB%A1%9C%EC%9A%B4-%EC%9C%84%EC%B9%98-%EC%A0%9C%EC%96%B4&quot;&gt;CSS position 속성: 자유로운 위치 제어&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-1-position-%EC%86%8D%EC%84%B1%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%98%A4%ED%94%84%EC%85%8B-4%EB%8C%80%EC%9E%A5&quot;&gt;2-1. position 속성의 개념과 오프셋 4대장&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-2-static-%EA%B8%B0%EB%B3%B8%EA%B0%92&quot;&gt;2-2. static (기본값)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-3-relative-%EC%9B%90%EB%9E%98-%EC%9E%90%EA%B8%B0-%EC%9E%90%EB%A6%AC-%EA%B8%B0%EC%A4%80&quot;&gt;2-3. relative (원래 자기 자리 기준)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-4-absolute-%EA%B8%B0%EC%A4%80-%EC%A1%B0%EC%83%81-%EA%B8%B0%EC%A4%80--%EC%8B%A4%EB%AC%B4-%EA%B3%B5%EC%8B%9D&quot;&gt;2-4. absolute (기준 조상 기준) &amp;amp; 실무 공식&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-5-fixed-%ED%99%94%EB%A9%B4-%EB%B7%B0%ED%8F%AC%ED%8A%B8-%EA%B8%B0%EC%A4%80-%EC%98%81%EA%B5%AC-%EA%B3%A0%EC%A0%95&quot;&gt;2-5. fixed (화면 뷰포트 기준 영구 고정)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-6-position-4%EB%8C%80-%EC%86%8D%EC%84%B1-%ED%95%9C%EB%88%88%EC%97%90-%EB%B9%84%EA%B5%90%ED%95%98%EA%B8%B0&quot;&gt;2-6. position 4대 속성 한눈에 비교하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-flexbox-flexible-box-layout-1%EC%B0%A8%EC%9B%90-%EC%A0%95%EB%A0%AC-%EC%8B%9C%EC%8A%A4%ED%85%9C&quot;&gt;Flexbox (Flexible Box Layout): 1차원 정렬 시스템&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-1-flexbox%EC%9D%98-%ED%83%84%EC%83%9D-%EB%B0%B0%EA%B2%BD%EA%B3%BC-%ED%95%B5%EC%8B%AC-%ED%8A%B9%EC%A7%95&quot;&gt;3-1. Flexbox의 탄생 배경과 핵심 특징&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-2-flex-container-%EB%B6%80%EB%AA%A8-vs-flex-item-%EC%9E%90%EC%8B%9D&quot;&gt;3-2. Flex Container (부모) vs Flex Item (자식)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-3-%EC%A3%BC%EC%B6%95main-axis-vs-%EA%B5%90%EC%B0%A8%EC%B6%95cross-axis&quot;&gt;3-3. 주축(Main Axis) vs 교차축(Cross Axis)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-4-flexbox-%EC%A0%95%EB%A0%AC-3%EB%8B%A8%EA%B3%84-%ED%95%B5%EC%8B%AC-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0&quot;&gt;3-4. Flexbox 정렬 3단계 핵심 프로퍼티&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-5-%EC%8B%A4%EB%AC%B4-%EB%A7%88%EB%B2%95%EC%9D%98-%EC%BD%94%EB%93%9C-%EC%A0%95%EA%B0%80%EC%9A%B4%EB%8D%B0-%EC%A0%95%EB%A0%AC--flex-1-%EC%8A%A4%ED%8B%B0%ED%82%A4-%ED%91%B8%ED%84%B0&quot;&gt;3-5. 실무 마법의 코드: 정가운데 정렬 &amp;amp; flex: 1 스티키 푸터&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-6-%EC%B6%94%EC%B2%9C-flexbox-%EC%8B%A4%EC%A0%84-%EC%97%B0%EC%8A%B5-%EA%B2%8C%EC%9E%84-flexbox-froggy&quot;&gt;3-6. [추천] Flexbox 실전 연습 게임: Flexbox Froggy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#4-%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%94%94%EC%9E%90%EC%9D%B8-responsive-design--media-query&quot;&gt;반응형 웹 디자인 (Responsive Design) &amp;amp; Media Query&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#4-1-%EB%B0%98%EC%9D%91%ED%98%95-%EB%94%94%EC%9E%90%EC%9D%B8%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1&quot;&gt;4-1. 반응형 디자인의 필요성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#4-2-%EB%B0%98%EC%9D%91%ED%98%95%EC%9D%98-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%86%8C--rem-%ED%81%AC%EA%B8%B0-%EB%8B%A8%EC%9C%84&quot;&gt;4-2. 반응형의 3대 핵심 요소 &amp;amp; rem 크기 단위&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#4-3-media-query-%EB%AF%B8%EB%94%94%EC%96%B4-%EC%BF%BC%EB%A6%AC-%EB%AC%B8%EB%B2%95%EA%B3%BC-%EB%B6%84%EA%B8%B0%EC%A0%90&quot;&gt;4-3. Media Query (미디어 쿼리) 문법과 분기점&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#5-%EC%8B%A4%EC%A0%84-%EC%A2%85%ED%95%A9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B0%98%EC%9D%91%ED%98%95-%EB%84%A4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-%EB%B0%94-responsive-navbar&quot;&gt;실전 종합 프로젝트: 반응형 네비게이션 바 (Responsive Navbar)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#5-1-%EC%8B%9C%EB%A7%A8%ED%8B%B1-html-%EA%B5%AC%EC%A1%B0-%EC%84%A4%EA%B3%84-navbarhtml&quot;&gt;5-1. 시맨틱 HTML 구조 설계 (navbar.html)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#5-2-%EB%8D%B0%EC%8A%A4%ED%81%AC%ED%86%B1-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-css-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81-navbar_stylecss&quot;&gt;5-2. 데스크톱 레이아웃 CSS 스타일링 (navbar_style.css)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#5-3-%EB%AA%A8%EB%B0%94%EC%9D%BC-%EB%B0%98%EC%9D%91%ED%98%95-%EB%AF%B8%EB%94%94%EC%96%B4-%EC%BF%BC%EB%A6%AC-%EC%A0%81%EC%9A%A9-media-max-width-400px&quot;&gt;5-3. 모바일 반응형 미디어 쿼리 적용 (@media max-width: 400px)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#6--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Normal Flow (기본 문서 흐름)와 레이아웃의 필요성&lt;/h2&gt;
&lt;a id=&quot;user-content-1-normal-flow-기본-문서-흐름와-레이아웃의-필요성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#1-normal-flow-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EC%84%9C-%ED%9D%90%EB%A6%84%EC%99%80-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. Normal Flow란?&lt;/h3&gt;
&lt;a id=&quot;user-content-1-1-normal-flow란&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#1-1-normal-flow%EB%9E%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CSS에서 아무런 위치/레이아웃 속성도 적용하지 않았을 때 브라우저가 요소를 자동으로 배치하는 기본 규칙&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;웹 문서의 가장 자연스러운 원시적 흐름(Normal Flow)입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. Normal Flow의 배치 규칙과 한계점&lt;/h3&gt;
&lt;a id=&quot;user-content-1-2-normal-flow의-배치-규칙과-한계점&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#1-2-normal-flow%EC%9D%98-%EB%B0%B0%EC%B9%98-%EA%B7%9C%EC%B9%99%EA%B3%BC-%ED%95%9C%EA%B3%84%EC%A0%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Inline 요소&lt;/b&gt;: 텍스트를 쓸 때처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;왼쪽에서 오른쪽으로&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;나열되며, 공간이 꽉 차면 자동으로 다음 줄로 넘어갑니다 (span,&lt;span&gt;&amp;nbsp;&lt;/span&gt;a,&lt;span&gt;&amp;nbsp;&lt;/span&gt;strong).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Block-level 요소&lt;/b&gt;: 블록처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;위에서 아래로 한 줄 전체를 독점&lt;/b&gt;하며 벽돌을 쌓듯 차례로 배치됩니다 (div,&lt;span&gt;&amp;nbsp;&lt;/span&gt;p,&lt;span&gt;&amp;nbsp;&lt;/span&gt;h1).&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #9a6700;&quot; data-ke-size=&quot;size16&quot;&gt;Warning&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  Normal Flow의 치명적 한계&lt;/b&gt;:&lt;br /&gt;기본 흐름만으로는 현대 웹의 필수 요소인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;좌우 가로 정렬, 상하좌우 완전한 정가운데 정렬, 유연한 간격(gap) 조절, 특정 위치 고정(헤더/배지)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등을 구현하기가 극도로 어렵습니다.&lt;br /&gt;➔ 따라서 우리는 **position**과 **flexbox**를 통해 Normal Flow를 의도적으로 벗어나거나 제어합니다!&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. CSS position 속성: 자유로운 위치 제어&lt;/h2&gt;
&lt;a id=&quot;user-content-2-css-position-속성-자유로운-위치-제어&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-css-position-%EC%86%8D%EC%84%B1-%EC%9E%90%EC%9C%A0%EB%A1%9C%EC%9A%B4-%EC%9C%84%EC%B9%98-%EC%A0%9C%EC%96%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. position 속성의 개념과 오프셋 4대장&lt;/h3&gt;
&lt;a id=&quot;user-content-2-1-position-속성의-개념과-오프셋-4대장&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-1-position-%EC%86%8D%EC%84%B1%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%98%A4%ED%94%84%EC%85%8B-4%EB%8C%80%EC%9E%A5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 요소를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;어디에(Where), 무엇을 기준(Reference)으로&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;배치할지 결정하는 핵심 속성.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오프셋 프로퍼티&lt;/b&gt;: 기준점으로부터 얼마나 떨어질지 거리를 지정합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;top,&lt;span&gt;&amp;nbsp;&lt;/span&gt;bottom,&lt;span&gt;&amp;nbsp;&lt;/span&gt;left,&lt;span&gt;&amp;nbsp;&lt;/span&gt;right&lt;span&gt;&amp;nbsp;&lt;/span&gt;(px, rem, % 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;position: static&lt;span&gt;&amp;nbsp;&lt;/span&gt;(기본값)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-position-static-기본값&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-2-position-static-%EA%B8%B0%EB%B3%B8%EA%B0%92&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 HTML 요소의 태생적 기본값.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Normal Flow를 그대로 유지&lt;/b&gt;하며 일반적인 문서 흐름에 따라 배치됩니다.&lt;/li&gt;
&lt;li&gt;⚠️&lt;span&gt;&amp;nbsp;&lt;/span&gt;top,&lt;span&gt;&amp;nbsp;&lt;/span&gt;left,&lt;span&gt;&amp;nbsp;&lt;/span&gt;right,&lt;span&gt;&amp;nbsp;&lt;/span&gt;bottom&lt;span&gt;&amp;nbsp;&lt;/span&gt;오프셋 좌표를 적어도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;완전히 무시&lt;/b&gt;되어 적용되지 않습니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;position: relative&lt;span&gt;&amp;nbsp;&lt;/span&gt;(원래 자기 자리 기준)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-3-position-relative-원래-자기-자리-기준&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-3-position-relative-%EC%9B%90%EB%9E%98-%EC%9E%90%EA%B8%B0-%EC%9E%90%EB%A6%AC-%EA%B8%B0%EC%A4%80&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기준점&lt;/b&gt;: **&quot;내가 원래 있었어야 할 본래 위치&quot;**가 기준점(0, 0)이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Normal Flow 유지&lt;/b&gt;: 요소가 시각적으로 이동하더라도,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;원래 자리는 빈 공간(유령 자리)으로 그대로 보존&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;다른 인접 요소들의 레이아웃 배치에 전혀 영향을 주지 않습니다 (margin과 다른 점!).&lt;/li&gt;
&lt;li&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자식의&lt;span&gt;&amp;nbsp;&lt;/span&gt;absolute를 가두는 기준 조상 역할&lt;/b&gt;로 가장 많이 사용됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.box {
  position: relative;
  top: 30px;  /* 원래 위치에서 아래로 30px 이동 */
  left: 30px; /* 원래 위치에서 오른쪽으로 30px 이동 */
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;position: absolute&lt;span&gt;&amp;nbsp;&lt;/span&gt;(기준 조상 기준) &amp;amp; 실무 공식&lt;/h3&gt;
&lt;a id=&quot;user-content-2-4-position-absolute-기준-조상-기준--실무-공식&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-4-position-absolute-%EA%B8%B0%EC%A4%80-%EC%A1%B0%EC%83%81-%EA%B8%B0%EC%A4%80--%EC%8B%A4%EB%AC%B4-%EA%B3%B5%EC%8B%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기준점&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;가장 가까운&lt;span&gt;&amp;nbsp;&lt;/span&gt;position이 지정된 조상 요소&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(즉, static이 아닌 relative, absolute, fixed를 가진 부모).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Normal Flow에서 완전 제거&lt;/b&gt;: 붕 떠오르면서(부유) 원래 차지하던 자리가 사라집니다. 주변 요소들이 빈자리를 메우기 위해 당겨집니다.&lt;/li&gt;
&lt;li&gt;기준이 될 포지셔닝 부모가 없으면 **브라우저 화면(Viewport / 초기 컨테이닝 블록)**을 기준으로 배치됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  실무 100% 필수 공식: &quot;부모 relative + 자식 absolute&quot;&lt;/h4&gt;
&lt;a id=&quot;user-content--실무-100-필수-공식-부모-relative--자식-absolute&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#-%EC%8B%A4%EB%AC%B4-100-%ED%95%84%EC%88%98-%EA%B3%B5%EC%8B%9D-%EB%B6%80%EB%AA%A8-relative--%EC%9E%90%EC%8B%9D-absolute&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
  &amp;lt;div class=&quot;box&quot;&amp;gt;BOX&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 1. 부모에게 기준점 부여 */
.container {
  width: 200px;
  height: 200px;
  border: 3px solid #333;
  position: relative; /* 자식의 absolute 좌표 기준점이 됨! */
}

/* 2. 자식은 부모 안에서 자유자재로 이동 */
.box {
  width: 100px;
  height: 100px;
  background: #4caf50;
  position: absolute;
  top: 0px;
  left: 0px; /* 부모 컨테이너의 좌상단(0, 0)에 정확히 밀착 */
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  실전 활용 예제: 우상단 링크/배지 고정&lt;/h4&gt;
&lt;a id=&quot;user-content--실전-활용-예제-우상단-링크배지-고정&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#-%EC%8B%A4%EC%A0%84-%ED%99%9C%EC%9A%A9-%EC%98%88%EC%A0%9C-%EC%9A%B0%EC%83%81%EB%8B%A8-%EB%A7%81%ED%81%AC%EB%B0%B0%EC%A7%80-%EA%B3%A0%EC%A0%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.korean-link {
  position: absolute;
  top: 10px;
  right: 10px; /* 부모의 오른쪽 위 모서리에 고정 */
  color: darkcyan;
  font-size: small;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-5.&lt;span&gt;&amp;nbsp;&lt;/span&gt;position: fixed&lt;span&gt;&amp;nbsp;&lt;/span&gt;(화면 뷰포트 기준 영구 고정)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-5-position-fixed-화면-뷰포트-기준-영구-고정&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-5-position-fixed-%ED%99%94%EB%A9%B4-%EB%B7%B0%ED%8F%AC%ED%8A%B8-%EA%B8%B0%EC%A4%80-%EC%98%81%EA%B5%AC-%EA%B3%A0%EC%A0%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기준점&lt;/b&gt;: 부모가 누구든 상관없이 무조건 **브라우저 화면 전체(Viewport)**가 기준점.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Normal Flow에서 완전히 제거됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;페이지를 아무리 길게 스크롤해도 화면의 지정된 그 위치에 못 박힌 듯 영구 고정&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;주요 사용처:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;상단 고정 헤더(Navigation Bar)&lt;/b&gt;, 화면 우하단&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;맨 위로 가기 플로팅 버튼&lt;/b&gt;, 챗봇 상담 아이콘.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.fixed-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%; /* 화면 상단 전체를 덮는 고정 바 */
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-6. position 4대 속성 한눈에 비교하기&lt;/h3&gt;
&lt;a id=&quot;user-content-2-6-position-4대-속성-한눈에-비교하기&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-6-position-4%EB%8C%80-%EC%86%8D%EC%84%B1-%ED%95%9C%EB%88%88%EC%97%90-%EB%B9%84%EA%B5%90%ED%95%98%EA%B8%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;속성값기준점 (Reference)Normal Flow 이탈 여부원래 자리 보존 여부스크롤 시 동작&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;static&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;일반적인 문서 흐름&lt;/td&gt;
&lt;td&gt;❌ (유지)&lt;/td&gt;
&lt;td&gt;⭕ (보존)&lt;/td&gt;
&lt;td&gt;함께 스크롤됨 (위치 이동 불가)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;relative&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;자신의 본래 위치&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;❌ (유지)&lt;/td&gt;
&lt;td&gt;⭕ (원래 자리 비어있음)&lt;/td&gt;
&lt;td&gt;함께 스크롤됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;absolute&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;포지셔닝된 가장 가까운 조상&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;⭕ (완전 제거)&lt;/td&gt;
&lt;td&gt;❌ (자리 사라짐)&lt;/td&gt;
&lt;td&gt;함께 스크롤됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;fixed&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;브라우저 화면 (Viewport)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;⭕ (완전 제거)&lt;/td&gt;
&lt;td&gt;❌ (자리 사라짐)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;화면에 영구 고정 (스크롤 무시)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Flexbox (Flexible Box Layout): 1차원 정렬 시스템&lt;/h2&gt;
&lt;a id=&quot;user-content-3-flexbox-flexible-box-layout-1차원-정렬-시스템&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-flexbox-flexible-box-layout-1%EC%B0%A8%EC%9B%90-%EC%A0%95%EB%A0%AC-%EC%8B%9C%EC%8A%A4%ED%85%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. Flexbox의 탄생 배경과 핵심 특징&lt;/h3&gt;
&lt;a id=&quot;user-content-3-1-flexbox의-탄생-배경과-핵심-특징&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-1-flexbox%EC%9D%98-%ED%83%84%EC%83%9D-%EB%B0%B0%EA%B2%BD%EA%B3%BC-%ED%95%B5%EC%8B%AC-%ED%8A%B9%EC%A7%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;목적&lt;/b&gt;: 복잡한 계산 없이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;여러 박스를 한 방향(가로 or 세로)으로 유연하게 배치하고 정렬&lt;/b&gt;하기 위한 최신 CSS 레이아웃 시스템.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 특징&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;1차원 레이아웃&lt;/b&gt;: 가로(Row) 또는 세로(Column) 중 한 방향 축을 기준으로 정렬.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부모 중심 제어&lt;/b&gt;: 부모(Container)에게 속성을 주면 자식(Items)들의 배치가 일괄 통제됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;직관적인 간격과 정렬&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;gap,&lt;span&gt;&amp;nbsp;&lt;/span&gt;justify-content,&lt;span&gt;&amp;nbsp;&lt;/span&gt;align-items로 손쉬운 여백 제어.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. Flex Container (부모) vs Flex Item (자식)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-2-flex-container-부모-vs-flex-item-자식&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-2-flex-container-%EB%B6%80%EB%AA%A8-vs-flex-item-%EC%9E%90%EC%8B%9D&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;부모 요소에&lt;span&gt;&amp;nbsp;&lt;/span&gt;display: flex;를 선언하는 순간, 즉시 Flex 환경이 가동됩니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt; &amp;lt;!-- Flex Container (부모) --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;A&amp;lt;/div&amp;gt; &amp;lt;!-- Flex Item (자식) --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;B&amp;lt;/div&amp;gt; &amp;lt;!-- Flex Item (자식) --&amp;gt;
  &amp;lt;div class=&quot;item&quot;&amp;gt;C&amp;lt;/div&amp;gt; &amp;lt;!-- Flex Item (자식) --&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.container {
  display: flex; /* 자식들이 기본적으로 가로(row) 방향으로 나란히 정렬됨 */
  gap: 10px;     /* 자식 아이템 사이의 간격을 10px로 균등 배치 */
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-3. 주축(Main Axis) vs 교차축(Cross Axis)&lt;/h3&gt;
&lt;a id=&quot;user-content-3-3-주축main-axis-vs-교차축cross-axis&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-3-%EC%A3%BC%EC%B6%95main-axis-vs-%EA%B5%90%EC%B0%A8%EC%B6%95cross-axis&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Flexbox는 항상&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;두 개의 직교하는 축&lt;/b&gt;을 기준으로 요소를 정렬합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;less&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;[기본값: flex-direction: row 인 경우]

  주축 (Main Axis: 가로) ➔ justify-content 로 정렬
  ────────────────────────────────────────────────────────►
 │ [Item A]   [Item B]   [Item C]
 │
 │ 교차축 (Cross Axis: 세로) ➔ align-items 로 정렬
 ▼
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;주축 (Main Axis)&lt;/b&gt;: 아이템들이 배치되는 기본 진행 방향 (기본값:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가로 방향&lt;span&gt;&amp;nbsp;&lt;/span&gt;row&lt;/b&gt;).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교차축 (Cross Axis)&lt;/b&gt;: 주축과 90도로 교차하는 수직 방향 (기본값:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;세로 방향&lt;span&gt;&amp;nbsp;&lt;/span&gt;column&lt;/b&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-4. Flexbox 정렬 3단계 핵심 프로퍼티&lt;/h3&gt;
&lt;a id=&quot;user-content-3-4-flexbox-정렬-3단계-핵심-프로퍼티&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-4-flexbox-%EC%A0%95%EB%A0%AC-3%EB%8B%A8%EA%B3%84-%ED%95%B5%EC%8B%AC-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 1단계: 주축의 방향 결정 (flex-direction)&lt;/h4&gt;
&lt;a id=&quot;user-content-1-1단계-주축의-방향-결정-flex-direction&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#1-1%EB%8B%A8%EA%B3%84-%EC%A3%BC%EC%B6%95%EC%9D%98-%EB%B0%A9%ED%96%A5-%EA%B2%B0%EC%A0%95-flex-direction&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flex-direction: row;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(기본값) ➔ 왼쪽에서 오른쪽으로 가로 배치&lt;/li&gt;
&lt;li&gt;flex-direction: column;&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔ 위에서 아래로 세로 배치 (모바일 반응형에서 필수!)&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 2단계: 주축 방향의 정렬 결정 (justify-content)&lt;/h4&gt;
&lt;a id=&quot;user-content-2-2단계-주축-방향의-정렬-결정-justify-content&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#2-2%EB%8B%A8%EA%B3%84-%EC%A3%BC%EC%B6%95-%EB%B0%A9%ED%96%A5%EC%9D%98-%EC%A0%95%EB%A0%AC-%EA%B2%B0%EC%A0%95-justify-content&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flex-start&lt;span&gt;&amp;nbsp;&lt;/span&gt;(기본값): 시작 지점으로 정렬&lt;/li&gt;
&lt;li&gt;center:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;주축 기준 가운데 정렬&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;flex-end: 끝 지점으로 정렬&lt;/li&gt;
&lt;li&gt;space-between:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;양 끝을 벽에 붙이고, 아이템 사이 간격을 균등하게 배분 (네비게이션 바 필수!)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;space-around&lt;span&gt;&amp;nbsp;&lt;/span&gt;/&lt;span&gt;&amp;nbsp;&lt;/span&gt;space-evenly: 아이템 둘레/사이를 균등 분배&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) 3단계: 교차축 방향의 정렬 결정 (align-items)&lt;/h4&gt;
&lt;a id=&quot;user-content-3-3단계-교차축-방향의-정렬-결정-align-items&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-3%EB%8B%A8%EA%B3%84-%EA%B5%90%EC%B0%A8%EC%B6%95-%EB%B0%A9%ED%96%A5%EC%9D%98-%EC%A0%95%EB%A0%AC-%EA%B2%B0%EC%A0%95-align-items&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stretch&lt;span&gt;&amp;nbsp;&lt;/span&gt;(기본값): 부모의 높이만큼 아이템을 늘림&lt;/li&gt;
&lt;li&gt;center:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;교차축 기준 수직 가운데 정렬&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;flex-start&lt;span&gt;&amp;nbsp;&lt;/span&gt;/&lt;span&gt;&amp;nbsp;&lt;/span&gt;flex-end: 상단 또는 하단 정렬&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-5. 실무 마법의 코드: 정가운데 정렬 &amp;amp; flex: 1 스티키 푸터&lt;/h3&gt;
&lt;a id=&quot;user-content-3-5-실무-마법의-코드-정가운데-정렬--flex-1-스티키-푸터&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-5-%EC%8B%A4%EB%AC%B4-%EB%A7%88%EB%B2%95%EC%9D%98-%EC%BD%94%EB%93%9C-%EC%A0%95%EA%B0%80%EC%9A%B4%EB%8D%B0-%EC%A0%95%EB%A0%AC--flex-1-%EC%8A%A4%ED%8B%B0%ED%82%A4-%ED%91%B8%ED%84%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  마법 1: 박스 안의 글자/요소를 상하좌우 완전 정가운데 놓기&lt;/h4&gt;
&lt;a id=&quot;user-content--마법-1-박스-안의-글자요소를-상하좌우-완전-정가운데-놓기&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#-%EB%A7%88%EB%B2%95-1-%EB%B0%95%EC%8A%A4-%EC%95%88%EC%9D%98-%EA%B8%80%EC%9E%90%EC%9A%94%EC%86%8C%EB%A5%BC-%EC%83%81%ED%95%98%EC%A2%8C%EC%9A%B0-%EC%99%84%EC%A0%84-%EC%A0%95%EA%B0%80%EC%9A%B4%EB%8D%B0-%EB%86%93%EA%B8%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.item {
  display: flex;
  justify-content: center; /* 가로(주축) 가운데 */
  align-items: center;     /* 세로(교차축) 가운데 */
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  마법 2:&lt;span&gt;&amp;nbsp;&lt;/span&gt;flex: 1&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔ 남은 공간 혼자 다 차지하기 (Sticky Footer 패턴)&lt;/h4&gt;
&lt;a id=&quot;user-content--마법-2-flex-1--남은-공간-혼자-다-차지하기-sticky-footer-패턴&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#-%EB%A7%88%EB%B2%95-2-flex-1--%EB%82%A8%EC%9D%80-%EA%B3%B5%EA%B0%84-%ED%98%BC%EC%9E%90-%EB%8B%A4-%EC%B0%A8%EC%A7%80%ED%95%98%EA%B8%B0-sticky-footer-%ED%8C%A8%ED%84%B4&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;콘텐츠가 적은 페이지에서도 푸터(Footer)가 화면 중간에 뜨지 않고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;항상 브라우저 맨 바닥에 달라붙게 만드는 실무 표준 기법&lt;/b&gt;:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;body {
  min-height: 100vh;       /* 화면 전체 높이 보장 */
  display: flex;
  flex-direction: column;  /* 세로 방향으로 쌓기 */
}

main {
  flex: 1;                 /* ⭐ 메인 콘텐츠가 화면의 남은 여백을 전부 차지하여 푸터를 맨 밑으로 밀어냄! */
}

footer {
  margin-bottom: 2rem;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-6. [추천] Flexbox 실전 연습 게임: Flexbox Froggy&lt;/h3&gt;
&lt;a id=&quot;user-content-3-6-추천-flexbox-실전-연습-게임-flexbox-froggy&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#3-6-%EC%B6%94%EC%B2%9C-flexbox-%EC%8B%A4%EC%A0%84-%EC%97%B0%EC%8A%B5-%EA%B2%8C%EC%9E%84-flexbox-froggy&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개구리를 연잎 위에 올려놓으며 Flexbox 정렬 속성을 직관적으로 마스터하는 세계적인 학습 게임:&lt;/li&gt;
&lt;li&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;링크&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://flexboxfroggy.com/#ko&quot;&gt;https://flexboxfroggy.com/#ko&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 반응형 웹 디자인 (Responsive Design) &amp;amp; Media Query&lt;/h2&gt;
&lt;a id=&quot;user-content-4-반응형-웹-디자인-responsive-design--media-query&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#4-%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%94%94%EC%9E%90%EC%9D%B8-responsive-design--media-query&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 반응형 디자인의 필요성&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-반응형-디자인의-필요성&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#4-1-%EB%B0%98%EC%9D%91%ED%98%95-%EB%94%94%EC%9E%90%EC%9D%B8%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스마트폰, 태블릿, 데스크톱 모니터 등&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자의 화면 크기(Viewport)와 디바이스 환경이 다양화&lt;/b&gt;됨에 따라, 화면에 맞춰 레이아웃과 폰트 크기가 자연스럽게 재배치되는 웹을 구축해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. 반응형의 3대 핵심 요소 &amp;amp; rem 크기 단위&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-반응형의-3대-핵심-요소--rem-크기-단위&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#4-2-%EB%B0%98%EC%9D%91%ED%98%95%EC%9D%98-3%EB%8C%80-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%86%8C--rem-%ED%81%AC%EA%B8%B0-%EB%8B%A8%EC%9C%84&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;유연한 레이아웃&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;Flexbox,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Grid&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유연한 상대 크기 단위&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;%,&lt;span&gt;&amp;nbsp;&lt;/span&gt;vw,&lt;span&gt;&amp;nbsp;&lt;/span&gt;vh,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;rem&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조건부 스타일&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Media Query (@media)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;p style=&quot;color: #0969da;&quot; data-ke-size=&quot;size16&quot;&gt;Note&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;rem&lt;span&gt;&amp;nbsp;&lt;/span&gt;단위란?&lt;/b&gt;&lt;br /&gt;rem(Root em)은 최상위&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;html&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;태그의 기본 폰트 크기(보통 16px)를 기준으로 비례하는 상대 단위입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1rem&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 16px&lt;/li&gt;
&lt;li&gt;2.4rem&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 약 38.4px (대제목)&lt;/li&gt;
&lt;li&gt;0.9rem&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 약 14.4px (작은 본문/라벨)&lt;br /&gt;모바일이나 사용자 설정에 따라 기본 글꼴이 커지면 모든 요소가 아름답게 함께 확대/축소됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3. Media Query (미디어 쿼리) 문법과 분기점&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-media-query-미디어-쿼리-문법과-분기점&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#4-3-media-query-%EB%AF%B8%EB%94%94%EC%96%B4-%EC%BF%BC%EB%A6%AC-%EB%AC%B8%EB%B2%95%EA%B3%BC-%EB%B6%84%EA%B8%B0%EC%A0%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: **&quot;화면이 이 조건(크기)에 부합하면, 아래 스타일을 덮어써서 적용하라!&quot;**는 조건부 CSS 규칙.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 화면 너비가 400px 이하인 작은 스마트폰 화면일 때만 실행 */
@media (max-width: 400px) {
  .container {
    flex-direction: column; /* 가로 나열을 세로 쌓기로 변경 */
  }
  .box {
    background: orange;     /* 배경색 변경 */
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 실전 종합 프로젝트: 반응형 네비게이션 바 (Responsive Navbar)&lt;/h2&gt;
&lt;a id=&quot;user-content-5-실전-종합-프로젝트-반응형-네비게이션-바-responsive-navbar&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#5-%EC%8B%A4%EC%A0%84-%EC%A2%85%ED%95%A9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B0%98%EC%9D%91%ED%98%95-%EB%84%A4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-%EB%B0%94-responsive-navbar&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;강의 슬라이드에서 완성한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;PC에서는 가로 1줄, 모바일(400px 이하)에서는 세로로 깔끔하게 떨어지는 반응형 상단 메뉴바&lt;/b&gt;의 완성 코드입니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. 시맨틱 HTML 구조 설계 (navbar.html)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-시맨틱-html-구조-설계-navbarhtml&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#5-1-%EC%8B%9C%EB%A7%A8%ED%8B%B1-html-%EA%B5%AC%EC%A1%B0-%EC%84%A4%EA%B3%84-navbarhtml&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
  &amp;lt;title&amp;gt;반응형 Navigation Bar&amp;lt;/title&amp;gt;
  &amp;lt;!-- Font Awesome CDN 및 외부 스타일시트 연결 --&amp;gt;
  &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css&quot; /&amp;gt;
  &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;navbar_style.css&quot; /&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;nav class=&quot;navbar&quot;&amp;gt;
    &amp;lt;!-- 1. 좌측 로고 --&amp;gt;
    &amp;lt;div class=&quot;navbar__logo&quot;&amp;gt;
      &amp;lt;i class=&quot;fa-brands fa-dev&quot;&amp;gt;&amp;lt;/i&amp;gt;
      &amp;lt;a href=&quot;#&quot;&amp;gt;qu3vipon&amp;lt;/a&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;!-- 2. 중앙 메뉴 링크 --&amp;gt;
    &amp;lt;ul class=&quot;navbar__menu&quot;&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;a href=&quot;resume.html&quot;&amp;gt;Resume&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;Gallery&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;

    &amp;lt;!-- 3. 우측 SNS 아이콘 --&amp;gt;
    &amp;lt;ul class=&quot;navbar__icons&quot;&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;i class=&quot;fa-brands fa-github&quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;i class=&quot;fa-brands fa-x-twitter&quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/nav&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. 데스크톱 기본 스타일 (navbar_style.css)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-데스크톱-기본-스타일-navbar_stylecss&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#5-2-%EB%8D%B0%EC%8A%A4%ED%81%AC%ED%86%B1-%EA%B8%B0%EB%B3%B8-%EC%8A%A4%ED%83%80%EC%9D%BC-navbar_stylecss&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 기본 리셋 및 폰트 */
body {
  margin: 0;
  font-family: &quot;BBH Bogle&quot;, sans-serif;
}

a {
  text-decoration: none;
  color: black;
}

/* 네비게이션 컨테이너: flex 3등분 좌우 분배 */
.navbar {
  display: flex;
  justify-content: space-between; /* 로고 - 메뉴 - 아이콘을 양 끝과 중앙에 고루 배치 */
  align-items: center;            /* 수직 가운데 정렬 */
  background-color: beige;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
}

.navbar__logo {
  font-size: 1.4rem;
}

/* 메뉴 리스트: 가로 flex 배치 */
.navbar__menu {
  display: flex;
  list-style: none;
  padding: 0;
}

.navbar__menu li {
  padding: 8px 12px;
}

.navbar__menu li:hover {
  background-color: white;
  border-radius: 8px;
}

/* SNS 아이콘 리스트: 가로 flex 배치 */
.navbar__icons {
  display: flex;
  list-style: none;
  padding: 0;
}

.navbar__icons li {
  padding: 8px 4px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 모바일 반응형 미디어 쿼리 (@media (max-width: 400px))&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3-모바일-반응형-미디어-쿼리-media-max-width-400px&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#5-3-%EB%AA%A8%EB%B0%94%EC%9D%BC-%EB%B0%98%EC%9D%91%ED%98%95-%EB%AF%B8%EB%94%94%EC%96%B4-%EC%BF%BC%EB%A6%AC-media-max-width-400px&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;화면 너비가 좁아지면 가로 정렬을 **세로 1열(column)**로 전환하여 화면 찌그러짐을 방지합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;@media (max-width: 400px) {
  /* 1. 전체 바를 세로로 쌓고 왼쪽 정렬 */
  .navbar {
    flex-direction: column;
    align-items: flex-start;
    padding: 16px;
  }

  /* 2. 메뉴 항목을 가로폭 100% 차지하게 늘리고 텍스트 중앙 정렬 */
  .navbar__menu {
    flex-direction: column;
    width: 100%;
    text-align: center;
  }

  /* 3. 아이콘 모음도 중앙 정렬 */
  .navbar__icons {
    justify-content: center;
    width: 100%;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-6--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day3/CSS2.md#6--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;1. position 핵심 공식
   - static   : 기본 흐름 (top/left 무시)
   - relative : 원래 내 자리 기준 (부모 기준점 잡기용)
   - absolute : 가장 가까운 포지셔닝 부모 기준 (자식 부유 배치)
   - fixed    : 화면 창(viewport) 기준 (스크롤해도 영구 고정)
     공식: 부모에 position: relative 주고 자식에 position: absolute 주기!

2. Flexbox 정렬 공식
   - display: flex;                     (가로 정렬 가동)
   - justify-content: center;           (주축 가로 가운데)
   - align-items: center;               (교차축 세로 가운데)
   - justify-content: space-between;    (양 끝 벌리기)
   - flex: 1;                           (남은 빈 공간 다 차지하기)

3. 반응형 Media Query 공식
   @media (max-width: 768px) {
     /* 모바일/태블릿용 스타일 작성 (flex-direction: column 등) */
   }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/29</guid>
      <comments>https://write31991.tistory.com/29#entry29comment</comments>
      <pubDate>Wed, 14 Oct 2026 16:04:15 +0900</pubDate>
    </item>
    <item>
      <title>HTML/CSS &amp;amp; Javascript 3일차</title>
      <link>https://write31991.tistory.com/28</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-has-sidebar=&quot;true&quot; data-component=&quot;SplitPageLayout&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div&gt;
&lt;div data-is-hidden-narrow=&quot;false&quot; data-component=&quot;SplitPageLayout.Content&quot;&gt;
&lt;div data-width=&quot;full&quot;&gt;
&lt;div id=&quot;repos-split-pane-content&quot; data-selector=&quot;repos-split-pane-content&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-hpc=&quot;true&quot;&gt;
&lt;div&gt;
&lt;h1&gt;  CSS 핵심 마스터: 선택자(Selector), 우선순위, 박스 모델 &amp;amp; 디스플레이 완벽 정리 노트&lt;/h1&gt;
&lt;a id=&quot;user-content--css-핵심-마스터-선택자selector-우선순위-박스-모델--디스플레이-완벽-정리-노트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#-css-%ED%95%B5%EC%8B%AC-%EB%A7%88%EC%8A%A4%ED%84%B0-%EC%84%A0%ED%83%9D%EC%9E%90selector-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84-%EB%B0%95%EC%8A%A4-%EB%AA%A8%EB%8D%B8--%EB%94%94%EC%8A%A4%ED%94%8C%EB%A0%88%EC%9D%B4-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%EB%85%B8%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS 적용 방식(Internal vs External)부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모든 종류의 선택자(기본&amp;middot;결합&amp;middot;속성&amp;middot;가상 클래스)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;선택자 우선순위 점수표&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;박스 모델(Box Model)과 box-sizing 계산 공식&lt;/b&gt;, 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Inline vs Block vs Inline-Block&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;디스플레이 성질까지 완벽 가이드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  목차&lt;/h2&gt;
&lt;a id=&quot;user-content--목차&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#-%EB%AA%A9%EC%B0%A8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#1-css-%EC%A0%81%EC%9A%A9-3%EA%B0%80%EC%A7%80-%EB%B0%A9%EC%8B%9D-%EC%A0%81%EC%9A%A9-%EC%9C%84%EC%B9%98%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%B6%84%EB%A5%98&quot;&gt;CSS 적용 3가지 방식 (적용 위치에 따른 분류)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#1-1-inline-style-%EC%9D%B8%EB%9D%BC%EC%9D%B8-%EC%8A%A4%ED%83%80%EC%9D%BC&quot;&gt;1-1. Inline Style (인라인 스타일)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#1-2-internal-css-%EB%82%B4%EB%B6%80-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%8B%9C%ED%8A%B8&quot;&gt;1-2. Internal CSS (내부 스타일 시트)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#1-3-external-css-%EC%99%B8%EB%B6%80-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%8B%9C%ED%8A%B8&quot;&gt;1-3. External CSS (외부 스타일 시트)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-css-%EC%84%A0%ED%83%9D%EC%9E%90-selectors-%EC%99%84%EC%A0%84-%EC%A0%95%EB%B3%B5&quot;&gt;CSS 선택자 (Selectors) 완전 정복&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-1-%EA%B8%B0%EB%B3%B8-%EC%84%A0%ED%83%9D%EC%9E%90-4%EC%A2%85-%EC%A0%84%EC%B2%B4-%ED%83%9C%EA%B7%B8-%ED%81%B4%EB%9E%98%EC%8A%A4-id&quot;&gt;2-1. 기본 선택자 4종 (전체, 태그, 클래스, ID)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-2-%EA%B2%B0%ED%95%A9%EC%9E%90-%EA%B4%80%EA%B3%84-%EC%84%A0%ED%83%9D%EC%9E%90-4%EC%A2%85-%EC%9E%90%EC%86%90-%EC%9E%90%EC%8B%9D-%EC%9D%B8%EC%A0%91-%ED%98%95%EC%A0%9C-%EC%9D%BC%EB%B0%98-%ED%98%95%EC%A0%9C&quot;&gt;2-2. 결합자 (관계) 선택자 4종 (자손, 자식, 인접 형제, 일반 형제)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-3-%EC%86%8D%EC%84%B1-%EC%84%A0%ED%83%9D%EC%9E%90-attribute-selectors&quot;&gt;2-3. 속성 선택자 (Attribute Selectors)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-4-%EA%B0%80%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%84%A0%ED%83%9D%EC%9E%90-pseudo-class-selectors&quot;&gt;2-4. 가상 클래스 선택자 (Pseudo-class Selectors)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-5-%EC%B6%94%EC%B2%9C-%EC%84%A0%ED%83%9D%EC%9E%90-%EC%8B%A4%EC%A0%84-%EC%97%B0%EC%8A%B5-%EC%82%AC%EC%9D%B4%ED%8A%B8-css-diner&quot;&gt;2-5. [추천] 선택자 실전 연습 사이트: CSS Diner&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#3-%EC%84%A0%ED%83%9D%EC%9E%90-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84-specificity--%EC%BA%90%EC%8A%A4%EC%BC%80%EC%9D%B4%EB%94%A9-%EA%B7%9C%EC%B9%99&quot;&gt;선택자 우선순위 (Specificity / 캐스케이딩 규칙)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#3-1-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84-%EA%B3%84%EA%B8%89-%EC%B2%B4%EA%B3%84&quot;&gt;3-1. 우선순위 계급 체계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#3-2-%ED%99%A9%EA%B8%88-%EA%B7%9C%EC%B9%99-id--class--tag&quot;&gt;3-2. 황금 규칙: id &amp;gt; class &amp;gt; tag&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#4-css-%EB%B0%95%EC%8A%A4-%EB%AA%A8%EB%8D%B8-box-model---%EA%BC%AD-%EC%95%94%EA%B8%B0%ED%95%98%EC%9E%90&quot;&gt;CSS 박스 모델 (Box Model - 꼭 암기하자!)&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#4-1-%EB%B0%95%EC%8A%A4-%EB%AA%A8%EB%8D%B8%EC%9D%98-4%EB%8C%80-%EA%B5%AC%EC%84%B1-%EC%9A%94%EC%86%8C&quot;&gt;4-1. 박스 모델의 4대 구성 요소&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#4-2-%EC%8B%A4%EC%A0%9C-%ED%99%94%EB%A9%B4-%ED%81%AC%EA%B8%B0-%EA%B3%84%EC%82%B0%EA%B3%BC-content-box%EC%9D%98-%ED%95%A8%EC%A0%95&quot;&gt;4-2. 실제 화면 크기 계산과 content-box의 함정&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#4-3-%ED%95%B4%EA%B2%B0%EC%B1%85-box-sizing-border-box-%ED%95%84%EC%88%98-%EC%B4%88%EA%B8%B0%ED%99%94&quot;&gt;4-3. 해결책: box-sizing: border-box 필수 초기화&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-%EC%A3%BC%EC%9A%94-css-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0&quot;&gt;주요 CSS 스타일링 프로퍼티&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-1-background-color--marginborderpadding&quot;&gt;5-1. background-color &amp;amp; margin/border/padding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-2-font-family--font-%EB%8B%A8%EC%B6%95-%EC%86%8D%EC%84%B1shorthand&quot;&gt;5-2. font-family &amp;amp; font 단축 속성(Shorthand)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-3-%EB%A7%81%ED%81%AC-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81-text-decoration--hover&quot;&gt;5-3. 링크 스타일링 (text-decoration &amp;amp; hover)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-4-%EC%9B%B9-%ED%8F%B0%ED%8A%B8-%EC%95%84%EC%9D%B4%EC%BD%98-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-font-awesome-%ED%99%9C%EC%9A%A9&quot;&gt;5-4. 웹 폰트 아이콘 라이브러리: Font Awesome 활용&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#6-%EA%B3%B5%EA%B0%84-%EB%B0%B0%EC%B9%98%EC%99%80-%EC%84%B1%EC%A7%88-inline-vs-block-vs-inline-block&quot;&gt;공간 배치와 성질: Inline vs Block vs Inline-block&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#6-1-inline-%EC%9A%94%EC%86%8C-vs-block-level-%EC%9A%94%EC%86%8C-%EB%B9%84%EA%B5%90&quot;&gt;6-1. Inline 요소 vs Block-level 요소 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#6-2-display-%EC%86%8D%EC%84%B1%EC%9C%BC%EB%A1%9C-%EC%84%B1%EC%A7%88-%EC%A0%84%ED%99%98%ED%95%98%EA%B8%B0&quot;&gt;6-2. display 속성으로 성질 전환하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#7--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;  실전 핵심 요약 치트시트&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. CSS 적용 3가지 방식 (적용 위치에 따른 분류)&lt;/h2&gt;
&lt;a id=&quot;user-content-1-css-적용-3가지-방식-적용-위치에-따른-분류&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#1-css-%EC%A0%81%EC%9A%A9-3%EA%B0%80%EC%A7%80-%EB%B0%A9%EC%8B%9D-%EC%A0%81%EC%9A%A9-%EC%9C%84%EC%B9%98%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%B6%84%EB%A5%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
방식작성 위치문법 예시장단점 및 특징
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;1. Inline Style&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;HTML 태그 안&lt;span&gt;&amp;nbsp;&lt;/span&gt;style=&quot;&quot;&lt;/td&gt;
&lt;td&gt;&amp;lt;p style=&quot;color: red;&quot;&amp;gt;&lt;/td&gt;
&lt;td&gt;특정 태그 하나에만 즉시 적용되나 유지보수가 어렵고 우선순위가 너무 높아 실무 지양&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;2. Internal CSS&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;HTML&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;head&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;안&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;style&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;태그&lt;/td&gt;
&lt;td&gt;&amp;lt;style&amp;gt; div { text-align: center; } &amp;lt;/style&amp;gt;&lt;/td&gt;
&lt;td&gt;한 HTML 파일 안에서 일괄 관리 가능, 단 여러 페이지에 걸쳐 재사용 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;3. External CSS&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;별도 분리된&lt;span&gt;&amp;nbsp;&lt;/span&gt;.css&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일&lt;/td&gt;
&lt;td&gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;실무 표준!&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;HTML과 스타일을 완벽히 분리하고 여러 페이지에서 공통 재사용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  Internal CSS 예시 코드&lt;/h3&gt;
&lt;a id=&quot;user-content--internal-css-예시-코드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#-internal-css-%EC%98%88%EC%8B%9C-%EC%BD%94%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;head&amp;gt;
  &amp;lt;style&amp;gt;
    div { text-align: center; }
    header { font-size: x-large; font-weight: bold; }
    main { font-size: medium; }
    footer { font-size: xx-small; }
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  External CSS 예시 코드&lt;/h3&gt;
&lt;a id=&quot;user-content--external-css-예시-코드&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#-external-css-%EC%98%88%EC%8B%9C-%EC%BD%94%EB%93%9C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;head&amp;gt;
  &amp;lt;!-- 별도의 style.css 파일을 불러와 연결 --&amp;gt;
  &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. CSS 선택자 (Selectors) 완전 정복&lt;/h2&gt;
&lt;a id=&quot;user-content-2-css-선택자-selectors-완전-정복&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-css-%EC%84%A0%ED%83%9D%EC%9E%90-selectors-%EC%99%84%EC%A0%84-%EC%A0%95%EB%B3%B5&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;선택자(Selector)란?&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;어떤 HTML 요소에 CSS 스타일을 적용할지 대상을 지정하는 규칙&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 기본 선택자 4종&lt;/h3&gt;
&lt;a id=&quot;user-content-2-1-기본-선택자-4종&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-1-%EA%B8%B0%EB%B3%B8-%EC%84%A0%ED%83%9D%EC%9E%90-4%EC%A2%85&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 1. 전체 셀렉터 (*): 페이지 내의 모든 HTML 요소를 일괄 선택 */
* {
  margin: 0;
  padding: 0;
}

/* 2. 태그 셀렉터: 지정한 태그 이름을 가진 모든 요소 선택 */
div {
  color: blue;
}

/* 3. 클래스 셀렉터 (.class): 특정 클래스명을 가진 요소 그룹 선택 */
.class {
  font-size: 16px;
}

/* 4. ID 셀렉터 (#id): 페이지에 단 하나뿐인 고유 ID를 가진 요소 선택 */
#id {
  font-weight: bold;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. 결합자 (관계) 선택자 4종&lt;/h3&gt;
&lt;a id=&quot;user-content-2-2-결합자-관계-선택자-4종&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-2-%EA%B2%B0%ED%95%A9%EC%9E%90-%EA%B4%80%EA%B3%84-%EC%84%A0%ED%83%9D%EC%9E%90-4%EC%A2%85&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모, 자식, 형제 관계를 기반으로 대상을 정밀하게 조준합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌──────────────────────────────────────────────┐
│ &amp;lt;div class=&quot;parent&quot;&amp;gt;                         │
│     &amp;lt;p&amp;gt;1번 문단 (div의 직계 자식이자 자손)&amp;lt;/p&amp;gt;   │
│     &amp;lt;section&amp;gt;                                │
│         &amp;lt;p&amp;gt;2번 문단 (div의 자손)&amp;lt;/p&amp;gt;          │
│     &amp;lt;/section&amp;gt;                               │
│ &amp;lt;/div&amp;gt;                                       │
│ &amp;lt;p&amp;gt;3번 문단 (div 바로 다음 인접 형제)&amp;lt;/p&amp;gt;        │
│ &amp;lt;p&amp;gt;4번 문단 (div 뒤에 오는 일반 형제)&amp;lt;/p&amp;gt;        │
└──────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
선택자 종류문법공백/기호설명 및 선택 범위
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;자손 선택자&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;div p&lt;/td&gt;
&lt;td&gt;공백 ( )&lt;/td&gt;
&lt;td&gt;div&lt;span&gt;&amp;nbsp;&lt;/span&gt;안에 들어있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모든&lt;span&gt;&amp;nbsp;&lt;/span&gt;p&lt;span&gt;&amp;nbsp;&lt;/span&gt;요소&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(자식이든 손자든 깊이 상관없이 전부)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;자식 선택자&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;div &amp;gt; p&lt;/td&gt;
&lt;td&gt;꺾쇠 (&amp;gt;)&lt;/td&gt;
&lt;td&gt;div의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;바로 아래 직계 자식&lt;span&gt;&amp;nbsp;&lt;/span&gt;p만&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;선택 (손자/증손자는 제외)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;인접 형제 선택자&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;div + p&lt;/td&gt;
&lt;td&gt;더하기 (+)&lt;/td&gt;
&lt;td&gt;div&lt;span&gt;&amp;nbsp;&lt;/span&gt;바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;뒤에 딱 붙어서 뒤따라오는 첫 번째&lt;span&gt;&amp;nbsp;&lt;/span&gt;p&lt;span&gt;&amp;nbsp;&lt;/span&gt;하나만&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;일반 형제 선택자&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;div ~ p&lt;/td&gt;
&lt;td&gt;물결 (~)&lt;/td&gt;
&lt;td&gt;div&lt;span&gt;&amp;nbsp;&lt;/span&gt;뒤에 오는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모든 형제&lt;span&gt;&amp;nbsp;&lt;/span&gt;p&lt;span&gt;&amp;nbsp;&lt;/span&gt;요소들&lt;/b&gt;을 전부 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. 속성 선택자 (Attribute Selectors)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-3-속성-선택자-attribute-selectors&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-3-%EC%86%8D%EC%84%B1-%EC%84%A0%ED%83%9D%EC%9E%90-attribute-selectors&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태그가 가진&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;속성(Attribute)과 그 값&lt;/b&gt;을 조건으로 요소를 선택합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 1. href 속성을 가지고 있는 모든 a 태그 선택 */
a[href] {
  color: green;
}

/* 2. type 속성값이 정확히 &quot;text&quot;인 input 태그만 선택 */
input[type=&quot;text&quot;] {
  border: 1px solid #ccc;
}

/* 3. target 속성이 &quot;_blank&quot;인 링크만 선택 */
a[target=&quot;_blank&quot;] {
  font-weight: bold;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-4. 가상 클래스 선택자 (Pseudo-class Selectors)&lt;/h3&gt;
&lt;a id=&quot;user-content-2-4-가상-클래스-선택자-pseudo-class-selectors&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-4-%EA%B0%80%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%84%A0%ED%83%9D%EC%9E%90-pseudo-class-selectors&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소의 **특정한 상태(마우스 오버, 포커스 등)**나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;위치 순서&lt;/b&gt;를 기준으로 선택합니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 1. :hover ➔ 마우스 커서를 요소 위에 올렸을 때 */
a:hover {
  text-decoration: underline;
  color: red;
}

/* 2. :focus ➔ 입력창(input) 등을 클릭하여 포커스를 가졌을 때 */
input:focus {
  outline: 2px solid skyblue;
}

/* 3. :active ➔ 마우스 버튼을 꾹 누르고(클릭 중) 있는 그 순간 */
button:active {
  background-color: darkgray;
}

/* 4. :nth-child(n) ➔ 부모 기준으로 n번째 자식 요소 선택 */
li:nth-child(1) { color: red; }       /* 1번째 항목 */
li:nth-child(even) { background: #eee; } /* 짝수 번째 항목 */
li:nth-child(2n+1) { background: #fff; } /* 홀수 번째 항목 */&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-5. [추천] 선택자 실전 연습 사이트: CSS Diner&lt;/h3&gt;
&lt;a id=&quot;user-content-2-5-추천-선택자-실전-연습-사이트-css-diner&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-5-%EC%B6%94%EC%B2%9C-%EC%84%A0%ED%83%9D%EC%9E%90-%EC%8B%A4%EC%A0%84-%EC%97%B0%EC%8A%B5-%EC%82%AC%EC%9D%B4%ED%8A%B8-css-diner&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS 선택자의 원리를 직관적인 식탁 접시 게임으로 실습할 수 있는 최고의 연습 사이트:&lt;/li&gt;
&lt;li&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;링크&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://flukeout.github.io/&quot;&gt;https://flukeout.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 선택자 우선순위 (Specificity / 캐스케이딩 규칙)&lt;/h2&gt;
&lt;a id=&quot;user-content-3-선택자-우선순위-specificity--캐스케이딩-규칙&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#3-%EC%84%A0%ED%83%9D%EC%9E%90-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84-specificity--%EC%BA%90%EC%8A%A4%EC%BC%80%EC%9D%B4%EB%94%A9-%EA%B7%9C%EC%B9%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 스타일이 동일한 요소에 충돌할 때, 브라우저가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;어떤 스타일을 최종 채택할지 결정하는 계급 체계&lt;/b&gt;입니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;less&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;[최강] !important (무조건 1순위 강제 적용)
  ▲
  │   inline style (HTML 태그 안 style=&quot;&quot;)  ── [1000점]
  │   id 선택자 (#id)                       ── [100점]
  │   class / 속성 / 가상 클래스 (.c, [t], :h)── [10점]
  │   태그 선택자 (div, p)                   ── [1점]
  │   * (전체 선택자)                        ── [0점]
[최약] 상속된 부모 스타일
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  황금 요약 규칙&lt;/h3&gt;
&lt;a id=&quot;user-content--황금-요약-규칙&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#-%ED%99%A9%EA%B8%88-%EC%9A%94%EC%95%BD-%EA%B7%9C%EC%B9%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;clean&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;✅ !important &amp;gt; inline style &amp;gt; id (#) &amp;gt; class (.) &amp;gt; tag &amp;gt; *
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;점수가 같으면 **&quot;가장 나중에(아래쪽에) 작성된 코드&quot;**가 최종 승리합니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. CSS 박스 모델 (Box Model - 꼭 암기하자!)&lt;/h2&gt;
&lt;a id=&quot;user-content-4-css-박스-모델-box-model---꼭-암기하자&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#4-css-%EB%B0%95%EC%8A%A4-%EB%AA%A8%EB%8D%B8-box-model---%EA%BC%AD-%EC%95%94%EA%B8%B0%ED%95%98%EC%9E%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote style=&quot;color: #59636e;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;박스 모델이란?&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;브라우저가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모든 HTML 요소를 네모난 사각형 박스&lt;/b&gt;로 취급하고, 그 크기와 여백을 계산하는 규칙입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;scss&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────────┐
│                        MARGIN                          │  ◀── 바깥쪽 여백
│   ┌────────────────────────────────────────────────┐   │
│   │                    BORDER                      │   │  ◀── 테두리 선
│   │   ┌────────────────────────────────────────┐   │   │
│   │   │                PADDING                 │   │   │  ◀── 안쪽 여백
│   │   │   ┌────────────────────────────────┐   │   │   │
│   │   │   │                                │   │   │   │
│   │   │   │            CONTENT             │   │   │   │  ◀── 실제 콘텐츠 내용
│   │   │   │         (글자, 이미지 등)        │   │   │   │      (width x height)
│   │   │   │                                │   │   │   │
│   │   │   └────────────────────────────────┘   │   │   │
│   │   └────────────────────────────────────────┘   │   │
│   └────────────────────────────────────────────────┘   │
└────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 박스 모델의 4대 구성 요소&lt;/h3&gt;
&lt;a id=&quot;user-content-4-1-박스-모델의-4대-구성-요소&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#4-1-%EB%B0%95%EC%8A%A4-%EB%AA%A8%EB%8D%B8%EC%9D%98-4%EB%8C%80-%EA%B5%AC%EC%84%B1-%EC%9A%94%EC%86%8C&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Content (콘텐츠)&lt;/b&gt;: 텍스트나 이미지가 들어있는 실제 알맹이 영역.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Padding (패딩)&lt;/b&gt;: 콘텐츠와 테두리(Border) 사이의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;안쪽 여백&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Border (테두리)&lt;/b&gt;: 패딩 바깥을 감싸는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;시각적 테두리 경계선&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Margin (마진)&lt;/b&gt;: 테두리 바깥에 생기는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다른 요소와의 간격(바깥쪽 여백)&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. 실제 화면 크기 계산과 content-box의 함정&lt;/h3&gt;
&lt;a id=&quot;user-content-4-2-실제-화면-크기-계산과-content-box의-함정&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#4-2-%EC%8B%A4%EC%A0%9C-%ED%99%94%EB%A9%B4-%ED%81%AC%EA%B8%B0-%EA%B3%84%EC%82%B0%EA%B3%BC-content-box%EC%9D%98-%ED%95%A8%EC%A0%95&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;box&quot;&amp;gt;BOX&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.box {
  width: 100px;
  padding: 50px;
  border: 5px solid black;
  margin: 20px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본값(box-sizing: content-box) 상태에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;width: 100px이 오직&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Content 영역만의 크기&lt;/b&gt;를 의미합니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 차지하는 가로 폭=width(100)+padding 양쪽(50&amp;times;2)+border 양쪽(5&amp;times;2)=210px&lt;/p&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p style=&quot;color: #9a6700;&quot; data-ke-size=&quot;size16&quot;&gt;Warning&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 박스 크기를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;100px&lt;/b&gt;로 만들려고 했으나, 패딩과 테두리가 더해져&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실제 크기가 210px로 2배 이상 뚱뚱해지는 대참사&lt;/b&gt;가 발생합니다!&lt;/p&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-3. 해결책: box-sizing: border-box 필수 초기화&lt;/h3&gt;
&lt;a id=&quot;user-content-4-3-해결책-box-sizing-border-box-필수-초기화&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#4-3-%ED%95%B4%EA%B2%B0%EC%B1%85-box-sizing-border-box-%ED%95%84%EC%88%98-%EC%B4%88%EA%B8%B0%ED%99%94&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;box-sizing: border-box로 설정하면, 지정한&lt;span&gt;&amp;nbsp;&lt;/span&gt;width&lt;span&gt;&amp;nbsp;&lt;/span&gt;안에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Padding과 Border의 두께가 자동으로 포함&lt;/b&gt;되어 계산됩니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 가로 폭=100px 안에 Padding과 Border가 모두 들어감! (크기 유지)&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;/* 실무 필수 표준 리셋 코드: 모든 요소에 border-box 일괄 적용 */
*, *::before, *::after {
  box-sizing: border-box;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 주요 CSS 스타일링 프로퍼티&lt;/h2&gt;
&lt;a id=&quot;user-content-5-주요-css-스타일링-프로퍼티&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-%EC%A3%BC%EC%9A%94-css-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. background-color &amp;amp; margin/border/padding&lt;/h3&gt;
&lt;a id=&quot;user-content-5-1-background-color--marginborderpadding&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-1-background-color--marginborderpadding&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;header {
  font-size: x-large;
  font-weight: bold;
  background-color: red;
  margin-top: 20px;       /* 위쪽 바깥 여백 20px */
  border: 2px solid blue; /* 2px 두께 실선 파란 테두리 */
}

main {
  font-size: medium;
  background-color: green;
  padding: 50px;          /* 사방 안쪽 여백 50px */
}

footer {
  font-size: xx-small;
  background-color: yellow;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-2. font-family &amp;amp; font 단축 속성(Shorthand)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-2-font-family--font-단축-속성shorthand&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-2-font-family--font-%EB%8B%A8%EC%B6%95-%EC%86%8D%EC%84%B1shorthand&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1)&lt;span&gt;&amp;nbsp;&lt;/span&gt;font-family: 글꼴과 대체 폰트(Fallback)&lt;/h4&gt;
&lt;a id=&quot;user-content-1-font-family-글꼴과-대체-폰트fallback&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#1-font-family-%EA%B8%80%EA%BC%B4%EA%B3%BC-%EB%8C%80%EC%B2%B4-%ED%8F%B0%ED%8A%B8fallback&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;header {
  /* 1순위: Times New Roman, 없으면 2순위 Times, 둘 다 없으면 기본 명조(serif) */
  font-family: 'Times New Roman', Times, serif;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;font&lt;span&gt;&amp;nbsp;&lt;/span&gt;단축 속성 (순서 주의!)&lt;/h4&gt;
&lt;a id=&quot;user-content-2-font-단축-속성-순서-주의&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#2-font-%EB%8B%A8%EC%B6%95-%EC%86%8D%EC%84%B1-%EC%88%9C%EC%84%9C-%EC%A3%BC%EC%9D%98&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;작성 순서&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;font-weight&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;font-size&lt;span&gt;&amp;nbsp;&lt;/span&gt;➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;font-family&lt;/li&gt;
&lt;li&gt;&lt;b&gt;필수 포함 규칙&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;font-size와&lt;span&gt;&amp;nbsp;&lt;/span&gt;font-family는 반드시 생략 없이 포함&lt;/b&gt;되어야 단축 문법이 유효합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;header {
  /* font-weight(bold) + font-size(x-large) + font-family */
  font: bold x-large 'Times New Roman', Times, serif;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-3. 링크 스타일링 (text-decoration &amp;amp; hover)&lt;/h3&gt;
&lt;a id=&quot;user-content-5-3-링크-스타일링-text-decoration--hover&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-3-%EB%A7%81%ED%81%AC-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81-text-decoration--hover&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 밑줄을 지우고, 마우스를 올렸을 때만 밑줄이 나타나게 하는 깔끔한 링크 스타일:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;.github-link {
  font-size: small;
  color: gray;
  text-decoration: none; /* 파란 기본 밑줄 제거 */
}

.github-link:hover {
  text-decoration: underline; /* 마우스 올렸을 때만 밑줄 표시 */
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-4. 웹 폰트 아이콘 라이브러리: Font Awesome 활용&lt;/h3&gt;
&lt;a id=&quot;user-content-5-4-웹-폰트-아이콘-라이브러리-font-awesome-활용&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#5-4-%EC%9B%B9-%ED%8F%B0%ED%8A%B8-%EC%95%84%EC%9D%B4%EC%BD%98-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-font-awesome-%ED%99%9C%EC%9A%A9&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹에서 사용하는 다양한 브랜드/시스템 아이콘을 글자(Font)처럼 제공하는 대표 라이브러리:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;lt;head&amp;gt;에 CDN 링크 연결:&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;link
  rel=&quot;stylesheet&quot;
  href=&quot;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css&quot;
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;태그로 아이콘 출력 (예: GitHub 고양이 로고):&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;a class=&quot;github-link&quot; href=&quot;https://github.com/qu3vipon&quot;&amp;gt;
  &amp;lt;i class=&quot;fa-brands fa-github&quot;&amp;gt;&amp;lt;/i&amp;gt; GitHub
&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 공간 배치와 성질: Inline vs Block vs Inline-block&lt;/h2&gt;
&lt;a id=&quot;user-content-6-공간-배치와-성질-inline-vs-block-vs-inline-block&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#6-%EA%B3%B5%EA%B0%84-%EB%B0%B0%EC%B9%98%EC%99%80-%EC%84%B1%EC%A7%88-inline-vs-block-vs-inline-block&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면에서 공간을 차지하고 줄바꿈되는 방식에 따라 요소는 크게 나뉩니다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-1. Inline 요소 vs Block-level 요소 비교&lt;/h3&gt;
&lt;a id=&quot;user-content-6-1-inline-요소-vs-block-level-요소-비교&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#6-1-inline-%EC%9A%94%EC%86%8C-vs-block-level-%EC%9A%94%EC%86%8C-%EB%B9%84%EA%B5%90&quot;&gt;&lt;/a&gt;&lt;/div&gt;
구분Block-level (블록 요소)Inline (인라인 요소)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;줄바꿈&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;항상 새로운 줄에서 시작&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;줄바꿈 없이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;같은 줄에 나란히 배치&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;너비(Width)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;기본값으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부모 가로 폭 100% 전부 차지&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;텍스트/콘텐츠의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내용물 크기만큼만 차지&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;크기 지정&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;width,&lt;span&gt;&amp;nbsp;&lt;/span&gt;height&lt;span&gt;&amp;nbsp;&lt;/span&gt;지정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;width,&lt;span&gt;&amp;nbsp;&lt;/span&gt;height&lt;span&gt;&amp;nbsp;&lt;/span&gt;지정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;불가 (무시됨)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&lt;b&gt;상하 여백&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;margin-top/bottom&lt;span&gt;&amp;nbsp;&lt;/span&gt;완벽 적용&lt;/td&gt;
&lt;td&gt;margin-top/bottom&lt;span&gt;&amp;nbsp;&lt;/span&gt;제대로 적용 안 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&lt;b&gt;대표 태그&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;div&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;p&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;h1&amp;gt;~&amp;lt;h6&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;section&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;article&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;header&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;footer&amp;gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;span&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;a&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;strong&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;em&amp;gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;img&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;display&lt;span&gt;&amp;nbsp;&lt;/span&gt;속성으로 성질 전환하기&lt;/h3&gt;
&lt;a id=&quot;user-content-6-2-display-속성으로-성질-전환하기&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#6-2-display-%EC%86%8D%EC%84%B1%EC%9C%BC%EB%A1%9C-%EC%84%B1%EC%A7%88-%EC%A0%84%ED%99%98%ED%95%98%EA%B8%B0&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS의&lt;span&gt;&amp;nbsp;&lt;/span&gt;display&lt;span&gt;&amp;nbsp;&lt;/span&gt;속성을 사용하면 요소의 본래 태생적 성질을 마음대로 변경할 수 있습니다:&lt;/p&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;&amp;lt;!-- 1. 기본 블록 요소: 한 줄 전체를 차지함 --&amp;gt;
&amp;lt;div style=&quot;background-color: skyblue;&quot;&amp;gt;Block 1&amp;lt;/div&amp;gt;

&amp;lt;!-- 2. display: inline ➔ 글자 취급되므로 width: 100px이 무시됨! --&amp;gt;
&amp;lt;div style=&quot;display: inline; width: 100px; background-color: orange;&quot;&amp;gt;Inline 1&amp;lt;/div&amp;gt;

&amp;lt;!-- 3. display: inline-block ➔ 옆으로 나란히 붙으면서도 width: 100px 크기가 온전히 적용됨! --&amp;gt;
&amp;lt;div style=&quot;display: inline-block; width: 100px; background-color: orange;&quot;&amp;gt;Inline 2&amp;lt;/div&amp;gt;

&amp;lt;!-- 4. 다시 블록 요소: 새 줄에서 시작 --&amp;gt;
&amp;lt;div style=&quot;background-color: skyblue;&quot;&amp;gt;Block 2&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7.   실전 핵심 요약 치트시트&lt;/h2&gt;
&lt;a id=&quot;user-content-7--실전-핵심-요약-치트시트&quot; style=&quot;background-color: #000000; color: #0969da;&quot; href=&quot;https://github.com/ey607928-ai/Assignment/blob/main/HTML_CSS/day2/CSS.md#7--%EC%8B%A4%EC%A0%84-%ED%95%B5%EC%8B%AC-%EC%9A%94%EC%95%BD-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;pre class=&quot;maxima&quot; style=&quot;background-color: #f6f8fa; color: #1f2328;&quot;&gt;&lt;code&gt;1. 선택자 우선순위 점수
   !important &amp;gt; inline style(1000점) &amp;gt; #id(100점) &amp;gt; .class/[attr]/:hover(10점) &amp;gt; tag(1점) &amp;gt; *(0점)

2. 결합자(관계) 기호 구분
   - div p   : 모든 자손
   - div &amp;gt; p : 바로 아래 자식
   - div + p : 바로 뒤에 붙은 인접 형제 1개
   - div ~ p : 뒤따라오는 모든 형제

3. 박스 크기 계산 표준 공식
   *, *::before, *::after { box-sizing: border-box; }
   (지정한 width 안에 padding과 border를 자동 포함시켜 레이아웃 깨짐 방지)

4. font 단축 속성 필수 순서
   font: [font-weight] [font-size] [font-family];
   (font-size와 font-family는 필수!)

5. display 3대장 핵심
   - block        : 한 줄 독점 (width/height 가능)
   - inline       : 나란히 배치 (width/height 불가)
   - inline-block : 나란히 배치 + width/height 크기 지정 가능&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <author>write31991</author>
      <guid isPermaLink="true">https://write31991.tistory.com/28</guid>
      <comments>https://write31991.tistory.com/28#entry28comment</comments>
      <pubDate>Wed, 14 Oct 2026 16:02:28 +0900</pubDate>
    </item>
  </channel>
</rss>