뭐부터 해야할지 일단 머리부터 박아봤다
일단 docker 빌드해서 초기 환경 설정하고 이것저것 프레임워크 까는 거 부터 시작하자
…
짧은 팀 회의 후 기술 스택 선정 했으니 이것 위주로 공부 해야한다
CSS - Tailwind
프론트엔드 - React
백엔드 - FastAPI
DB - MongoDB
인프라 - AWS
상태 확인
docker compose ps로그 보기
docker compose logs -f --tail=100 frontend
docker compose logs -f backend
일시정지
docker compose stop다시시작
docker compose up -d완전 종료
docker compose down데이터까지 클리어
docker compose down -v개별 서비스 제어
docker compose stop frontend
docker compose up -d frontend
docker compose restart backend
docker compose rm -f frontend # 컨테이너 제거(정지 필요)
이미지 다시 빌드
docker compose up -d --build # 전체 재빌드
docker compose up -d --build frontend # 프론트만 재빌드
도커로 일단 초기 설정부터 해볼 계획이다
Docker = 실행 환경 보장
React + Tailwind = 브라우저에서 쓸 UI
FastAPI = 요청 받아 DB로부터 JSON 돌려주는 서버
MongoDB = 문서 저장 DB
[브라우저] http://localhost:5173
└─(fetch) GET /posts ─────────────────────────────────┐
[React(Vite dev서버)] │
▼
http://localhost:8000 (포트 매핑)
[FastAPI(Uvicorn)]
│ └─ CORS 허용
▼
mongodb://mongo:27017 (컨테이너 네트워크)
[MongoDB (posts 컬렉션)]
│
결과 문서들
▼
[FastAPI] → JSON 변환(id 문자열화)
▼
[브라우저(React)] 상태 업데이트 → HTML 렌더
docker 활용해서 로컬에 빌드해보았다
[브라우저] (호스트 OS)
│
├─ http://localhost:5173 → [frontend 컨테이너: Vite dev 서버]
│ └ React 앱(HTML/JS/CSS) 서빙, HMR
│
├─ http://localhost:8000 → [backend 컨테이너: Uvicorn + FastAPI]
│ └ Motor(비동기 드라이버)로 Mongo 접속
│
└─ http://localhost:8081 → [mongo-express 컨테이너: DB UI]
(관리자 화면)
[MongoDB 컨테이너: mongo] ← backend가 내부 네트워크로 `mongodb://mongo:27017` 접속
도커로 각 서비스 리눅스 컨테이너로 띄우고, 포트/볼륨/환경 변수까지 표준화 한다
컨테이너는 같은 네트워크라 서비스명으로 통신하고 브라우저는 호스트 포트로 접근한다
페이지 로드 & 목록 조회 (GET /posts)
글 작성 (POST /posts)
역할: 개발용 정적 서버 + HMR1
동작:
역할: UI 로직
const API = import.meta.env.VITE_API_BASE ?? "http://localhost:8000";
useEffect(() => { load(); }, []);
async function load() {
const res = await fetch(`${API}/posts`); // ← 여기서 GET /posts
setPosts(await res.json());
}
상호작용:
역할:
Uvicorn: 소켓 수신 -> ASGI 프로토콜로 FastAPI에 전달
FastAPI: 라우팅(@app.get("/posts"))6 후 엔드포인트 함수 실행
@app.get("/posts")
async def list_posts(skip: int = 0, limit: int = 20):
cursor = posts.find().skip(skip).limit(limit).sort("_id", -1)
return [to_out(d) async for d in cursor]
역할: DB와 대화하는 라이브러리
상호작용:
posts.find()가 비동기 커서7 반환 → async for 로 문서들을 끌어옴
이동안 FastAPI는 await 덕분에 다른 요청도 처리 가능(동시성↑)
직렬화:
Mongo 문서는 _id가 Objectid -> 그대로 JSON에 못 담음
헬퍼 to_out()이 _id를 str()로 바꿔 id 필드에 넣음
응답:
Content-Type: application/jsonReact:
await fetch(`${API}/posts`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title, body })
});
CORS 사전요청:
Content-Type: application/json은 브라우저가 먼저 OPTIONS 요청을 보냄
FastAPI의 CORSMiddleware가 Access-Control-* 헤더를 응답 → 본 요청 허용
class PostIn(BaseModel):
title: str = Field(min_length=1, max_length=100)
body: str
@app.post("/posts", response_model=PostOut, status_code=201)
async def create_post(p: PostIn): # ← JSON이 자동으로 PostIn으로 파싱/검증
res = await posts.insert_one(p.dict())
doc = await posts.find_one({"_id": res.inserted_id})
return to_out(doc)
Pydantic 역할:
JSON → PostIn으로 파싱 & 유효성 검사
규칙 위반 시 FastAPI가 422 응답과 에러 JSON 자동 반환(함수 본문 실행 안 됨)
성공 시:
Motor로 insert_one → Mongo가 _id 생성
다시 find_one으로 방금 문서 조회 → _id 문자열화 → 201 Created + JSON
load() 재호출 → 목록 갱신 → 새로운 글 화면 반영Vite dev 서버: 개발 중 정적 파일/모듈 서빙 + HMR
React: UI 컴포넌트 + 상태관리
fetch로 API 호출CORS 미들웨어: 다른 출처 호출 허용
Uvicorn(ASGI 서버): HTTP 소켓 수신, FastAPI 호출
FastAPI(라우팅): URL/메서드 매칭, 의존성/미들웨어, 응답 포맷
Pydantic(모델/검증): 요청/응답 스키마와 자동 유효성 검사
Motor(비동기 드라이버): Mongo 프로토콜로 비동기 I/O 수행
MongoDB: 문서 저장/조회/수정/삭제
_id:ObjectIDto_out 직렬화: _id -> 문자열 id로 변환해 JSON 호환
유의점은 비동기라서 await / async for로 논블로킹(기다리는 동안 다른 요청 처리) 하게 읽어온다
setState()가 호출되면 새 가상 DOM을 만들고 이전 것과 비교해서 바뀐 부분만 실제 DOM에 반영한다
Hot Module Replacement, 코드 수정시 전부 고치는게 아닌 변경된 곳만 교체해서 실행 애플리케이션에 반영 ↩
ECMAScript Module, 자바스크립트에서 공식적으로 표준화된 모듈 시스템 ↩
Just-in-Time compile, 실행하기 전에 컴파일 하는게 아닌 프로그램 실행하며 필요한 부분 즉석으로 컴파일 하는 방식 ↩
미들웨어, 요청들어오고 라우트 핸들러 실행, 응답 나감 사이에 끼어있는 중간 처리자다 ↩
CORS에 사용되는 HTTP 응답 헤더 중 하나로 어떤 도메인에서 요청을 허용할 것인지 명시한다 ↩
“어떤 URL + HTTP 메서드 → 어떤 함수가 처리할지”를 매핑하는 것. 여기서는 이후 매핑된 실행 함수인 엔드포인터 함수(=핸들러) 까지 실행한다 ↩
DB에서 문서 한 번에 다 못받을때 사용하는 네트워크 I/O 이터레이터(배열 참조시 사용하는 개체)
↩
React가 메모리 안에서 갖고 있는 경량 복사본 트리다
↩
브라우저가 실제로 들고 있는 트리로 여기 직접 조작하면 렌더 비용이 크다 ↩