[포스코x코딩온] 2차 프로젝트 회고록(1)

minjeong·2024년 4월 21일
0
post-thumbnail

1. 프로젝트 소개

Node.js, express, ejs, mysql 등 다양한 스택을 활용해서 '고가네' 웹사이트를 디벨롭하였다. 이전 사이트에서UI와 세부검색이 제일 불편하다고 느껴 이를 중점으로 진행하였다. 메인페이지에빠른 검색 을 만들어서 지역, 모집분야를 선택해 바로 채용정보에 접근하도록 구성하였다. 또한 채용 관련 정보보다 벼룩시장이나 홍보관련 글에 더 집중되어 있음을 느껴서, 채용 전문 사이트라는 전문성과 사용자의 편함을 위해 이력서 관리 페이지를 따로 만들었다. 글자수 세기,계산기,달력 등 구직자가 구직할때 필요한 정보를 빨리 얻을 수 있게 기능을 추가하였다.

선택한 계기

지인이 유치원 관련 종사자여서 우연히 듣게 되었는데, 유아관련 전문 채용 사이트 중 70% 이상의 사람들이 '고가네' 사이트를 이용하고 이 중 나이가 어느정도 있으신 분들이 많이 사용하시는데, 이때 UI 및 기능의 불편함을 느꼈다고 하였다. 뛰어나지는 않더라도 조금이나마 더 도움이 되고싶어서 해당 사이트의 UI를 디벨롭 하기로 결정했다.

프로젝트 기간

  • 2024.02.22 ~ 2024.03.08 (주말 포함, 총 16일)

팀 구성

  • 프론트엔드 2명
  • 백엔드 2명

기술 스택

Frontend

  • css
  • JQuery
  • JavaScript

Backend

  • AWS
  • Node.js(Express, EJS)

Database

  • MySQL

Communication

  • slack
  • Google Docs
  • Github

ETC

  • figma

구현 기능

  • 빠른 검색(URL 문자열 파싱)
  • 검색하기(DB)
  • 로그인 / 회원가입(이메일 인증)
  • 계산기, 글자수 세기, 달력
  • 사용자 인증(jsonwebtoken)

2. 프로젝트 진행과정

2-1. 첫 미팅

1차 프로젝트와 같이 랜덤으로 팀이 구성되었다. 팀원들이 우선적으로 원하는 파트를 정했고, 자동으로 나의 포지션은 정해졌다.
-> 각자 만들고 싶었던 웹 페이지에 대해서 생각해왔다. 그 중, 내가 제시했던 고가네 사이트 디벨롭이 전후 차이를 보여주기에도 좋고, 그동안 배웠던 것을 연습할 수 있는 좋은 기회이며, 어떤 점을 어떻게 하면 좋을지 설명했더니, 팀원 모두가 동의해서 진행하게 되었다.
1차 프로젝트를 하면서 느꼈던 것 중 하나는 기획을 할 때 브랜치 명, 함수 명, 공통 부분 등을 모든 팀원이 이해할 수 있게 세세하게 기록하는 것이었다. (그렇게 하지 않으면 무조건 충돌이 생겼다ㅜ)

2-2. 첫 번째 어려움

어떤식으로 페이지를 구성할지 같이 토론한 후, 프론트를 맡은 팀원이 figma를 이용해서 이미지화하고, 백엔드를 맡은 팀원이 ERD설계서를 만들기로 했다. 하지만 프론트를 맡은 팀원 두분이 figma를 다뤄본 적이 없어서 내가 만들게 되었다.. DB 및 라우터 정리와 figma를 같이 하게되어서 2주 중 4일정도로 생각보다 시간이 오래 걸리게 되었다.
그렇지만.. 모두 으쌰으쌰 하면서 진행했다..!

2-3. 회의록, 소통


