공부의 숲은 스터디를 만들고 습관 기록과 타이머 측정을 통해 공부 기록을 하고 동기부여를 해주는 반응형 웹 어플리케이션 입니다. 기능은 크게 습관, 타이머, 이모지 기능으로 나뉘고 이를 통해 사용자는 습관 기록과 타이머 측정으로 포인트를 얻고 다른 사람들과 이모지 반응 등을 공유하여 동기부여를 얻습니다.
오늘의 습관 조회 기능, 오늘의 습관 생성, 수정, 삭제 기능 및 습관 모달 UI,
백앤드: 모달에서 습관 조회하고 습관을 생성, 수정, 삭제 하는 기능구현했다.
프론트앤드: 습관 모달 UI 를 전체적으로 구현하여 습관 화면에서 목록 수정을 클릭 했을 때 모달이 뜰 수 있도록 했다. 모달의 전체적인 동작을 구현했다.
기술 스택
Frontend: Vite, React, React Router, Axios
Backend: Node.js, Express.js, Prisma(ORM), PostgreSQL
Deploy: Netlify, Render
Tool: Git/GitHub, Figma
주요 기능
프론트엔드
모달에서 습관 조회하고 습관을 생성, 수정, 삭제 하는 기능을 만들고 db와 연동해 데이터를 주고 받는 부분을 구현했다. 또한 스터디 메인 화면과 소통하며 완료된 습관인지 완료가 안된 습관인지 구분하기 위해 habit에 isDone을 추가하여 isDone이 false인것만 띄울 수 있도록 함수를 작성했다.
백엔드
모달의 전체적인 동작을 구현했다. 삭제와 생성을 화면에서 동적으로 구현했고 완료 버튼을 누르면 그 동작들이 백으로 전송되게끔 구현했다. 스타일은 style.css를 사용했고 global css를 참조해 전체적인 통일성을 높였다. 데스크탑, 태블릿, 모바일 환경에서 다 사용 가능 하도록 반응형으로 구현했고 모바일 지향 트랜드에 맞춰 모바일 환경을 먼저 구현해 진행했다.
Git 충돌 문제: 초기 브랜치 전략이 제대로 세팅되지 않은 상태에서 동시 작업으로 인해 Git 충돌이 자주 발생했습니다. 원인을 분석한 뒤, 팀원들과 Git flow에 대한 공통 규칙을 정하고, PR 리뷰 과정을 통해 충돌 가능성을 줄였습니다.
습관 관리 로직 중복 문제: 습관을 생성, 수정, 삭제하는 API가 각각 분리되어 있어서 로직이 중복되고 관리가 복잡했으나, 이를 하나의 PUT 요청으로 통합 하고, 클라이언트에서는 id 여부와 isDone 상태에 따라 처리 방식이 달라지도록 설계했습니다.
//수정 완료 시 변경 습관들 서버로
const handleConfirmRevision = async () => {
try {
const result = await getHabits(studyId);
// 1. 새로운 습관: habits에는 있고 result에는 없는 습관들
const newHabits = habits.filter(
(habit) => !result.some((rHabit) => rHabit.id === habit.id)
);
// 2. 수정된 습관: habits와 result에서 id는 같지만 title이 다른 습관들
const updatedHabits = habits.filter((habit) => {
const existingHabit = result.find((rHabit) => rHabit.id === habit.id);
return existingHabit && existingHabit.title !== habit.title;
});
//3. 삭제 된 습관: result에는 있고 habits에는 없는 습관들
const deletedHabits = result.filter(
(result) => !habits.some((habit) => habit.id === result.id)
);
await Promise.all([
...newHabits.map((newHabit) => postHabit(studyId, newHabit)),
...updatedHabits.map(
(
{ id, ...updatedHabit }
) => patchHabits(id, updatedHabit)
),
...deletedHabits.map((deletedHabit) => deleteHabit(deletedHabit.id)),
]);
alert("습관 수정 완료");
} catch (error) {
alert("습관 수정 실패");
}
const handleConfirmRevision = async () => {
try {
await putHabits(studyId, habits);
alert("습관 수정 완료");
onClose();
} catch (error) {
alert("습관 수정 실패");
}
이렇게 라우터와 모듈을 수정한 것을 통해 프론트엔드에서 axios 로 api데이터를 연결하는 부분의 작업이 간소화 되었고 리액트 부분에서도 더 간단한 함수를 사용할 수 있게 되어 작업의 복잡성을 줄일 수 있었고 코드의 가독성도 좋아졌습니다.