스마트시티 산업 동향과 딥페이크 탐지 기술이 비대면 서비스 보안 등에 왜 필요한지 이론을 학습합니다. 이어서, 팀별 워크숍을 통해 실제 '딥페이크 탐지 웹 앱'의 목표(SMART), 아키텍처(플로우 차트), UI/UX, API를 직접 설계
Table of Content
2일차: 스마트시티 산업 동향 및 딥페이크 탐지 프로젝트 설계
부제: 딥페이크 탐지 기술의 스마트시티 적용 방안 모색 및 웹 서비스 기획
2일차 학습 목표 및 일정
1.
이론 (2H): 스마트시티 산업 동향 및 딥페이크 탐지 기술 적용 방안
2.
실습 (6H): 딥페이크 탐지 웹 애플리케이션 프로젝트 설계
•
목표 설정 (SMART) 및 기능 정의
•
시스템 아키텍처 및 UI/UX
•
데이터베이스 (ERD) 및 API 설계
3.
발표 및 피드백: 팀별 설계 내용 발표
모듈 1: 스마트시티 산업과 AI
1. 스마트시티 산업 동향
어제(1일차)는 저희가 Colab이라는 환경에서 AI, 딥러닝, 그리고 딥페이크 데이터가 어떻게 생겼는지 '기술 중심'으로 탐색하고 분석해 봤습니다.
오늘(2일차)은 '도메인(Domain)'과 '기획(Planning)'에 집중하는 시간입니다. 우리가 배운 기술을 '어디에', '어떻게' 적용할지 구체화하는 단계이죠.
그 첫 번째로, 우리가 만들 딥페이크 탐지 시스템의 주 무대가 될 '스마트시티'의 산업 동향부터 살펴보겠습니다."
•
정의: ICT 기술을 도시 공간에 적용, 도시 자원을 효율적으로 활용함.
"먼저, 스마트시티의 '정의'부터 다시 짚어보겠습니다.
교안을 보시면, 'ICT 기술을 도시 공간에 적용하여, 도시 자원을 효율적으로 활용하는 것' 이라고 정의되어 있습니다.
여기서 핵심 키워드는 '효율적 활용'입니다.
기존의 도시(Dumb City)가 교통 체증, 에너지 낭비, 쓰레기 처리 문제 등 비효율적인 자원 사용을 감수했다면, 스마트시티는 ICT 기술을 이용해 이 모든 것을 '데이터 기반'으로 최적화하겠다는 접근입니다."
•
국내외 사례 분석 (HWP 기반)
◦
한국 (세종, 부산): 국가 시범 도시.
◦
싱가포르: Virtual Singapore (디지털 트윈 활용).
◦
바르셀로나: 데이터 기반 도시 운영.
"말로만 들으면 막연하니, '국내외 주요 사례'를 보겠습니다.
•
한국 (세종, 부산): 이 두 도시는 '국가 시범 도시'입니다. 새로운 AI 서비스나 자율주행, 스마트 그리드 같은 기술들을 실제 도시에 적용해 보는, 국가적인 '테스트베드(Testbed)' 역할을 수행하고 있습니다.
•
싱가포르 (Virtual Singapore): 여기가 아주 중요한 사례입니다. 싱가포르는 '버추얼 싱가포르'라는 이름으로, 도시 전체를 3D 가상 공간에 쌍둥이처럼 복제했습니다. 이것이 바로 1일차에 언급했던 '디지털 트윈' 기술입니다.
이 가상 도시에서 뭘 할 수 있을까요? 예를 들어, '이곳에 새 건물을 지으면 바람길이 어떻게 바뀔까?', '바이러스가 퍼지면 시민들의 동선이 어떻게 겹칠까?' 같은 모든 시뮬레이션을 현실에 적용하기 전에 미리 돌려볼 수 있습니다.
•
바르셀로나: 바르셀로나는 '데이터 기반 도시 운영'의 대표 주자입니다. 도시 전역에 IoT 센서를 설치해서, 주차 공간, 쓰레기통 상태, 교통 흐름을 실시간으로 수집합니다. 그리고 이 데이터를 AI가 분석해서 'A 구역 쓰레기차가 지금 출발해야 한다', 'B 주차장이 비어있다' 같은 최적의 의사결정을 내립니다."
•
핵심 기술: IoT, 빅데이터, AI, 그리고 디지털 트윈.
"방금 보신 사례들을 관통하는 '핵심 기술'이 바로 이 세 가지입니다.
1.
IoT (사물인터넷): 도시의 모든 데이터를 수집하는 '신경망'입니다. (CCTV, 센서 등)
2.
빅데이터: 수집된 데이터를 저장하고 처리하는 '창고'입니다.
3.
AI (인공지능): 이 데이터에서 패턴을 찾아 '예측'하고 '판단'하는 '두뇌'입니다.
4.
그리고 더하여 디지털 트윈: 그리고 이 모든 것을 시뮬레이션하는 '가상 실험실'입니다.
2. 딥페이크 탐지 기술의 스마트시티 적용 (핵심)
•
개요: 1일차에 학습한 딥페이크 기술은 스마트시티의 '신뢰'를 위협함.
"하지만 이 모든 스마트시티의 근간은 '데이터의 신뢰'입니다.
만약 IoT(CCTV)가 수집한 영상 데이터가 가짜라면? AI 두뇌가 가짜 데이터를 기반으로 잘못된 예측을 한다면?
바로 이 지점에서 '딥페이크 탐지'가 스마트시티의 핵심 기술로 등장하게 됩니다.
다음 장에서는 이 딥페이크 탐지 기술이 스마트시티에 구체적으로 어떻게 적용되는지 살펴보겠습니다."
•
적용 분야
◦
보안: 비대면 민원 서비스 신원 확인, 얼굴 인식 출입 시스템 강화.
◦
미디어/통신: 가짜 뉴스 모니터링, 재난/교통 상황 오정보 방지.
◦
복지/의료: 비대면 의료 환자 본인 확인, AI 기반 약자 관리(고독사 예방) 시스템 안정성 확보.
•
토론: 딥페이크 탐지 기술 적용 시 예상되는 문제점 및 해결 방안 (팀별 논의).
"자, 앞서서 우리는 싱가포르, 바르셀로나 같은 도시들이 데이터를 기반으로 얼마나 똑똑하게 운영되는지 살펴봤습니다.
그런데 이 모든 스마트시티 시스템의 근간에는 '데이터의 신뢰'라는 아주 중요한 전제가 깔려있습니다.
CCTV가 보내는 영상이 '진짜'라고 믿고, 비대면 인증을 요청한 사용자의 얼굴이 '그 사람 본인'이라고 믿어야만 AI가 올바른 판단을 내릴 수 있겠죠."
"바로 이 '신뢰'를 근본적으로 위협하는 것이, 우리가 1일차에 학습한 '딥페이크 기술'입니다.
AI가 만든 가짜 데이터가 스마트시티의 AI 두뇌를 속이려 하는 것이죠."
"그렇다면 우리가 만들 '탐지 기술'이 스마트시티의 어떤 분야에 적용될 수 있는지, 교수설계서(HWP)를 기반으로 세 가지 핵심 분야를 살펴보겠습니다."
"첫 번째는 보안 (Security) 분야입니다.
스마트시티는 행정, 금융, 공공 서비스를 대부분 '비대면 민원 서비스'로 처리하게 됩니다.
이때 '신원 확인'은 어떻게 할까요? 아마 카메라로 얼굴을 비추거나, 목소리를 녹음해서 인증을 하겠죠.
만약, 딥페이크로 타인의 얼굴과 음성을 합성해서 비대면 인증을 통과해버린다면? 개인정보 유출은 물론이고, 금융 사기, 공공 계정 탈취 등 심각한 문제가 발생합니다.
•
*'얼굴 인식 출입 시스템'도 마찬가지입니다. 스마트 홈이나 보안 구역에서 딥페이크 영상 하나로 잠금장치가 뚫린다면, 그건 물리적인 해킹과 다를 바가 없습니다."
"두 번째는 미디어 및 통신 분야입니다.
단순히 '가짜 뉴스' 문제를 넘어서, 도시 운영에 직접적인 타격을 줄 수 있습니다.
예를 들어, 누군가 'A대교가 붕괴했다'는 가짜 딥페이크 재난 영상을 만들어 유포한다면, 도시 전체의 교통망이 마비되고 불필요한 공포가 확산될 수 있습니다. AI 기반 재난 모니터링 시스템이 이 가짜 영상을 '실제 상황'으로 오인하고 잘못된 경보를 발령할 수도 있겠죠. "
"마지막으로, 복지 및 의료 분야입니다.
•
비대면 의료: 원격 진료 시, 의사가 환자 본인을 확인하는 것은 매우 중요합니다. [cite: 3-5] 만약 딥페이크로 환자인 척 위장하여 의료 정보를 유출하거나, 마약성 의약품 같은 것을 대리 처방받는다면 큰일이죠.
•
AI 기반 약자 관리: 교수설계서(HWP)에도 언급된 '고독사 예방 시스템'을 생각해 보죠. AI가 CCTV로 독거 어르신의 상태를 24시간 모니터링합니다. 그런데 만약 이 CCTV 영상이 딥페이크 영상(예: 평화롭게 주무시는 영상)으로 교란된다면, 실제 응급 상황을 AI가 놓치게 됩니다. 오히려 AI가 안전을 방해하는 최악의 상황이 발생하는 겁니다."
"이처럼 딥페이크 탐지 기술은, 스마트시티의 '보안', '신뢰', '안전'이라는 가장 중요한 가치를 지키는 핵심 방어막입니다.
우리가 오늘부터 설계할 '딥페이크 탐지 웹 앱'이 바로 이 방어막의 프로토타입이 될 것입니다."
모듈 2: 프로젝트 설계 워크숍 (실습 1/3) - 기획 (SMART, User Story)
1. 실습 개요
•
주제: "딥페이크 탐지 웹 애플리케이션" 개발 프로젝트 기획.
•
방식: 팀별 브레인스토밍 및 설계 문서 작성.
•
목표: 6시간 동안 실제 프로젝트 설계 과정을 압축 경험함.
스마트시티라는 '도메인'을 이해하고, '딥페이크 탐지 기술'이 왜 이 도메인의 핵심 보안 요소인지 이론적으로 접근해 봤습니다.”
"1일차에 '기술(Tech)'을 배웠고, 방금 전까지 '도메인(Domain)'을 배웠다면, 이제는 이 둘을 합쳐 실제 **'제품(Product)'**을 기획하는 단계입니다.”
•
주제(Topic): 우리의 주제는 명확합니다. 1일차에 분석했던 그 데이터를 기반으로, '딥페이크 탐지 웹 애플리케이션' 개발 프로젝트를 '기획'하는 것입니다.
•
방식(Method): 오늘은 제가 코드를 알려드리는 시간이 아닙니다. 각 팀별로 **'브레인스토밍'**을 진행하고, 그 결과를 **'설계 문서'**로 직접 작성하는 시간입니다. 여기 계신 분들은 모두 현업 개발자이시니, 실제 현업에서 하시는 '기획'과 '설계' 단계를 압축해서 진행한다고 보시면 됩니다.
•
목표(Goal): 6일차에 최종 결과물을 만들어야 하죠. 그러기 위해서 오늘 6시간 동안, 실제 소프트웨어 개발 프로젝트의 '설계 과정'을 압축해서 경험하는 것이 목표입니다.
"오늘 이 6시간 동안 우리가 만들어낸 '설계도'가 앞으로 3, 4, 5, 6일차에 우리가 개발할 모든 것의 '청사진'이 될 것입니다."
"자, 그럼 이 청사진을 그리는 첫 번째 단계, **'Step 1: 프로젝트 목표 설정(SMART 원칙)'**부터 시작하겠습니다.”
2. Step 1: 프로젝트 목표 설정 (SMART 원칙)
첫 번째 단계를 시작하겠습니다.
모든 프로젝트의 시작은 **'목표 설정'**입니다. 목표가 명확하지 않으면 6일 뒤에 우리 팀이 무엇을 만들었는지, 잘 만든 것인지조차 판단할 수 없게 됩니다.
'딥페이크 탐지 시스템'이라는 막연한 주제를 실제 동작하는 제품으로 만들기 위해, 우리는 'SMART' 원칙에 따라 목표를 구체화할 것입니다.
•
S (Specific): 명확한 목표 정의
◦
목표는 구체적이어야 하며, 달성 할 수 있는 특정 행동이나 성과를 명확히 기술해야 합니다.
•
M (Measurable): 측정 가능성 확보
◦
목표의 진행 상황을 측정할 수 있어야 하며, 정량적 지표를 통해 성과를 평가할 수 있어야 합니다.
•
A (Achievable): 현실적으로 달성 가능
◦
설정한 목표는 도전적이지만 현실적으로 달성 가능해야 하며, 필요 자원을 고려해야 합니다.
•
R (Relevant): 연관성 확보
◦
설정한 목표는 프로젝트의 전체 방향(예: 딥페이크 탐지) 및 상위 목표와 연관성이 있어야 합니다.
•
T (Time-bound): 명확한 기한 설정
◦
목표 달성을 위한 명확한 마감 기한(예: 6일차 최종 발표)이 설정되어야 합니다.
•
팀별 활동: 프로젝트의 핵심 목표 1줄로 정의하기.
이건 기획이나 PM 직무뿐만 아니라, 우리 개발자들에게도 매우 중요한 프레임워크입니다. '무엇을', '왜' 만드는지 알아야 올바른 기술을 선택할 수 있으니까요."
"SMART 원칙은 보시는 것처럼 5가지 기준의 앞 글자를 딴 것입니다. 하나씩 짚어보죠."
•
S (Specific): 명확해야 합니다.
'좋은 탐지 시스템' 같은 모호한 목표는 안 됩니다.
◦
(Bad): "딥페이크를 잘 잡는 앱"
◦
(Good): "사용자가 업로드한 **음성 파일(.mp3, .wav)**의 딥보이스 여부를 판별하는 웹 서비스"
◦
(Good): "이미지 URL을 입력받아 딥페이크 합성 여부를 90% 정확도로 탐지하는 API"
◦
목표는 구체적이어야 하며, 달성할 수 있는 특정 행동이나 성과를 명확히 기술해야 합니다.
•
M (Measurable): 측정 가능해야 합니다.
목표가 달성되었는지 아닌지를 '숫자'로 증명할 수 있어야 합니다.
◦
(Bad): "빠르게 탐지한다"
◦
(Good): "탐지 요청 후 5초 이내에 결과를 반환한다"
◦
(Good): "AI Hub 테스트 데이터셋 기준, 탐지 정확도(Accuracy) 85% 이상을 달성한다"
◦
목표의 진행 상황을 측정할 수 있어야 하며, 정량적 지표를 통해 성과를 평가할 수 있어야 합니다.
•
A (Achievable): 달성 가능해야 합니다.
목표는 도전적이어야 하지만, '6일'이라는 우리 과정의 현실적인 제약 안에서 달성 가능해야 합니다.
◦
(Bad): "실시간 스트리밍 영상의 모든 딥페이크를 100% 탐지한다" (6일 안에 불가능)
◦
(Good): "업로드된 10MB 이하의 단일 파일에 대한 탐지 기능을 구현한다"
◦
설정한 목표는 도전적이지만 현실적으로 달성 가능해야 하며, 필요 자원을 고려해야 합니다.
•
R (Relevant): 연관성이 있어야 합니다.
우리의 상위 목표, 즉 '스마트시티 보안'과 연관성이 있어야 합니다.
◦
(Bad): "연예인 닮은꼴 찾기 기능" (딥페이크와 무관)
◦
(Good): "비대면 인증 시나리오에 활용할 수 있는 음성/안면 탐지 기능"
◦
설정한 목표는 프로젝트의 전체 방향(예: 딥페이크 탐지) 및 상위 목표와 연관성이 있어야 합니다.
•
T (Time-bound): 기한이 명확해야 합니다.
모든 목표에는 마감 시간이 필요합니다.
◦
(Good): "6일차 최종 프로젝트 발표 시, 기획한 핵심 기능을 **시연(Demo)**할 수 있는 상태로 완성한다."
◦
목표 달성을 위한 명확한 마감 기한(예: 6일차 최종 발표)이 설정되어야 합니다.
"좋습니다. 이 SMART 원칙을 바탕으로, 지금부터 첫 번째 팀별 활동을 시작하겠습니다.
각 팀별로 20분 동안 토의하여, 우리가 6일 동안 만들 프로젝트의 '핵심 목표'를 단 한 문장으로 정의해 주시기 바랍니다.
(예시: "6일차까지 스마트시티 비대면 인증용 딥보이스 탐지 웹 앱 프로토타입을 개발)
3. Step 2: 기능 정의 및 사용자 스토리 작성
•
사용자 스토리 (User Story) 란?
◦
사용자 관점에서 필요한 기능을 정의하는 방식.
◦
양식: "나는 [사용자]로서, [기능]을 통해 [가치]를 얻고 싶다."
•
작성 예시
◦
"나는 (스마트시티 민원 담당자)로서, (업로드된 음성 파일)의 딥페이크 여부를 판별하여 (금융 사기를 예방)하고 싶다."
◦
"나는 (일반 사용자)로서, (이미지 URL)을 입력하여 (해당 이미지의 합성 여부)를 확인하고 싶다."
•
팀별 활동: 프로젝트의 핵심 기능 목록(최소 3개)을 사용자 스토리 형태로 작성.
"자, Step 1에서 우리 팀의 SMART 목표를 한 문장으로 명확히 정의했습니다.
이제 Step 2에서는, 그 '목표'를 달성하기 위해 '무엇을' 만들어야 하는지, 즉 **'기능'**을 정의할 차례입니다.
과거에는 '기능 명세서'라고 해서 개발자 관점에서 두꺼운 문서를 작성했지만, 최근 애자일(Agile) 환경에서는 **'사용자 스토리(User Story)'**라는 훨씬 더 효율적인 방식을 사용합니다."
"사용자 스토리(User Story)란 무엇일까요?
이름 그대로, '사용자' 관점에서 시스템의 기능을 서술하는 방식입니다.
'시스템은 ~을 제공해야 한다' (X)
'사용자는 ~을 할 수 있다' (O)
처럼, 개발자가 아닌 **사용자가 원하는 '가치'**에 초점을 맞추는 것이 핵심입니다."
"양식은 아주 간단합니다. 이 템플릿만 기억하시면 됩니다.
'나는 [사용자]로서, [어떤 기능]을 통해 [어떤 가치]를 얻고 싶다.'
•
[사용자] (Who): 이 기능을 사용할 사람은 누구인가? (예: 일반 사용자, 관리자, 민원 담당자)
•
[기능] (What): 그 사용자가 원하는 행동이나 기능은 무엇인가? (예: 파일 업로드, 결과 확인)
•
[가치] (Why): 왜 이 기능이 필요한가? 사용자가 얻는 이득은 무엇인가? (예: 사기 예방, 진위 확인)"
"교안의 작성 예시를 보겠습니다.
•
"나는 (스마트시티 민원 담당자)로서, (업로드된 음성 파일)의 딥페이크 여부를 판별하여 (금융 사기를 예방)하고 싶다."
◦
→ 이 스토리를 보면, '음성 파일 업로드 기능', '탐지 결과(판별) 표시 기능'이 필요하다는 것을 개발자가 바로 파악할 수 있습니다.
•
"나는 (일반 사용자)로서, (이미지 URL)을 입력하여 (해당 이미지의 합성 여부)를 확인하고 싶다."
◦
→ '파일 업로드'뿐만 아니라 'URL 입력 폼'도 필요하다는 요구사항이 도출됩니다.
이처럼 사용자 스토리는 우리가 3일차(React)와 4일차(NestJS)에 만들어야 할 **'기능 목록(Feature List)'**이자, **'백로그(Backlog)'**가 됩니다."
"이와 같은 사용자 스토리는 개발자는 Use Case Diagram이라는 것으로 작성합니다. 결국 둘 다 '누가(Actor) 무엇을(Function) 하는가'를 정의하는 설계의 핵심입니다.”
'사용자 스토리'는 애자일(Agile) 방식에서 요구사항을 정의하는 가벼운 형태라면, 개발자가 전통적인 소프트웨어 공학(설계)에서 사용하는 것이 바로 **'유스케이스 다이어그램(Use Case Diagram)'**입니다.
이 유스케이스 다이어그램은 시스템이 사용자에게 '무엇'을 제공해야 하는지, 그 범위를 정의하는 핵심 설계 자료입니다.
'나는 **[사용자]**로서...'라고 했던 이 **'사용자'**를 유스케이스 다이어그램에서는 **'액터(Actor)'**라고 부릅니다.
이 '액터'는 시스템 외부에 있으면서 시스템과 무언가 상호작용을 하는 모든 것, 즉 사람, 다른 시스템, 또는 시간(스케줄러)이 될 수 있습니다.
그리고 '...**[어떤 기능]**을 통해...'라고 했던 부분이 바로 '프로그램의 기능(유스케이스)' 그 자체이며, 다이어그램 안에서는 보통 타원형으로 표현됩니다.
결론적으로, 유스케이스 다이어그램은 이 **'액터(사용자)'**가 **'프로그램의 기능(유스케이스)'**과 어떻게 상호작용하는지, 그 관계와 시스템의 전체 범위를 **'도식화(Visualization)'**한 것입니다.
개발자는 이 다이어그램을 보고 '아, 우리 시스템은 A라는 액터에게는 B와 C 기능을 제공해야 하고, D라는 액터에게는 C 기능만 제공하면 되는구나'처럼 시스템의 전체적인 요구사항과 범위를 한눈에 파악할 수 있습니다. 그래서 이 자료는 프로그램의 초기 설계 시 활용되는 매우 중요한 자료가 됩니다.
방금 Step 1에서 정의한 우리 팀의 SMART 목표를 달성하기 위해 필요한 '핵심 기능 목록'을 최소 3개 이상, 사용자 스토리 양식 또는 Use Case Diagram으로 작성해 주시기 바랍니다.
(예시: '나는 관리자로서, 일일 탐지 통계를 확인하여 어뷰징 사용자를 차단하고 싶다.' 등)
시간은 30분 드리겠습니다. 작성이 끝나면 다음 단계인 '시스템 아키텍처 설계'로 넘어가겠습니다."
모듈 3: 프로젝트 설계 워크숍 (실습 2/3) - 아키텍처 및 UX
1. Step 3: 시스템 아키텍처 설계 (플로우 차트)
•
플로우 차트(Flowchart)는 시스템 아키텍처의 중요한 요소로, 프로세스나 작업 구성 요소 간의 논리적 흐름(순서)을 시각적으로 표현합니다.
•
이를 통해 전체 시스템의 동작 흐름과 처리 과정을 명확히 이해할 수 있습니다. 각 구성 요소의 역할과 작업 순서를 정리하여, 팀워크와 프로젝트 진행에 필요한 정보를 공유하는 데 도움이 됩니다.
•
우리의 아키텍처
◦
Frontend: React (3일차 학습)
◦
Backend: NestJS (4일차 학습)
◦
Database: MySQL (4일차 학습)
◦
AI Model: Python (Flask/FastAPI) - 5/6일차 학습
•
팀별 활동: 사용자 스토리 기반, React-NestJS-FastAPI 의 시스템 아키텍처 구성, 데이터 흐름도(Flowchart) 작성.
"자, 이제 오후 실습의 두 번째 파트, 모듈 3입니다.
Step 2에서 우리가 '무엇을' 만들지 **'사용자 스토리'**로 정의했다면, Step 3에서는 '어떻게' 만들지, 즉 **'시스템의 청사진'**을 그릴 차례입니다."
**'시스템 아키텍처 설계 (플로우 차트)'**입니다.
"**'시스템 아키텍처(System Architecture)'**는 우리 시스템의 **'구조'**입니다.
'부품'이 무엇이 있고, 그 부품들이 어떻게 '배치'되어 있는지를 보여주는 '설계도' 또는 '청사진' 그 자체입니다.
예를 들어, '사용자 화면(Frontend)', '메인 서버(Backend)', '데이터베이스(DB)'가 각각 존재하고, 서로 연결되어 있다는 구조를 정의하는 것이죠."
우리의 아키텍처의 구성은 다음 처럼 정의되어 있습니다."
"바로 이 구조입니다."
•
Frontend (사용자 화면): React (3일차 학습)
•
Backend (메인 서버): NestJS (4일차 학습)
•
Database (데이터베이스): MySQL (4일차 학습)
•
AI Model (AI 전용 서버): Python (FastAPI) (5-6일차 학습)
"이것이 우리가 6일 동안 구축할 시스템의 '아키텍처'입니다."
이 아키텍처의 각 컴포넌트(부품)들이 '서로 어떻게 통신하는지' 그 **'흐름(Flow)'**을 그리는 것입니다.
**'플로우 차트(Flowchart)'**는 이 구조 안에서 일어나는 특정 **'프로세스의 흐름'**이나 '논리적 순서'를 시각화하는 것입니다.
예를 들어, '사용자가 로그인을 시도한다' → '아이디가 맞는가? (Y/N)' → '비밀번호가 맞는가? (Y/N)' → '로그인 성공/실패' 같은 '동작의 순서'를 보여주는 것이죠."
우리가 Step 2에서 작성한 **'사용자 스토리'**를 기준으로 삼으면 됩니다."
"(예시) '나는 일반 사용자로서, 음성 파일을 업로드하여 딥페이크 여부를 판별하고 싶다.'라는 스토리가 있다면,"
"이때 데이터는 어떻게 흐를까요?
1.
사용자가 React에서 '업로드' 버튼을 클릭합니다.
2.
React는 이 파일을 NestJS 서버의 /api/v1/detect/audio (API)로 전송(POST)합니다.
3.
NestJS 서버는 요청을 받고, 파일 검증 후 'AI 분석이 필요하다'고 판단합니다.
4.
NestJS는 이 파일을 다시 FastAPI (AI 모델 서버)로 전달합니다.
5.
FastAPI가 AI 모델을 돌려 'Fake: 92%'라는 결과를 NestJS에게 반환합니다.
6.
NestJS는 이 결과를 MySQL (DB)에 저장하고,
7.
최종적으로 "탐지 결과: 가짜 92%"라는 JSON을 React에게 응답(Response)합니다.
8.
React는 이 JSON을 받아 사용자 화면에 예쁘게 표시해 줍니다."
"바로 이 **'데이터의 흐름과 처리 과정'**을 팀별로 '플로우 차트' (또는 데이터 흐름도, DFD)로 도식화하는 것이 이번 실습의 목표입니다."
엔터티 다이어그램(ERD)은 데이터베이스의 전체 구조를 한눈에 파악할 수 있도록 시각화한 상세한 설계도입니다.
우리가 만들 애플리케이션의 '데이터 창고(DB)'를 짓기 위한 '건축 도면'이라고 생각하시면 됩니다. '어떤 방을 만들고, 각 방에 무엇을 보관할지'를 정하는 거죠."
(슬라이드 두 번째 문장 강조)
"이 도면을 그리기 위해 가장 먼저 할 일은, 애플리케이션을 개발할 때 다루어야 하는 핵심 데이터 단위인 '엔터티(Entity)'를 먼저 정의하는 것입니다."
"엔터티는 쉽게 말해 '우리가 저장하고 관리해야 할 데이터의 주제'입니다.
(슬라이드 예시 강조) 예를 들어, 우리 딥페이크 탐지 앱이라면 **'사용자(User)'**가 필요하겠죠. (로그인, 파일 업로드 주체)
그리고 사용자가 요청한 '프로젝트(Project)' 또는 '탐지 요청 건(DetectRequest)'이 있을 수 있습니다.
마지막으로 그 요청에 대한 **'딥페이크 결과(Result)'**도 저장해야 합니다.
이런 '사용자', '프로젝트', '딥페이크 결과'와 같은 주요 데이터 객체들이 바로 '엔터티'에 해당합니다."
(슬라이드 세 번째 문장 강조)
"엔터티(방)를 다 정의했다면, 그런 다음, 이러한 엔터티들이 서로 어떻게 연결되어 있는지를 나타내는 '관계(Relationship)'를 명확하게 정의해야 합니다. '방'과 '방' 사이의 '문'을 만드는 작업이죠."
"예를 들어 볼까요?
•
'사용자(User)' 한 명은 여러 개의 '딥페이크 결과(Result)'를 가질 수 있습니다. (1:N, 일대다 관계)
•
'딥페이크 결과(Result)' 하나는 반드시 한 명의 '사용자(User)'에게 속해야 합니다. (1:1, 일대일 관계)"
"이처럼 1:1, 1:N(일대다), N:M(다대다) 같은 관계를 통해 시스템은 데이터가 어떻게 상호작용하고 저장되어야 하는지 그 논리적 구조를 파악할 수 있습니다."
"자, 그럼 이게 우리 개발자에게 왜 그렇게 중요할까요?
우리는 4일차에 NestJS와 함께 **'TypeORM'**이라는 ORM을 사용할 겁니다. ORM은 '객체 관계 매핑(Object-Relational Mapping)'의 약자죠.
바로 이 ERD가 TypeORM 코드의 '청사진'이 됩니다.
•
우리가 ERD에서 정의한 **'엔터티(Entity)'**는, NestJS 프로젝트에서 @Entity() 데코레이터가 붙은 **'클래스(Class)'**가 됩니다. (User.entity.ts)
•
엔터티의 '속성(Attribute)'(예: userName, email)은 클래스 내부의 **'프로퍼티(Property)'**가 됩니다. (@Column())
•
엔터티 간의 '관계(Relationship)'(예: 1:N)는 @OneToMany, @ManyToOne 같은 **'데코레이터'**로 코드에 그대로 구현됩니다.
즉, 우리가 지금 그리는 ERD는 단순한 DB 설계도를 넘어, 4일차에 작성할 '백엔드 데이터 모델 클래스 다이어그램'과 사실상 동일합니다.
•
시스템 아키텍처가 프로그램의 구조설계도라면 *'플로우 차트'**가 시스템의 **'동작(Behavior)'**을 정의하는 첫 번째 기둥이라면, **'ERD'**는 시스템의 **'데이터(Structure)'**를 정의하는 두 번째 핵심 기둥입니다.
이러한 소프트웨어 설계도가 있어야 흔들림 없이 개발을 진행할 수 있습니다."
2. Step 4: UI/UX 디자인 (대표 화면)
•
개요: 사용자가 겪을 경험(UX)과 보게 될 화면(UI) 설계.
•
활용 도구: Figma, OVEN, 또는 PPT (간단한 Wireframe 수준).
•
필수 화면
◦
메인 페이지 (파일/URL 업로드 영역).
◦
결과 확인 페이지 (탐지 결과: 진/가짜 확률, 분석 근거).
•
팀별 활동: 대표 화면 2~3개의 와이어프레임(Wireframe) 또는 Mockup 제작.
•
Step 2에서 '사용자 스토리'로 우리가 '무엇을' 만들지 정의했고,
•
Step 3에서 '플로우 차트'와 'ERD'로 '어떻게(How)' 동작하고 '무엇을(Data)' 저장할지, 즉 시스템의 '뼈대'를 설계했습니다.
이제 Step 4에서는 이 시스템의 **'얼굴'**을 설계할 차례입니다. 사용자가 실제로 '보고', '만지고', '경험'하게 될 화면, 바로 UI/UX 디자인입니다."
"먼저 개요입니다.
UI와 UX라는 용어는 많이 들어보셨을 텐데, 이 둘은 미묘하게 다릅니다."
•
UX (User Experience): **'사용자 경험'**입니다. '이 앱은 사용하기 참 편하다', '직관적이다', '결과를 이해하기 쉽다'처럼 사용자가 우리 시스템을 사용하며 느끼는 '총체적인 감정과 여정'을 의미합니다.
•
UI (User Interface): **'사용자 인터페이스'**입니다. UX를 구현하기 위한 '시각적인 수단'이죠. 즉, 사용자가 실제로 보는 '버튼', '레이아웃', '아이콘', '폰트' 등을 말합니다.
"우리의 목표는 '좋은 UX(편리한 경험)'를 제공하는 '효과적인 UI(화면)'를 설계하는 것입니다."
"우리가 지금부터 디자이너처럼 포토샵을 열고 화려한 시안을 만들지는 않을 겁니다.
우리의 목표는 '와이어프레임(Wireframe)' 또는 '목업(Mockup)' 수준의 **'설계도'**를 그리는 것입니다.
즉, '여기에 버튼이 있다', '여기에 결과 그래프가 나온다'처럼 화면의 구조와 배치를 잡는 것이 핵심입니다."
"활용 도구는 간단합니다.
전문적인 툴인 Figma를 쓰셔도 좋고, 국내 툴인 OVEN을 쓰셔도 좋습니다. 하지만 시간이 없으니 그냥 **PPT(파워포인트)**의 도형 그리기 기능만으로도 충분합니다."
"그럼 어떤 화면을 그려야 할까요?
우리가 Step 2에서 정의한 '사용자 스토리'를 만족시키기 위한 **'필수 화면'**이 있습니다."
"최소 이 두 가지 화면은 모든 팀이 설계해야 합니다."
1.
메인 페이지 (파일/URL 업로드 영역):
•
사용자가 '탐지'라는 행동을 시작하는 첫 관문입니다.
•
'음성/이미지 파일을 여기로 드래그 앤 드롭하세요' 같은 파일 업로드 영역이 있어야겠죠.
•
'또는, 분석할 이미지의 URL을 입력하세요' 같은 URL 입력 폼도 필요합니다.
2.
결과 확인 페이지:
•
탐지가 완료된 후, 사용자에게 '가치(Value)'를 전달하는 가장 중요한 화면입니다.
•
단순히 '가짜임'이라고 끝내면 안 됩니다.
•
탐지 결과: 'Real' / 'Fake'
•
신뢰도(확률): 'Fake 92%' 처럼 AI가 얼마나 확신하는지 **'정량적 지표'**를 보여줘야 합니다.
•
(선택) 분석 근거: 1일차에 우리가 librosa로 봤던 '스펙트로그램'이나, cv2로 봤던 '아티팩트 영역(히트맵)'을 시각화해서 '왜' 가짜라고 판단했는지 근거를 보여주면 훨씬 신뢰받는 서비스가 될 것입니다.
이 설계도는 3일차에 우리가 React 컴포넌트로 구현할 '시각적인 가이드'가 될 것입니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>딥페이크 탐지 프로토타입 (UI Mockup)</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Inter 폰트 적용 (Tailwind 기본) */
body {
font-family: 'Inter', sans-serif;
}
/* 활성 탭 스타일 */
.tab-active {
background-color: #ffffff; /* bg-white */
border-bottom: 2px solid #3B82F6; /* border-blue-500 */
color: #3B82F6; /* text-blue-500 */
font-weight: 600; /* font-semibold */
}
/* 비활성 탭 스타일 */
.tab-inactive {
background-color: transparent;
border-bottom: 2px solid transparent;
color: #6B7280; /* text-gray-500 */
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center p-4">
<!-- 메인 카드 -->
<div class="bg-white p-8 rounded-2xl shadow-xl max-w-2xl w-full">
<h1 class="text-3xl font-bold text-center text-gray-800 mb-6">딥페이크 탐지 프로토타입</h1>
<p class="text-center text-gray-500 mb-8">
2일차 UI/UX 와이어프레임 (React로 구현될 화면)
</p>
<!-- 탭 네비게이션 -->
<div class="border-b border-gray-200 mb-6">
<nav class="flex -mb-px">
<button id="tab-btn-image" class="tab-active py-4 px-6 text-sm focus:outline-none" onclick="showTab('image')">
이미지 탐지 (Image)
</button>
<button id="tab-btn-audio" class="tab-inactive py-4 px-6 text-sm focus:outline-none" onclick="showTab('audio')">
음성 탐지 (Audio)
</button>
</nav>
</div>
<!-- 탭 컨텐츠 -->
<div>
<!-- 1. 이미지 탐지 탭 -->
<div id="tab-content-image">
<p class="text-gray-600 mb-4">탐지할 이미지 파일을 업로드하거나 이미지 URL을 입력하세요.</p>
<!-- 파일 업로드 영역 -->
<label for="image-upload" class="flex flex-col items-center justify-center w-full h-40 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 hover:bg-gray-100 transition">
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<svg class="w-10 h-10 mb-3 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-4-4V6a4 4 0 014-4h10a4 4 0 014 4v6a4 4 0 01-4 4H7z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 9v6m3-3H7"></path></svg>
<p class="mb-2 text-sm text-gray-500"><span class="font-semibold">클릭하여 업로드</span> 또는 드래그 앤 드롭</p>
<p class="text-xs text-gray-500">PNG, JPG, GIF (MAX. 10MB)</p>
</div>
<input id="image-upload" type="file" class="hidden" accept="image/*" />
</label>
<!-- "또는" 구분선 -->
<div class="my-6 flex items-center justify-center">
<span class="flex-grow bg-gray-200 h-px"></span>
<span class="mx-4 text-gray-500 font-semibold">또는</span>
<span class="flex-grow bg-gray-200 h-px"></span>
</div>
<!-- URL 입력 폼 -->
<div>
<label for="image-url" class="block mb-2 text-sm font-medium text-gray-700">이미지 URL</label>
<input type="text" id="image-url" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500" placeholder="https://example.com/image.jpg">
</div>
<!-- 탐지 버튼 -->
<button id="detect-btn" class="w-full mt-6 bg-blue-600 text-white p-3 rounded-lg font-bold text-lg hover:bg-blue-700 transition duration-300" onclick="startDetection()">
탐지 시작 (Detect)
</button>
</div>
<!-- 2. 음성 탐지 탭 (초기 숨김) -->
<div id="tab-content-audio" class="hidden">
<p class="text-gray-600 mb-4">탐지할 음성 파일을 업로드하세요.</p>
<!-- 파일 업로드 영역 -->
<label for="audio-upload" class="flex flex-col items-center justify-center w-full h-40 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 hover:bg-gray-100 transition">
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<svg class="w-10 h-10 mb-3 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2z"></path></svg>
<p class="mb-2 text-sm text-gray-500"><span class="font-semibold">클릭하여 업로드</span> 또는 드래그 앤 드롭</p>
<p class="text-xs text-gray-500">MP3, WAV, M4A (MAX. 10MB)</p>
</div>
<input id="audio-upload" type="file" class="hidden" accept="audio/*" />
</label>
<!-- 탐지 버튼 -->
<button id="detect-btn-audio" class="w-full mt-6 bg-green-600 text-white p-3 rounded-lg font-bold text-lg hover:bg-green-700 transition duration-300" onclick="startDetection()">
탐지 시작 (Detect)
</button>
</div>
</div>
<!-- 3. 결과 섹션 (초기 숨김) -->
<div id="result-section" class="hidden mt-8 border-t border-gray-200 pt-6">
<!-- 3-1. 로딩 스피너 -->
<div id="loading-spinner" class="text-center">
<svg class="animate-spin h-8 w-8 text-blue-600 mx-auto" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<p class="mt-2 text-lg font-semibold text-gray-600">AI 모델이 분석 중입니다...</p>
<p class="text-sm text-gray-500">잠시만 기다려주세요.</p>
</div>
<!-- 3-2. 결과 표시 (초기 숨김) -->
<div id="result-content" class="hidden">
<h2 class="text-2xl font-bold text-gray-800 mb-4">탐지 결과</h2>
<!-- 최종 판정 -->
<div class="bg-red-100 border-l-4 border-red-500 text-red-800 p-4 rounded-lg shadow">
<p class="text-sm">최종 판정</p>
<p class="text-3xl font-bold">딥페이크 (Fake)</p>
</div>
<!-- 신뢰도 -->
<div class="mt-4">
<label class="block text-sm font-medium text-gray-700">AI 신뢰도: 92%</label>
<div class="w-full bg-gray-200 rounded-full h-4 mt-1">
<div class="bg-red-500 h-4 rounded-full" style="width: 92%;"></div>
</div>
</div>
<!-- 분석 근거 -->
<div class="mt-6">
<h3 class="text-lg font-semibold text-gray-700 mb-2">분석 근거 (Analysis Basis)</h3>
<div class="w-full h-48 bg-gray-900 text-gray-300 rounded-lg flex items-center justify-center text-center p-4">
(1일차에 분석한 '스펙트로그램' 또는 'AI 히트맵(Heatmap)'이<br>
여기에 시각화되어 '왜 Fake인지' 근거를 제시합니다.)
</div>
</div>
<!-- 다시하기 버튼 -->
<button class="w-full mt-6 bg-gray-500 text-white p-3 rounded-lg font-medium hover:bg-gray-600 transition" onclick="resetDetection()">
다른 파일로 다시 탐지
</button>
</div>
</div>
</div> <!-- /메인 카드 -->
<script>
// --- 탭 전환 로직 ---
function showTab(tabName) {
const imageTabBtn = document.getElementById('tab-btn-image');
const audioTabBtn = document.getElementById('tab-btn-audio');
const imageTabContent = document.getElementById('tab-content-image');
const audioTabContent = document.getElementById('tab-content-audio');
if (tabName === 'image') {
// 이미지 탭 활성화
imageTabBtn.classList.add('tab-active');
imageTabBtn.classList.remove('tab-inactive');
audioTabBtn.classList.add('tab-inactive');
audioTabBtn.classList.remove('tab-active');
imageTabContent.classList.remove('hidden');
audioTabContent.classList.add('hidden');
} else {
// 오디오 탭 활성화
audioTabBtn.classList.add('tab-active');
audioTabBtn.classList.remove('tab-inactive');
imageTabBtn.classList.add('tab-inactive');
imageTabBtn.classList.remove('tab-active');
audioTabContent.classList.remove('hidden');
imageTabContent.classList.add('hidden');
}
// 결과 창이 열려있으면 닫기
resetDetection();
}
// --- Mock API 호출 로직 ---
const resultSection = document.getElementById('result-section');
const loadingSpinner = document.getElementById('loading-spinner');
const resultContent = document.getElementById('result-content');
// (가짜) 탐지 시작
function startDetection() {
// 1. 결과 섹션 보이기
resultSection.classList.remove('hidden');
// 2. 로딩 스피너 보이기
loadingSpinner.classList.remove('hidden');
// 3. 실제 결과 숨기기
resultContent.classList.add('hidden');
// 4. (가짜) 2초간 AI 분석 시뮬레이션
setTimeout(() => {
// 5. 로딩 스피너 숨기기
loadingSpinner.classList.add('hidden');
// 6. 실제 결과 보이기
resultContent.classList.remove('hidden');
}, 2000); // 2초
}
// 초기화 (다시하기)
function resetDetection() {
resultSection.classList.add('hidden');
loadingSpinner.classList.add('hidden');
resultContent.classList.add('hidden');
}
</script>
</body>
</html>
HTML
복사
모듈 4: 프로젝트 설계 워크숍 (실습 3/3) - DB 및 API 설계
1. Step 5: 데이터베이스 설계 (ERD)
•
엔터티 다이어그램(ERD)은 데이터베이스의 전체 구조를 한눈에 파악할 수 있도록 시각화한 상세한 설계도입니다.
•
애플리케이션을 개발할 때 다루어야 하는 핵심 데이터 단위인 '엔터티(Entity)'를 먼저 정의합니다.
•
그런 다음, 이러한 엔터티들이 서로 어떻게 연결되어 있는지를 나타내는 '관계(Relationship)'를 명확하게 정의합니다.
•
팀별 활동: 핵심 엔터티를 포함한 간략한 ERD 작성. (TypeORM의 기반)
2. Step 6: API 설계 (RESTful API)
•
RESTful API: Frontend(React)와 Backend(NestJS) 간의 통신 규약.
•
설계 요소: Method (행위), Endpoint (자원), Request (요청), Response (응답).
•
설계 예시
◦
요청: POST /api/v1/detect/audio
◦
Request Body: { "file": (audio_file) }
◦
Response Body: { "status": "success", "is_deepfake": true, "confidence": 0.92 }
•
팀별 활동: 기능 목록 기반 API 명세서 2개 이상 작성.
Step 5: API 설계 (RESTful API)]
"자, 드디어 2일차 설계 워크숍의 마지막 단계입니다.
지금까지 우리 팀의 '목표(SMART)', '기능(User Story)', '뼈대(Architecture)', '데이터(ERD)', '얼굴(UI/UX)'까지 모두 정의했습니다."
"이제 이 모든 것을 연결할 **'신경망'**을 설계할 차례입니다.
바로 3일차에 만들 **Frontend(React)**와 4일차에 만들 **Backend(NestJS)**가 서로 대화할 수 있게 만드는 '통신 규약(Contract)', RESTful API 설계입니다."
"RESTful API는 우리가 만들 React(Client)가 NestJS(Server)에게 '무엇을 해달라'고 요청하는 '양식' 또는 '메뉴판'과 같습니다.
이 메뉴판이 명확해야, 프론트엔드 개발자와 백엔드 개발자가 각자 다른 파일(React, NestJS)을 만들면서도 완벽하게 협업할 수 있습니다.
이 '메뉴판'을 설계하는 4가지 핵심 요소가 있습니다."
1.
Method (행위):
•
사용자가 '무엇을' 할 것인지 정의합니다.
•
POST: (우리 주력) '생성' 또는 '제출'. 딥페이크 탐지를 위해 파일을 **'제출'**할 때 씁니다.
•
GET: '조회'. 과거의 탐지 목록을 '가져올' 때 씁니다.
•
(PUT: 수정, DELETE: 삭제)
2.
Endpoint (자원):
•
'어디에' 요청할지 정하는 '주소'입니다.
•
예: /api/v1/detect/audio (1버전 api의 탐지 기능 중 음성)
3.
Request (요청):
•
사용자가 서버에 '전달하는 데이터'입니다.
•
파일을 보낼 땐 FormData를, 텍스트(URL)를 보낼 땐 JSON을 주로 씁니다.
4.
Response (응답):
•
서버가 사용자에게 '반환하는 결과'입니다.
•
우리는 JSON 형태를 표준으로 사용합니다.
"캔버스 day2_project_design.md [cite: 83-90]의 설계 예시를 보시죠. '음성 탐지' 기능의 API입니다."
•
요청: POST /api/v1/detect/audio
◦
→ '오디오 탐지' 주소로 무언가를 '제출'합니다.
•
Request Body: { "file": (audio_file) }
◦
→ 'file'이라는 이름으로 실제 음성 파일(FormData)을 보냅니다.
•
Response Body: { "status": "success", "is_deepfake": true, "confidence": 0.92 }
◦
→ "성공했습니다. AI가 판단하니 '가짜(true)'이고, 그 확신은 '92%'입니다."
"이 약속(API)만 있으면, 3일차의 React 개발자는 '아, POST /api/v1/detect/audio로 FormData를 보내면 저런 JSON이 오는구나' 하고 화면을 만들 수 있고,
4일차의 NestJS 개발자는 '아, POST /api/v1/detect/audio로 요청이 오면 저런 JSON을 만들어 반환해야 하는구나' 하고 서버 로직을 짤 수 있습니다."
3. Step 7: 팀별 프로젝트 설계 발표
•
발표 (팀당 10분)
◦
프로젝트 목표 및 핵심 기능 (사용자 스토리/Use Case Diagram).
◦
시스템 아키텍처 / 플로우 차트.
◦
UI/UX 와이어프레임 및 ERD.
◦
API 명세서
•
피드백 및 정리: 강사 피드백.
3일차에는 'React'를 사용해 실제 동작하는 웹 화면(컴포넌트)으로 직접 구현하는 작업을 시작하겠습니다."
"3일차에는 JavaScript(ES6+) 핵심 문법부터 React Hooks까지, 프론트엔드 개발에 집중할 예정입니다.
오늘 설계하시느라 정말 고생 많으셨습니다. 2일차 교육은 여기서 마치겠습니다. 내일 뵙겠습니다."
요약 및 차주 예고: 3일차 - 프론트엔드 (React) 개발
•
2일차 성과: 딥페이크 탐지 웹 서비스 기획 완료 (설계 문서).
•
3일차 예고: 오늘 설계한 UI/UX를 React를 사용해 실제 웹 화면으로 구현 시작.