-> 내가 기억하기 위해서라도, 일을 두번하지 않기 위해서도 회의록, TODO LIST를 써둬야 했다. slack, 구글docs, 오픈채팅을 통해서 최대한 소통하려고 노력했다..!

2-4. ERD 설계서, 화면 설계서, 초안(with Figma)

ERD 설계서는 난생 처음 해봐서 꽤나 오래걸렸다. 최대한 알아보면서 만들어봤는데, 이게 정답은 아닐 수 있지만 실제로 DB생성하고 기본키,외래키 정할때 한 눈에 볼 수 있는게 큰 도움이 되었다.

  • ERD 설계서


-> 초안에 이렇게 작성햇는데 실제 진행하면서 일부 수정된 부분이 있다.

  • 화면 설계서(초안)

  • Figma

    -> '고가네'사이트의 메인 색이 핑크색이다. 그 색의 느낌을 최대한 살리되, 좀 더 심플하게 하려고 노력했다.

2-5. 트러블 슈팅

이번 2차 프로젝트부터 백엔드를 하면서 참 문제가 많이 생겼다.. 에러찾기도 어려웠고, 팀원들도 버거워 하는게 내 눈에 보였다. 이번 팀은 전공자가 아무도 없었기에 더 그랬던 것 같다.

(1) 상세페이지의 수정(innerText)

문제

채용정보 상세페이지를 <td>로 구조를 짜고, 그에 맞는 정보를 innerText로 불러왔다.
type이 input이면 innerText로 수정이 가능한데, <td>로 하다보니 불가했다.

해결

그래서 수정버튼을 클릭함과 동시에, 페이지 내에서 정해진 id를 가진 요소들(title, place_name, address 등)의 현재 값을 가져와 dataElements 배열에 객체로 저장하였다. 추가적으로 reduce 함수를 사용하여 이 배열의 각 항목을 객체의 속성으로 변환하여 dataObject라는 객체를 생성했다.
그리고 확인버튼을 클릭하면, 수정된 값을 가진 입력 필드에서 새로운 값을 가져와 updatedDataElements 배열에 저장하고, 마찬가지로 reduce 함수를 이용하여 이 배열을 updatedDataObject라는 객체로 변환하였다.

(2) DB 다중 checkbox 형태 넣기

문제

input의 text,radio 등 하나의 객체 타입의 data는 문제 없이 DB에 들어가지만, 다중 checkbox 형태의 경우 DB에 null값이 들어가는 문제가 발생했다.
찾아본 결과, 일반적으로 데이터베이스에는 각 필드가 하나의 열(column)을 나타내는 하나의 객체 형태로 데이터를 넣어야 한다는 것을 알게되었다.

해결

공통으로 부여된 name값이나 class값을 가지고 Array.from()으로 선택된 체크 박스 요소들을 배열로 변환했다.
그리고 map((checkbox) => checkbox.value): 배열의 각 요소에 대해 체크된 체크 박스의 값을 추출하여 새로운 배열을 생성했다. 마지막으로 join(', '): 생성된 배열의 각 요소들을 쉼표와 공백을 이용하여 하나의 문자열로 연결해서 DB에 데이터를 저장했다.

(3) 하나의 계정당 하나의 게시글만 써지는 에러

문제

원래 계획은 로그인 된 계정으로 벼룩시장, 채용공고, 커뮤니티 글쓰기를 하였을때 제한없이 글을 작성하게 했다. 그러기 위해 글을 작성한 계정의 DB를 게시글 DB에 담아두기 위해 DB관계를 설정해주었다.
하지만, DB간의 관계를 설정한 후, 하나의 계정당 하나의 게시글만 작성가능한 오류가 발생했다. 이때 오류 내용은 DB간의 관계 설정이 잘못 되었다고 했다.

해결

mysql로 DB관계 외래키 검사시 null값이 들어온 것을 확인했다. 이를 targetKey를 사용해서 참고할 DB의 외래키(userId) 를 직접 설정해주었다. 이를 통해서 회원가입한 유저들에게 순서대로 부여된 고유키를 외래키로 활용하여 작성자가 분류되면서 문제를 해결하였다.

