이번 주 학습 요약
이번 주에는 지금까지 배운 Python과 Git 기초를 바탕으로, 백엔드 API와 데이터베이스를 연결하고 이를 실제 웹 화면으로 보여주는 과정을 경험했다.
주 초반에는 FastAPI와 Supabase를 이용해 데이터를 생성하고 조회·수정·삭제하는 CRUD 구조를 구현했다. 이후 팀원별로 기능을 나누고 GitHub 브랜치에서 작업한 뒤, 각자의 코드를 하나의 프로젝트로 합치는 협업도 진행했다. 완성한 백엔드는 Render에 배포하면서 로컬 컴퓨터에서만 실행되던 프로그램을 외부에서도 접근할 수 있는 서비스로 옮겨봤다.
주 후반에는 Streamlit을 이용해 웹 화면을 만드는 방법을 배웠다. 단순히 글자와 입력창을 배치하는 것에서 시작해 columns, tabs, sidebar로 화면 구조를 나누고, 마지막에는 st.session_state를 활용해 로그인 → 설문 작성 → 결과 출력으로 이어지는 애플리케이션을 직접 완성했다.
이번 주의 가장 큰 흐름은 다음과 같았다.
사용자 화면
→ Streamlit
→ FastAPI
→ Supabase 또는 LLM
→ 처리 결과 반환
각 기술을 따로 연습하는 것을 넘어, 하나의 서비스 안에서 프론트엔드와 백엔드, 데이터베이스가 어떻게 연결되는지 조금씩 이해하기 시작한 한 주였다.
주요 학습 내용
FastAPI로 백엔드 API 만들기
FastAPI는 화면에서 전달된 요청을 받아 필요한 작업을 처리한 뒤 결과를 돌려주는 백엔드 프레임워크다.
예를 들어 사용자가 회원 정보를 입력하면 화면이 해당 데이터를 FastAPI로 전달하고, FastAPI는 데이터베이스에 정보를 저장한 뒤 성공 여부를 응답한다.
이번 주에는 HTTP 요청 방식과 CRUD 기능을 연결해서 생각하는 연습을 했다.
- POST: 새로운 데이터 생성
- GET: 저장된 데이터 조회
- PUT 또는 PATCH: 기존 데이터 수정
- DELETE: 데이터 삭제
처음에는 각각의 요청 방식을 외우는 느낌이 강했지만, 회원 가입이나 게시판 같은 실제 서비스에 대입해 보니 역할이 조금 더 명확해졌다.
회원 가입 → 데이터 생성
상품 조회 → 데이터 조회
회원 정보 수정 → 데이터 수정
게시글 삭제 → 데이터 삭제
단순히 API 주소를 만드는 것이 아니라, 어떤 요청을 받았을 때 어떤 데이터를 처리하고 무엇을 응답해야 하는지 설계하는 것이 중요하다는 점을 배웠다.
Supabase와 CRUD 연동
Supabase는 데이터를 저장하고 관리할 수 있는 클라우드 데이터베이스 서비스다.
FastAPI에서 Supabase로 요청을 보내면서, 파이썬 코드에서 입력한 데이터가 실제 데이터베이스에 저장되고 다시 조회되는 흐름을 실습했다.
이 과정에서 프론트엔드와 백엔드, 데이터베이스의 역할을 구분할 수 있었다.
프론트엔드
→ 사용자가 값을 입력하고 결과를 확인하는 화면
백엔드
→ 요청을 검사하고 필요한 작업을 처리하는 부분
데이터베이스
→ 데이터를 실제로 저장하는 공간
처음에는 CRUD 코드가 비슷해 보여서 어떤 부분을 바꿔야 하는지 헷갈렸지만, 작업의 목적에 따라 사용되는 메서드와 데이터가 달라진다는 것을 확인했다.
또한 팀원마다 서로 다른 CRUD 기능을 맡아 구현하면서, 각 기능이 최종적으로 같은 데이터베이스와 연결될 때 구조를 통일해야 한다는 점도 알게 됐다.
Render를 이용한 백엔드 배포
로컬 환경에서 실행한 FastAPI 서버는 내 컴퓨터가 켜져 있을 때만 사용할 수 있다. Render에 배포하면 인터넷을 통해 접근할 수 있는 주소를 만들 수 있다.
이번 주에는 GitHub 저장소와 Render를 연결하고, 배포에 필요한 설정과 환경변수를 확인했다.
배포 과정에서는 로컬에서 정상적으로 실행되던 코드가 배포 환경에서는 다르게 동작할 수 있다는 점을 경험했다. 특히 패키지 버전과 실행 명령어, 환경변수가 빠지면 서버가 정상적으로 시작되지 않을 수 있었다.
이 과정을 통해 requirements.txt가 단순한 패키지 목록이 아니라, 다른 환경에서도 같은 프로그램을 실행하기 위한 중요한 파일이라는 점을 다시 확인했다.
python -m pip install -r requirements.txt
배포는 버튼 한 번으로 끝나는 작업처럼 보였지만, 실제로는 코드뿐 아니라 실행 환경까지 함께 준비해야 한다는 것을 알게 됐다.
GitHub 브랜치를 이용한 팀 협업
이번 주 팀 실습에서는 리더가 기본 프로젝트 구조를 GitHub에 올리고, 팀원들은 저장소를 내려받아 각자의 브랜치에서 작업했다.
전체 흐름은 다음과 같았다.
공통 저장소 내려받기
→ 개인 브랜치 생성
→ 담당 기능 구현
→ commit과 push
→ 팀원 코드 확인
→ main 브랜치에 통합
혼자 작업할 때는 내 코드만 정상적으로 실행되면 됐지만, 팀 프로젝트에서는 파일 이름과 폴더 위치, 변수명, API 주소를 서로 맞추는 것이 중요했다.
각자 구현한 기능이 정상적으로 동작하더라도 프로젝트 구조가 다르면 코드를 합칠 때 충돌이나 오류가 생길 수 있다. 따라서 작업을 시작하기 전에 공통 구조와 규칙을 정하는 것이 필요했다.
Git 명령어 자체보다도, 다른 사람의 작업을 덮어쓰지 않고 각자의 기능을 안전하게 합치는 과정이 더 어렵게 느껴졌다.
LLM API와 CRUD 기능의 역할 구분
팀 프로젝트에서는 팀원들이 각각 CRUD 기능을 맡고, 한 명은 LLM API를 연결하는 구조로 실습했다.
CRUD는 정해진 데이터를 저장하고 조회하는 기능에 가깝고, LLM은 사용자의 자연어 입력을 받아 새로운 답변을 생성한다는 차이가 있었다.
예를 들면 다음과 같다.
CRUD
→ 저장된 게시글이나 회원 정보를 관리
LLM API
→ 사용자의 질문을 이해하고 답변 생성
두 기능은 역할이 다르지만 하나의 서비스 안에서 함께 사용할 수 있다. 사용자의 질문과 답변 기록은 데이터베이스에 저장하고, 실제 답변은 LLM이 생성하는 식으로 연결할 수 있다.
아직 완전한 AI 서비스를 구현한 것은 아니지만, 앞으로 만들 멀티 AI 에이전트 서비스가 어떤 구성으로 동작할지 기본 구조를 떠올릴 수 있었다.
Streamlit으로 웹 화면 구성하기
주 후반에는 Streamlit을 이용해 파이썬 코드만으로 웹 화면을 만들었다.
기본 입력 컴포넌트부터 시작해 여러 방식으로 화면을 나누는 방법을 실습했다.
st.text_input()
st.number_input()
st.selectbox()
st.radio()
st.checkbox()
st.button()
또한 st.columns를 사용해 화면을 가로로 나누고, st.tabs로 여러 내용을 탭에 배치했으며, st.sidebar를 이용해 메뉴나 설정 영역을 본문과 분리했다.
col1, col2 = st.columns(2)
tab1, tab2 = st.tabs(["첫 번째 탭", "두 번째 탭"])
st.sidebar.title("메뉴")
이전에는 웹 화면을 만들려면 HTML과 CSS를 먼저 작성해야 한다고 생각했지만, Streamlit을 사용하면 Python을 중심으로 간단한 입력 화면과 대시보드를 빠르게 만들 수 있었다.
다만 화면을 만드는 것과 사용자의 상태를 유지하는 것은 별개의 문제였다.
Streamlit의 재실행 방식과 Session State
Streamlit은 사용자가 버튼을 누르거나 값을 변경할 때 파이썬 파일을 위에서부터 다시 실행한다.
처음에는 다음과 같이 일반 변수로 로그인 상태를 관리했다.
login = False
하지만 코드가 다시 실행될 때마다 False가 다시 저장되므로 로그인 상태가 유지되지 않았다.
이 문제를 해결하기 위해 st.session_state를 사용했다.
if "login" not in st.session_state:
st.session_state.login = False
session_state는 현재 사용자의 실행 상태에서 유지해야 할 값을 저장하는 공간이다.
이번 실습에서는 다음 두 값을 중심으로 화면을 나눴다.
if "login" not in st.session_state:
st.session_state.login = False
if "survey_complete" not in st.session_state:
st.session_state.survey_complete = False
화면 구조는 다음과 같았다.
if st.session_state.login == False:
# 로그인 화면
elif st.session_state.survey_complete == False:
# 설문지 화면
else:
# 결과 화면
상태값 두 개만으로 로그인, 설문지, 결과 화면을 순서대로 보여줄 수 있다는 점이 인상 깊었다.
Query Params와 브라우저 저장소
st.session_state 외에도 값을 유지하거나 전달하는 여러 방법을 배웠다.
st.query_params
st.query_params는 URL에 값을 저장한다.
st.query_params["loginout"] = "login"
URL에 값이 표시되므로 새로고침한 뒤에도 확인할 수 있고, 주소를 다른 사람에게 공유할 수도 있다.
다만 URL은 누구나 볼 수 있으므로 비밀번호나 API 키 같은 중요한 정보를 저장하면 안 된다.
Session Storage
Session Storage는 현재 브라우저 탭이 유지되는 동안 값을 저장한다.
새로고침 → 유지
탭 종료 → 삭제
Local Storage
Local Storage는 브라우저를 종료한 뒤에도 값이 남아 있다.
새로고침 → 유지
브라우저 종료 후 재실행 → 유지
Cache
캐시는 로그인 상태 같은 사용자 정보를 저장하기보다는, 오래 걸리는 계산이나 데이터 조회 결과를 다시 사용하기 위한 기능이다.
@st.cache_data
def load_data():
return data
이번 주에는 여러 기능을 다음과 같이 구분해 볼 수 있었다.
기능주요 목적
| st.session_state | 현재 사용자의 화면 상태 유지 |
| st.query_params | URL을 통한 상태 전달 및 공유 |
| Session Storage | 현재 브라우저 탭에서 값 유지 |
| Local Storage | 브라우저에 값을 오래 유지 |
| Cache | 반복 계산과 데이터 요청 줄이기 |
실습 및 문제 해결
로그인 상태가 바뀌지 않았던 문제
로그인 성공 후 설문 화면으로 이동하도록 다음 코드를 작성했다.
st.session_state.login == True
하지만 로그인 버튼을 눌러도 계속 로그인 화면이 나타났다.
원인은 ==를 사용한 것이었다. ==는 두 값을 비교할 뿐, 값을 변경하지 않는다.
st.session_state.login = True
대입 연산자 =로 수정한 뒤 로그인 상태가 정상적으로 변경됐다.
이번 오류를 통해 아주 짧은 코드라도 연산자의 역할을 정확히 확인해야 한다는 점을 다시 배웠다.
화면 전환 직후 갱신되지 않는 문제
상태값을 변경한 뒤에는 새로운 상태를 기준으로 화면을 다시 그려야 했다.
st.session_state.login = True
st.rerun()
st.rerun()은 현재 실행을 멈추고 코드를 위에서부터 다시 실행한다.
로그인 성공 시에는 다음 순서로 처리됐다.
아이디와 비밀번호 확인
→ login을 True로 변경
→ 코드 재실행
→ 설문지 화면 출력
처음에는 Streamlit이 자동으로 재실행되는데 왜 st.rerun()이 필요한지 헷갈렸다. 실습을 통해 상태를 변경한 직후 바로 새로운 화면으로 전환하고 싶을 때 사용할 수 있다는 점을 알게 됐다.
설문 결과가 사라지는 문제 예방
설문 입력값을 일반 변수로만 사용하면 결과 화면으로 이동할 때 코드가 다시 실행되면서 이전 값에 접근하기 어려울 수 있다.
따라서 제출할 때 결과를 session_state에 저장했다.
st.session_state.survey_name = survey_name
st.session_state.survey_age = survey_age
st.session_state.survey_interest = survey_interest
st.session_state.survey_complete = True
결과 화면에서는 저장된 값을 다시 읽었다.
st.write(st.session_state.survey_name)
이 과정을 통해 화면에서 입력받은 값을 다음 화면에서도 사용하려면 상태 저장이 필요하다는 것을 이해했다.
입력값 검증 추가
처음 만든 설문은 이름을 입력하지 않거나 제출 동의를 하지 않아도 결과 화면으로 이동했다.
이를 막기 위해 제출 전에 조건을 검사했다.
if survey_name.strip() == "":
st.warning("이름을 입력해 주세요.")
elif survey_agree == False:
st.warning("설문 내용 제출에 동의해 주세요.")
입력 컴포넌트를 화면에 배치하는 것만으로 기능이 완성되는 것이 아니라, 사용자가 잘못된 값을 입력했을 때 어떻게 처리할지도 함께 만들어야 한다는 점을 배웠다.
팀 코드 통합의 어려움
팀 실습에서는 각자 작성한 코드를 GitHub에 올린 뒤 하나의 프로젝트로 합쳐야 했다.
개별 기능을 구현할 때는 잘 동작했지만, 통합 과정에서는 다음과 같은 부분을 맞춰야 했다.
- 공통 폴더 구조
- 파일명과 import 경로
- 환경변수 이름
- 데이터베이스 테이블 구조
- API 요청과 응답 형식
- 패키지 버전
이번 경험을 통해 팀 프로젝트에서는 코드를 잘 작성하는 것뿐 아니라, 다른 사람이 쉽게 이해하고 연결할 수 있게 작성하는 것도 중요하다는 점을 느꼈다.
KPT 회고
Keep
이번 주에는 수업에서 배운 내용을 그대로 끝내지 않고, 작은 기능부터 직접 실행하며 확인했다.
특히 Streamlit 과제를 만들 때 로그인 화면과 설문지, 결과 화면을 한꺼번에 작성하지 않고 다음과 같이 단계별로 확장한 방식이 도움이 됐다.
화면 분기 만들기
→ 로그인 입력창 추가
→ 로그인 상태 변경
→ 설문 입력창 추가
→ 제출 결과 저장
→ 결과 화면 출력
→ 입력 검증과 로그아웃 추가
오류가 생겼을 때도 전체 코드를 다시 작성하기보다, 현재 상태값과 조건문을 확인하며 원인을 좁혀갔다. =와 ==의 차이처럼 기본적인 부분도 그냥 넘기지 않고 다시 확인한 점은 앞으로도 유지하고 싶다.
또한 팀 프로젝트에서 개인 브랜치를 사용하고, 담당 기능을 구현한 뒤 공유하는 과정을 직접 경험한 것도 좋았다. 아직 익숙하지는 않지만 협업 흐름을 반복해서 경험하고 있다는 점은 긍정적이었다.
Problem
FastAPI, Supabase, Render, GitHub, Streamlit을 짧은 기간 안에 연속해서 다루다 보니 각 기술의 사용법은 따라갈 수 있어도 전체 연결 구조를 완전히 이해하지 못한 부분이 있다.
특히 API 요청이 들어와 데이터베이스에 저장되고 다시 화면으로 돌아오는 과정을 코드 한 줄씩 설명하려면 아직 막히는 부분이 있다.
GitHub 협업에서도 브랜치와 병합의 기본 흐름은 알지만, 충돌이 발생했을 때 어떤 파일을 기준으로 수정해야 하는지는 더 연습이 필요하다.
Streamlit에서는 session_state, Query Params, Session Storage, Local Storage가 모두 값을 유지하는 기능처럼 느껴져서, 실제 서비스에서 어떤 방법을 선택해야 하는지 바로 판단하기 어렵다.
또한 실습 코드를 작성할 때 화면 코드와 상태 처리 코드가 한 파일에 길게 이어져 있어, 코드가 더 복잡해지면 수정하기 어려워질 수 있다고 느꼈다.
Try
다음 주에는 이번 주에 사용한 기술을 각각 따로 외우기보다, 하나의 작은 서비스 흐름으로 다시 연결해 볼 계획이다.
먼저 FastAPI에서 간단한 데이터를 생성하고 조회하는 API를 혼자 다시 작성한다. 그다음 Streamlit 입력값을 FastAPI로 전달하고 응답을 화면에 출력하는 기능까지 연결해 본다.
Streamlit 과제는 다음과 같이 함수로 분리해 다시 작성해 볼 예정이다.
def init_state():
pass
def show_login():
pass
def show_survey():
pass
def show_result():
pass
GitHub에서는 개인 연습 저장소에서 브랜치를 새로 만들고, 수정한 파일을 병합하는 과정을 다시 반복한다. 가능하면 같은 줄을 서로 다르게 수정해 의도적으로 충돌을 만든 뒤 해결 과정도 연습하고 싶다.
또한 상태 관리 기능을 다음 기준으로 다시 정리할 예정이다.
현재 화면에서만 필요한 값
→ session_state
주소로 전달하거나 공유할 값
→ query_params
현재 탭에서 유지할 값
→ Session Storage
브라우저 종료 후에도 유지할 값
→ Local Storage
반복 실행을 줄일 계산 결과
→ Cache
다음 주 학습 계획
다음 주에는 이번 주에 배운 기능을 복습하면서 프론트엔드와 백엔드의 연결 흐름을 더 정확하게 이해하는 것이 목표다.
첫째, FastAPI의 요청과 응답 과정을 직접 설명할 수 있도록 간단한 CRUD API를 다시 작성한다.
둘째, Streamlit에서 입력한 값을 FastAPI로 보내고 응답을 화면에 보여주는 작은 예제를 만든다.
셋째, session_state를 사용하는 로그인 또는 설문 앱을 함수 단위로 다시 정리한다.
넷째, GitHub 브랜치 생성부터 병합까지의 명령어와 작업 순서를 README에 기록한다.
이번 주에는 여러 기술을 빠르게 경험했다면, 다음 주에는 각 기술이 어떻게 연결되는지 확인하며 기본 구조를 내 것으로 만드는 데 집중하고 싶다.
#FastAPI #Supabase #Streamlit #SessionState #Render배포 #GitHub협업 #CRUD #Python웹개발 #AI오케스트레이션캠프 #엔코아AI캠퍼스
'AI 오케스트레이션 캠프 > 주간 회고' 카테고리의 다른 글
| [SK네트웍스 Family 엔코아AI캠퍼스] AI 오케스트레이션 캠프 1기_8월 1주차 회고 (0) | 2026.08.07 |
|---|---|
| [SK네트웍스 Family 엔코아AI캠퍼스] AI 오케스트레이션 캠프 1기_7월 5주차 회고 (0) | 2026.07.31 |
| [SK네트웍스 Family 엔코아AI캠퍼스] AI 오케스트레이션 캠프 1기_7월 3주차 회고 (0) | 2026.07.17 |
| [SK네트웍스 Family 엔코아AI캠퍼스] AI 오케스트레이션 캠프 1기_7월 2주차 회고 (0) | 2026.07.12 |
댓글