💻 Today's Schedule
09:00 ~ 10:00 미니 프로젝트(개인개발)
10:00 ~ 12:00 미니 프로젝트(코드병합 1차)
12:00 ~ 13:00 점심시간
13:00 ~ 18:00 CSS, CRUD 질의, 미니프로젝트(개인개발)
18:00 ~ 19:00 저녁시간
18:00 ~ 19:00 미니 프로젝트(팀회의)
19:00 ~ 21:00 미니 프로젝트(개인개발)
✍ Today I Learned
미니 프로젝트 / CRUD (팀 소개 페이지 구현)
Key Issue (프로젝트 완료까지 Timeline)
- Issue 1 : 내가 맡은 개인 프로필의 Firebase 연동이 완료 된 후 PersonalPage의 1차 병합을 진행했다. 엄청난 충돌이 발생했는데 우선 내가 github 사용법이 미숙해 발생한 문제같다. 능숙한 팀원이 코드를 잘 확인해줘서 큰 문제 없이 병합을 완료했다. 화면공유로 함께 확인하며 진행했는데 아직은 너무 어렵게 느껴졌다.
- Issue 2 : PersonalPage의 포스팅 박스에서 파일로 저장한 프로젝트 이미지가 Firebase의 스토리지로만 저장됐다. 스토리지에 저장된 이미지 URL을 Firebase의 Database로 추가해야 하는 문제가 발생했다. 포스트 영역은 내 담당이 아니었지만 PersonalPage에서 Nar Bar와 연동하기 위해서도 함께 고민해야 하는 이슈였다. 때문에 튜터님을 정말 많이 찾아갔다.
- Issue 3 : 포스트를 영역을 담당한 멤버의 코드 작성이 완료된 후 확인하는 과정에서 발견된 문제가 있었다. 포스팅박스 토글이 열리고 닫히지 않는 이슈였는데 이 문제에서도 튜터님의 도움을 많이 받았다. > 1차 병합과정에서 나타난 문제였다. 개인 프로필에서 CSS 오류를 발견했다. 매니저님께서 프론트엔드 과정을 수료하셨다는 것을 기억해 도움을 요청했고 다행히 간단히 수정할 수 있었다.
- Issue 4 : 포스트 박스를 불러오는 과정에서 새로고침 이슈가 있었다. 구글링중 Ajax 동기식/비동기식를 찾아 응용해 해결했다.
- Issue 5 : Main Page와의 병합 후 엄청난 충돌. 서버 배포까지 수많은 문제 발생. 프로젝트 경험이 있는 팀원이 해결했다. (넘 감사하고 죄송...)
- Issue 6 : 프로젝트 발표를 위한 문서화 작업, PPT 제작, 영상 제작을 진행해야 했다. 발표 자료 마감이 당장 다음날 11시이기 때문에 마무리까지 함께 하고 하루를 마무리하기로 했다. 때문에 함께 노션으로 문서화 작업을 했고, 팀원 한명이 시연 영상을 촬영하는 동안 남은 팀원들은 구글 프레젠테이션으로 함께 PPT 작업을 마무리 했다.
Firestore Database 연동
- 어제 저녁에 진행한 팀 회의에서 Firestore Database에서 개인 프로필과 프로젝트 카드를 모두 불러오기로 결정했다. 때문에 Personal Page 의 1차 병합 전에 개인 프로필의 코드를 수정해야 했다. 그리고 시간 부족으로 제작하지 못한 달력 연동까지 완료해야 했다.
- 우선 Firestore Database에 members 컬렉션을 추가해 멤버별로 필요한 정보를 필드로 모두 추가했다.
- 또 포스팅 박스에서 멤버를 대조하기 위해 멤버별로 고유한 비밀번호를 부여했다.
// Firebase SDK 라이브러리 가져오기
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
import { getFirestore } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
import { collection, addDoc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
import { getDocs } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
// Firebase SDK 라이브러리 가져오기
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
import { getFirestore, collection, getDocs, query, where, addDoc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
import { getStorage, ref, uploadBytes } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-storage.js";
<위에서부터 기존 import문 수정된 import문>
- import문 수정
- 우리팀은 기본 코드 구조를 수강했던 강의의 완성 코드로 결정하고 여기서 수정해 나가는 것으로 결정했다. '강의 코드>메인 페이지 구조>개인 페이지 구조' 순으로 작성되었기 때문에 내 코드에도 기존 강의의 import문이 있었다. 이 코드를 내가 필요한 코드로 변경하는 작업이 필요했다.
- 강의 import문 에서는 getFirestore와 collection, addDoc, getDocs를 별도로 임포트하고있다. 나는 필요한 데이터 getFirestore, collection, getDocs, query, where, addDoc 를 한줄로 작성해 가져오도록 했다. 여기서 query와 where는 조건에 맞는 데이터를 검색할때 필요해 추가했다.
- 변경된 import문에서는 필요한 데이터 getFirestore, collection, getDocs, query, where, addDoc 를 한줄로 작성해 가져오도록 했다. 여기서 query와 where는 조건에 맞는 데이터를 검색할때 필요해 추가했다.
- 추가된 코드 : getStorage, ref, uploadBytes 기능을 추가로 임포트했다. 파일 업로드 및 관리를 위한 기능이다.
// Firebase에서 멤버 데이터 로드
async function getMemberData(memberName) {
try {
// Firestore에서 'members'컬렉션을 참조
const membersCollection = collection(db, "members");
// 'name' 필드가 전달된 memberName과 일치하는 문서들을 찾기 위한 쿼리를 생성
const q = query(membersCollection, where("name", "==", memberName));
// 쿼리 결과를 비동기적으로 가져옴.
const querySnapshot = await getDocs(q);
// 쿼리 결과로 반환된 문서들을 순회함.
querySnapshot.forEach((doc) => {
// 각 문서의 데이터를 가져옴.
const memberData = doc.data();
// 가져온 데이터를 화면에 멤버 카드 형식으로 표시함.
displayMemberCard(memberData);
});
} catch (error) {
// 에러 발생 시 콘솔에 에러 메시지를 출력함.
console.error("Error fetching member data: ", error);
}
}
- 사실 강의에서 배운 코드와 다른 코드를 사용했다. 바로 TIL을 작성했어야 했는데 데이터를 불러오는 과정에서 워낙 오류가 많이났기 때문에(^^;;) 원하는 답을 찾다보니 오류를 기록하지 못했다. 구글링을 하며 차례 차례 작성해 나갔다.
- getMemberData 함수 : Firestore Database에서 특정 멤버의 데이터를 검색하고, 검색된 데이터를 화면에 표시한다.
- 각 함수의 상세 내용은 ^ 주석으로 작성했다.
// 멤버 카드를 화면에 표시하는 함수
function displayMemberCard(data) {
const profileBox = document.querySelector(".profile-box");
profileBox.innerHTML = `
<div class="row no-gutters">
<div class="col-md-8 profile-simple">
<div class="profile-container">
<img src="${data.img}" alt="Profile Image" class="profile-img" />
<div class="profile-info">
<h1>${data.name}</h1>
<h3>${data.mbti}</h3>
<p>${data.task}</p>
<a href="mailto:${data.email}" target="_blank"><img src="https://firebasestorage.googleapis.com/v0/b/sparta-ieee-b36aa.appspot.com/o/icon%2Fmail_icon.png?alt=media&token=c09553b3-e861-40dd-8916-fa5d44d6e0b4"></a>
<a href="${data.github}" target="_blank"><img src="https://firebasestorage.googleapis.com/v0/b/sparta-ieee-b36aa.appspot.com/o/icon%2Fgithub_icon.png?alt=media&token=004e9b22-7911-4c66-9ce0-a0537dd143a6"></a>
<a href="${data.blog}" target="_blank"><img src="https://firebasestorage.googleapis.com/v0/b/sparta-ieee-b36aa.appspot.com/o/icon%2Fblog_icon.png?alt=media&token=f0462d70-942c-4af3-9c36-eed361e40f60" class="blog-icon"></a>
</div>
<div class="calendar-container">
<div id="calendar"></div>
</div>
</div>
</div>
</div>`;
}
- 강의에서는 append를 사용해 데이터를 읽어와 카드 형태의 HTML을 생성하고 페이지에 추가했는데, 이번 코드에서는 쿼리 결과에서 각 문서의 데이터를 읽고 displayMemberCard 함수를 호출해 개인 프로필을 호출하도록 했다.
- displayMemberCard 함수는 멤버 데이터를 받아서 데이터를 기반으로 HTML을 생성해 .profile-box 요소의 내용으로 교체(innerHTML)한다.
- 이때 캘린더가 들어갈 자리에 id = calendar 를 함께 추가했다. (아래 캘린더 내용 참조)
<div class="container profile-box">
<!-- 멤버카드표시-->
</div>
- 때문에 기존에 작성했던 모든 멤버의 HTML을 삭제하고 위와 같은 간단한 코드로 변경했다.
<script>
document.addEventListener("DOMContentLoaded", () => {
const navLinks = document.querySelectorAll(".nav li a");
navLinks.forEach(link => {
link.addEventListener("click", (e) => {
const memberName = e.target.textContent;
getMemberData(memberName);
});
});
});
</script>
<body>
<header>
<div class="container">
<ul class="nav">
<li class="col-1" style="margin-right: 3vw;"><a href="index.html"><img
src="https://firebasestorage.googleapis.com/v0/b/sparta-ieee-b36aa.appspot.com/o/ieee.png?alt=media&token=bf5c5b68-cbe2-419e-b5c3-f1c1e65a755b" /></a>
</li>
<li class="col-1"><a href="#">sample1</a></li>
<li class="col-1"><a href="#">나유화</a></li>
<li class="col-1"><a href="#">sample2</a></li>
<li class="col-1"><a href="#">smaple3</a></li>
</ul>
</div>
</header>
</body>
- 네비게이션바와 연동을 위해 기존의 클릭 이벤트와 헤드 모두 수정이 필요했다.
- 어제 제이쿼리로 작성했었는데, 오류가 있어 구글링을 하다 이렇게 변경했었다. 코드를 여러 방법으로 변경하다 보니 처음 수정했던 코드를 그대로 뒀었다. 같은 기능을 하는 제이쿼리는 아래와 같다.
$(document).ready(function () {
$(".nav li a").on("click", function (event) {
const memberName = $(this).text();
getMemberData(memberName);
});
});
- 참고 링크 (더 많은걸 참고했는데 기록에서 찾지 못해 기억나는 것만 , , , )
FullCalendar 라이브러리 이용하기
내가 담당한 영역에는 멤버의 생일을 표시해주는 달력이 있었다. 생각하고 결정한 것
- 달력은 어떻게 만들 것인가? 풀 캘린더 라이브러리를 선택했다. 다른 방법을 고려할 시간이 부족했다.
- 달력에 멤버 생일을 어떻게 연동할 것인가? Firestore Database에 개인 문서에 생일을 입력하고 Nav Bar 호출시 함께 표시하기
결과적으로는 이런 형태로 마무리를 했는데, 원하는 디자인까지 도달하지 못했다. 라이브러리 활용하는 것이 너무 어려웠다. 사실 내가 작성한 코드가 맞는지 잘 모르겠다만..전체 코드는 아래와 같다.
<!-- FullCalendar -->
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.10.2/main.min.css' rel='stylesheet' />
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.10.2/main.min.js'></script>
<script>
// FullCalendar 초기화
const calendarEl = document.getElementById('calendar');
const events = [];
const currentYear = new Date().getFullYear();
const { month, day } = formatBirthday(data.date);
// 생일 이벤트
for (let year = currentYear; year <= currentYear + 10; year++) {
events.push({
title: 'BD',
start: `${year}-${month}-${day}`
});
}
const calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
events: events,
dayMaxEventRows: true, // 날짜 셀에 표시할 수 있는 최대 이벤트 수
views: {
dayGridMonth: {
dayMaxEventRows: 5 // 필요에 따라 조정 가능
}
}
});
calendar.render();
</script>
- FullCalendar 라이브러리의 CSS와 JavaScript 파일을 외부 CDN에서 불러왔다.
1. 달력 초기화 및 생일 날짜 형식화
// FullCalendar 초기화
const calendarEl = document.getElementById('calendar');
const events = [];
const currentYear = new Date().getFullYear();
const { month, day } = formatBirthday(data.date);
- document.getElementById('calendar') : HTML 요소 중 ID가 'calendar'인 요소를 선택한다.
- const events = []; 달력에 표시할 이벤트들을 저장하기 위한 배열이다.
- const currentYear = new Date().getFullYear(); new Date().는 현재 날짜와 시간을 나타내는 data 객체를 생성하고, getFullYear() 은 날짜의 연도를 반환한다. 생일데이터를 현재부터 미래까지 추가한다.
- const { month, day } = formatBirthday(data.date); DB에 저장된 생일이 0118(월일) 형태이기 때문에 날짜를 MMDD 형식으로 받고, 이를 { month, day } 형태로 반환한다.
2. 생일 이벤트 추가
// 생일 이벤트
for (let year = currentYear; year <= currentYear + 10; year++) {
events.push({
title: 'BD',
start: `${year}-${month}-${day}`
});
}
- 루프로 현재 연도부터 10년 후까지의 연도에 생일 이벤트를 생성한다. 각 이벤트는 title과 start의 속성을 가지며 start의 속성은 YYYY-MM-DD 형식의 문자열이다.
3. FullCalender 생성
const calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
events: events,
// dayMaxEventRows: true, // 날짜 셀에 표시할 수 있는 최대 이벤트 수
// views: {
// dayGridMonth: {
// dayMaxEventRows: 5 // 필요에 따라 조정 가능
// }
// }
});
- new FullCalendar.Calendar(calendarEl, {...}) FullCalendar.Calendar 생성자를 호출하여 새로운 달력 인스턴스를 생성한다. 여기서 calendarEl은 달력을 표시할 HTML 요소이다.
- initialView : 달력의 초기 보기를 설정한다. 여기서는 dayGridMonth(월간 보기)로 설정된다.
- events : 달력에 표시할 이벤트 목록을 설정하며 앞서 만든 events 배열을 사용한다.
- dayMaxEventRows : 하루에 표시할 최대 이벤트 수를 설정한다. true로 설정하면 기본값으로 사용된다.
- views : 특정 보기에서 사용할 추가 설정을 정의. 여기서는 'dayGridMonth' 보기에서 하루에 최대 5개의 이벤트를 표시하도록 설정됨.
- 달력에 계속 문제가 있어서 이것 저것 붙여놓고 지워가며 달력을 완성해 나갔는데 dayMaxEventRows와 views를 미처 지우지 못했나보다. 지금 보니 이번 프로젝트에서는 필요 없는 데이터라 주석처리했다.
4. 달력 렌더링
calendar.render();
- 달력을 화면에 표시한다.
여기까지하면 이렇게 답도 없는 형태의 달력이 구현된다^^.. 매니저님께 여쭤보니 보통 탬플릿을 가져온다는데 사실 시간내에 달력을 빨리 구현해 생일 데이터를 연동해야 했고 이 과정에서 많은 시간을 소요했다. 아무튼.. 구현에 성공했으니 CSS를 직접 한땀한땀 수정과정을 거쳤다..^^ ..
/* .calendar-container {
margin-left: 20px;
flex-shrink: 0;
} */
/* FullCalendar 스타일 커스터마이징 */
/* .fc-toolbar {
color: #000000;
size: 8px;
} */
.fc-daygrid-day {
background-color: #E7F0DC;
/* border: 1px solid #ddd; */
text-align: center;
}
.fc-daygrid-event {
background-color: #FF9800;
/* color: white; */
border: none;
/* padding: 2px 4px; */
}
.fc-daygrid-day-number {
color: black;
text-decoration: none;
text-align: center;
}
.fc .fc-toolbar-chunk .fc-button:hover {
background-color: #FFA62F;
border-color: #FFA62F;
}
.fc .fc-toolbar-chunk .fc-button:active {
background-color: rgb(253, 102, 1);
border-color: rgb(253, 102, 1);
}
.fc .fc-toolbar-chunk .fc-button:focus {
box-shadow: none;
}
/* .fc-toolbar-title {
font-size: 15px !important;
text-decoration: none;
} */
/* 페이지 버튼*/
.fc .fc-toolbar-chunk .fc-button {
background-color: #ffffff;
border: none;
color: black;
font-size: 13px;
padding: 5px 0px;
text-decoration: none;
}
/* .fc-today-button {
background-color: #4CAF50;
border-color: #4CAF50;
color: white;
font-size: 14px;
padding: 8px 16px;
text-decoration: none;
} */
/* .fc-today-button:hover {
background-color: #45a049;
border-color: #45a049;
} */
/* .fc-today-button:active {
background-color: #3e8e41;
border-color: #3e8e41;
} */
/* 요일 */
.fc-col-header-cell-cushion {
text-align: center;
text-decoration: none;
color: black;
}
/* 달력 높이 조절 */
#calendar {
width: 400px;
height: 500px;
margin-right: 90px;
float: right;
}
/* .fc-scroller-harness,
.fc-scroller-harness-liquid,
.fc-scroller,
.fc-daygrid,
.fc-daygrid-body {
height: 100% !important;
} */
완전 답도 없는 원하는 CSS 찾아가기^^.. 사실 주석처리 없이 모든 코드를 최종 커밋에 넣었는데, TIL을 작성하며 천천히 다 확인 해본 결과 주석처리 된 부분이 없어도 현재 모습이 나타난다. 왜 이런 일이 발생했는가 하면, 화면을 축소하면 스크롤이 발생하고 정렬에 잦은 오류가 생겼다. 또 크기 조절이 잘 안됐다. 때문에 필요한 요소가 있을때마다 구글링 > 붙여넣기를 하다 보니 이 사단이....
아무튼 그래서 최종 캘린더 CSS 코드는 아래와 같다.
/* FullCalendar 스타일 커스터마이징 */
.fc-daygrid-day {
background-color: #E7F0DC;
text-align: center;
}
.fc-daygrid-event {
background-color: #FF9800;
border: none;
}
.fc-daygrid-day-number {
color: black;
text-decoration: none;
text-align: center;
}
.fc .fc-toolbar-chunk .fc-button:hover {
background-color: #FFA62F;
border-color: #FFA62F;
}
.fc .fc-toolbar-chunk .fc-button:active {
background-color: rgb(253, 102, 1);
border-color: rgb(253, 102, 1);
}
.fc .fc-toolbar-chunk .fc-button:focus {
box-shadow: none;
}
.fc .fc-toolbar-chunk .fc-button {
background-color: #ffffff;
border: none;
color: black;
font-size: 13px;
padding: 5px 0px;
text-decoration: none;
}
.fc-col-header-cell-cushion {
text-align: center;
text-decoration: none;
color: black;
}
#calendar {
width: 400px;
height: 500px;
margin-right: 90px;
float: right;
}
병합하고 CSS 통일화, 포스트카드 연동
- 팀원과 각자 작업한 PersonalPage의 페이지를 병합했고 포스트 카드를 어떻게 가져와야 하는지 여러차례 고민했다. 사실 이 과정과 함께 스토리지로 저장한 이미지의 URL을 DB로 저장하는 방법이 큰 난관이었는데, 튜터님과 팀원의 큰 노력으로 해결이 됐다. 이 부분의 코드는 내가 작성한 코드가 아니라 충분한 이해가 없기 때문에 우선 내 코드 위주로 작성한다.
- Nav Bar 에서 멤버를 로드할때 Members 컬렉션에 개인별 포스트까지 저장하고 내용을 불러오는 것이 사실 Best였다. 하지만 데드라인이 임박한 순간까지 구현하지 못했기 때문에 다른 방법이 필요하다 생각했다. 때문에 팀원에게 Post 컬렉션을 따로 생성하고, 멤버별로 고유 비밀번호를 부여했으니 호출할때 Members와 Post를 동시호출하는 방법을 제안했다. 조금 더 구현해보기로 하고 각자 코드를 작성해 보는 중에 Members 컬렉션에 Post 컬렉션을 추가 하는 방법을 팀원이 구현해 이 방법으로 고정했다.
- 또 각자 작성한 헤더의 CSS가 일치하지 않았다. 둘 중 어떤 CSS로 맞출 것인지 의논했고, 내 헤더로 통일화 하기로 결정했다. 이 과정에서 조금 오류가 생겼는데 Project 헤더에는 부트스트랩 토글 박스가 있어 통일화 하는게 조금 어렵게 느껴졌지만, 팀원이 URL 이미지를 DB로 가져가는 방법을 구현하는 동안 스타일을 통일화 시키는데 성공했다.
// Firebase 인스턴스 초기화
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
var storage = getStorage();
var member_id = "";
var member_pw = "";
// Firebase에서 멤버 데이터 로드
async function getMemberData(memberName) {
const membersCollection = collection(db, "members");
const q = query(membersCollection, where("name", "==", memberName));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
const memberData = doc.data();
displayMemberCard(memberData);
console.log(memberData);
member_id = memberData['key'];
member_pw = memberData['member_password'];
});
console.log('key : ' + member_id);
await loadProjectCards(member_id); // 포스팅 후 카드 다시 로드
}
- 프로젝트 카드 불러오기
- Firebase에서 멤버 데이터를 로드 하는 과정에서 리로드 오류가 발생해 함께 의논했다. 이 코드는 내가 작성한 코드를 베이스로 작성하게 된건데, 구글링으로 코드를 따왔기 때문에 내 다시 천천히 해석해보다가 await를 다시 한번 살펴봤고 ajax 비동기를 알게됐다. 이를 loadProjectCards 로 추가해 실행해보니 포스트 카드가 정상적으로 불러와지는 것을 확인했다.
- 코드 실행 과정 요약
- Firebase를 초기화하고 Firestore 및 Storage 참조를 설정
- member_id와 member_pw 변수를 선언하여 멤버 데이터를 저장하도록 함.
- getMemberData 함수가 호출되면, 주어진 멤버 이름에 대해 Firestore에서 데이터를 쿼리함.
- 쿼리 결과를 처리하여 멤버 카드 정보를 화면에 표시하고, 멤버의 ID와 비밀번호를 변수에 저장함.
- 이후에 loadProjectCards 함수를 호출하여 멤버 ID에 따라 프로젝트 카드를 다시 로드함.
- 처음 프로젝트 영역 커밋을 받아왔을때 이런 모양이었다. 멤버헤드는 화면 축소/확대에 영향을 받지 않게 작성했기 때문에 스타일을 동일하게 맞춰야하는데 모달 버튼 +가 말썽이었다.
- 여기서 Bootstrap의 container, row, col 클래스를 추가하여 레이아웃을 변경하고, 마무리로 CSS를 조금 더 변경했다.
Main Page/ PersonalPage 병합 / 배포 /프로젝트 문서화 마무리
- 이 과정을 진행했을때 이미 하루 일과가 끝난 시간이었고 프로젝트를 제출해야 할 시간이 임박했기 때문에 팀장님과 Main Page를 담당한 팀원이 병합과 배포를 진행하는 동안 남은 팀원들은 제출해야 될 문서를 작성했다.
📝회고
어찌저찌 프로젝트를 마무리했다.
사실 MainPage 는 Firebase와의 연동 방법만 알고있고 페이지네이션이나, 좋아요 카운트, 프로필 카드 등 어떤 코드를 사용했는지 살펴보지 못했다. 프로젝트의 기한이 짧았고 알고 있는 것들에 비해 구현해내야 하는 것들은 너무나 많았다. Main Page와 Personal Page를 구분하여 제작하다 보니 커밋이 없으면 병합전까지 서로의 코드도 확인하지 못했다. 마지막까지 Main은 댓글 카운트를, Personal은 리로드와 이미지 URL을 해결하느라 병합이 늦어졌고, 때문에 병합과 배포는 사실 참여하지 못했다.
아쉬움도 크지만 첫번째 프로젝트에서 생각보다 더 많은 것을 배우게 된 것같아 후련한 마음이 공존한다.
앞으로의 프로젝트에서 코드 병합과 배포는 무조건 거쳐야 하는 과정이기때문에 꽤 많은 복습을 진행해야겠다.너무 힘들었지만^^..............아무튼 끝!
🔖 Tomorrow's Goal
- 밀린 CODECATA..
- 밀린 TIL 작성..
- 프로젝트 발표 참석
- 웹 기초 특강