(4) 페이지에 쿼리값 넘겨주기

문제

메인페이지에 빠른 검색 기능을 통해 구직하는 사람이 모집분야, 지역만 선택하면 조건에 맞는 채용정보를 확인할 수 있는 기능을 추가하고 싶었다. 검색하기 버튼을 누르면 채용정보 페이지로 넘어가서 조건에 맞는 정보만 나오게 해야하는데,동일한 페이지에선 params에 선택한 값들을 넘겨주고 백에서 조건에 맞게 정보를 찾아서 프론트에서 보여주기만 하면 되었지만, 페이지 이동이 있을때 이 정보를 어디에 저장하고 해야하는지를 몰랐다.

해결

이때 수업에서 잠깐 배웠던 URL의 쿼리 문자열 파싱이 생각났다. 아! 쿼리문에 저장을 해서 넘겨주면 되겠구나. 라는 생각이 들어서 이를 토대로 진행했더니 해결되었다!

async function searchMainEmploy() {
    const city_name = document.querySelector('.waselect1').value;
    const job = document.querySelector('.waselect2').value;

    document.location.href = `/employ/board?city-name=${city_name}&job=${job}`; 
}//함수 실행시 url에 원하는 정보가 들어가게끔

그래서 프론트에서 아래와 같이 정보를 보내주고 백에서 무리없이 성공하면, 검색 내용을 추가하게끔 했다.

async function searchMainEmploy(city_name, job) {
    const res = await axios({
        method: 'GET',
        url: '/api/employ/board/search',
        params: {
            city_name: city_name,
            job: job,
        },
    });

    const { success, result } = res.data;
    if (success) {
        // 기존내용 삭제
        tbody.innerHTML = '';

        if (result.length === 0) {
            // 검색 결과가 없을 때 알림 표시
            alert('검색 결과가 없습니다.');
            return;
        }
        // 검색 결과를 추가합니다.
        for (let i = 0; i < result.length; i++) {
            const html = `
                <tr>
                    <td>${result[i].city_name.substring(0, 2)} ${result[i].town_name.substring(0, 2)}</td>
                    <td>${result[i].job}</td>
                    <td class = "title-td" ><a href="/employ/board/${result[i].id}" class="title-link">${
                result[i].title
            }</a></td>
                    <td>${result[i].place_name}</td>
                    <td>${result[i].career}</td>
                    <td>${result[i].createdAt.substring(5, 10)}</td>
                </tr>
                `;
            tbody.insertAdjacentHTML('beforeend', html);
        }
    }
}

추가적으로 아래의 채용정보 페이지에 무엇을 선택했는지 보여져야 하니까,

쿼리문으로 채용정보 사이트에 접속하게 되면 아래와 선택한 결과를 확인하게끔 해주었다.

window.onload = async function () {
   // URL의 쿼리 문자열 파싱 및 페이지에 반영
    const urlParams = new URLSearchParams(window.location.search);
    const city_name = urlParams.get('city-name');
    const job = urlParams.get('job');

    // 가져온 값으로 select box 설정
    if (city_name) {
        document.querySelector('.waselect1').value = city_name;
    }
    if (job) {
        document.querySelector('.recselect').value = job;
    }

    // 선택된 결과를 selectedresult에 표시
    if (city_name || job) {
        document.querySelector('.selectedresult').innerText = ` ${city_name}, ${job}`;
    }

    // 쿼리값에 따라 검색 결과 출력
    await searchMainEmploy(city_name, job);
    console.log(await searchMainEmploy(city_name, job));
};

회고록이 너무 길어지는 바람에 1탄, 2탄으로 나누었다.
다음 이야기 : 2탄

profile
중요한 건 꺾여도 다시 일어서는 마음

0개의 댓글