이 포트폴리오는 크로뮴에서 돌리는 것을 권장합니다

isLoad.

Gloomy Store

Frontend Developer's portfolio

Introduce

profile

Dae Young, Lee

199X.11.24

010-4343-1354

serenity90s@naver.com

프론트엔드
웹표준, 웹접근성, SEO
백엔드 이해까지

Career

icon트랜스코스모스코리아 UI디자이너&퍼블리셔
(2020.04~2021.04)

icon신한투자증권 디지털플랫폼팀 웹퍼플리셔
(2021.05~2022.10)

icon하나금융 핀크 개발2팀 프론트엔드
(2022.10~2023.07)

icon대기업 S사 클라우드솔루션팀 프론트엔드
(2023.08~현재)

총 경력

specialty

웹사이트 구축 및 운영

완벽한 반응형 웹개발

일본어 자유 의사소통

영어 메일 의사소통

Education

국민대학교 임산생명공학과 졸업 2018.08

이젠컴퓨터아카데미 UI/UX 과정 2020.02

더조은컴퓨터아카데미 PHP/MySQL 프로그래밍 2021.07

이젠컴퓨터아카데미 React.js 자바스크립트 2021.11

이젠컴퓨터아카데미 React Native 앱개발 2022.04

패스트캠퍼스 Java&Spring 웹 개발 종합반 2023.08

Certifications

웹디자인 기능사

GTQ Photoshop 1급

JLPT N1

TOEIC 825

TOEIC Speaking Lv6 (140)

ITQ Internet A급

Skills

HTML5 / CSS3 / JS(ES6) / React

PHP / MySQL

Photoshop / Illustrator / Xd

Premiere Pro

Character

다정다감하고 누구와도 잘 어울립니다.
내가 맡은 임무는 극한의 책임감을 가지고
끝까지 완수하여 팀원으로서 모범이 됩니다.

Skill

FE Stack

skills

HTML5

웹표준 및 웹접근성을 준수하며, 최상의 SEO를 위한 태그를 작성합니다. 검색노출을 위한 적절한 타이틀 사용과 최적의 HTML구조, 스크린리더를 위한 정확한 태그사용 등 모든 면에 대응합니다.

skills

CSS3

거의 모든 스타일을 자유자재로 다룰 수 있습니다. 주로 BEM 방법으로 클래스명을 작성합니다.

skills

SASS

반복문과 변수사용 및 코드 중복 방지를 위한 모듈입니다. 체계적으로 SASS를 작성할 경우 다크모드나 기타 상황에서 쉽게 color를 변경 가능합니다. SCSS 문법을 사용합니다.

skills

Bootstrap

스타일시트를 처음부터 제작하기 부담스러운 토이 프로젝트에 가끔 사용합니다.

skills

ES6

화살표함수, 스프레드연산자, const, let 등을 사용하며, this의 바인딩과 TDZ에 유의하며 스크립트를 작성합니다. ES5 및 ES6 스펙의 스크립트에 대응합니다. 바벨을 사용하지 않는 환경의 경우, 또한 ie까지 대응하는 경우 ES5 스펙으로 작성합니다. 이벤트 루프를 이해하며, 순서에 맞는 스크립트 작성에 유의합니다.

skills

React.js

함수형 컴포넌트를 사용합니다. 주로 관심사별로 묶는 스크립트를 작성하며, 개발팀의 스타일에 따라서 hook끼리 묶는 경우도 있습니다. 생명주기를 이해하여, 기능이 정확하게, 또 알맞는 타이밍에 작동하도록 스크립트를 작성합니다. 모든 동작은 state로 제어합니다.

skills

Vue.js

composition api 및 options api를 사용합니다. 주로 후자로 개발이 진행되나, 새 서버 및 새 프로젝트에서 관심사별로 기능을 묶는 요청이 내려올 경우 전자로 진행할 때도 있습니다. react와 마찬가지로, state로 모든 동작을 제어합니다. vue2 및 vue3 모두 대응합니다.

skills

Next.js

SSG의 장점을 살려, 최대한 Server side에서 많은 정보를 제공하도록 스크립트를 작성합니다. 예를 들어, 게시판의 경우, getServerSideProps로 간단한 작성 내용을 넣어둡니다. 구글 외 검색로봇은 게시글 하나하나의 내용을 server side에서 이해하도록 조치합니다. 클라이언트에 모든 스크립트가 다운로드 되어 hydrate 되었을 때, 달라지는 내용은 style밖에 없도록 노력합니다.

skills

Typescript

엄격한 타입 적용을 위해, 컴파일 단계에서 에러를 잡기 위해 사용합니다. 되도록 any를 사용하지 않도록 노력하고 있습니다.

skills

Redux

전역 상태 관리를 위해 사용하고 있습니다. props가 전달되는 범위가 넓어질 때, redux로 상태관리를 진행합니다.

skills

React-query

이제는 tanstack으로 알려진 React query를 서버상태 관리 및 관찰용으로 넣었습니다. fetch의 성공/실패/로딩중 등 관측이 가능하고, 언제 시도했는지, 몇 번째 시도인지 등 서버와의 통신상태를 점검할 수 있습니다. 근데 제 생각에는 생긴 것 자체가 가독성이 좋지는 않은 것 같아요.

skills

JQuery

legacy 프로젝트 외에는 크게 사용할 일이 없으나, 종종 jsp로 제작된 프로젝트에 jquery가 사용되고 있어 이 때 사용합니다. 기본적인 ui메소드와 ajax를 사용합니다.

BE Stack

skills

PHP

기본적인 CRUD를 알고있습니다. 게시판 제작 경험이 있으며, 실제 자체 제작 블로그에 PHP가 사용되고 있습니다. 로그인의 경우 쿠키와 세션으로 관리합니다.

skills

Node.js

express를 사용하여, 클라이언트에서 오는 각종 요청에 대해 처리합니다. 기본적으로는 PHP와 같이 간단한 CRUD를 처리하며, 클라이언트사이드 언어인 자바스크립트로 서버사이드까지 다룰 수 있는 점에 주목하고 있습니다.

skills

MySQL

SELECT, UPDATE, WHERE 외 간단한 CRUD를 할 수 있습니다.

skills

mongoDB

데이터가 json 그 자체이며, nodejs서버 상에서 객체를 자유롭게 다룰 수 있기 때문에 SQL과 마찬가지로 간단한 CRUD가 가능합니다.

skills

Spring

Spring 기반 Thymeleaf에도 간단한 대응이 가능합니다. spring framework의 대략적인 구조를 알고 있습니다. 또한 서블릿 기반 JSP, JSTL에도 간단한 대응이 가능합니다.

APP Stack

skills

React Native

React Native 컴포넌트를 사용하여 간단한 UI제작이 가능합니다.

Collaboration

skills

Git

github앱이나 git bash, 혹은 fork로 작업물을 관리합니다. 되도록 conflict가 일어나지 않도록 최신 소스를 주기적으로 pull 합니다.

skills

Jira

모든 작업에 대해 Jira에 내용을 작성 후 진행합니다. 전사적으로 HR이 어떻게 관리되는지 알기 쉽게 하기 위해 되도록 자세한 내용을 작성해 넣어둡니다.

skills

Github

skills

Confluence

프론트 소스의 관리를 위해, 중요 내용은 Confluence에 작성해둡니다.

skills

Gitlab

Design Stack

skills

Photoshop

사진사, 디자이너 업무 등으로 포토샵은 10년 이상 다루어 전문가 수준입니다.

skills

Illustrator

벡터그래픽 제작 시 사용합니다.

skills

XD

주로 웹사이트/앱 UI제작 시 사용합니다. 금융권 프로젝트에서 UI제작 시 사용했습니다.

skills

Zeplin

디자이너들이 작업해놓은 UI를 보고 개발에 옮깁니다.

skills

Figma

기능과 UI가 XD와 흡사하여, 어렵지 않게 대부분의 기능을 다룰 수 있습니다.

Deployment

skills

개인서버

본 포트폴리오 및 모든 작업물은 개인서버에 띄워져 있습니다. nginx로 리버스 프록시를 적용하여, domain.com/ 은 프론트 서버에, domain.com/api/는 api 서버에 연결되도록 포트번호를 지정합니다.

Portfolio - 글루미채팅

img
ConceptwebRTC 영상통화 + websocket채팅 + OAuth 로그인
FrontendNext.js 13
BackendNode.js(express, socket.io)
DatabasemongoDB
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%), BE개발(10%)
사용방법한 명은 id: admin, pw: admin으로 로그인,
한 명은 id: admin2, pw: admin2으로 로그인,
서로 영상통화와 채팅을 즐겨봅시다.

원한다면 google이나 github 소셜 로그인도 가능합니다.
포트폴리오 설명

프론트엔드

채팅: 채팅 기능의 핵심은 웹소켓입니다. 소켓에 메세지를 emit하면, 웹소켓 서버에서 해당 방에 참여한 모든 이들에게 broadcast해주고, broadcast 받은 클라이언트들은 모두 새로운 메세지를 받게되는 형태입니다.

화상통화: 2개의 PEER, 시그널 서버, TURN서버가 주 핵심요소입니다. 최초 동작시, 웹소켓으로 만들어진 시그널 서버에 sdp정보를 보내어 PEER끼리 서로 정보를 주고받습니다. 이후 서로 주고받은 sdp를 토대로 STUN서버 (stun:stun.google.com:19302)에 중계요청을 보내며, 중계기로부터 받은 영상데이터 혹은 PEER에게 직접 받은 영상데이터를 video태그에 재생시킵니다.

백엔드

채팅: 서버에서는 웹소켓 connection이 일어나면 클라이언트에서 받은 uuid를 토대로 방을 생성합니다. 이제 그 uuid로 전달된 메세지를 해당 방에 참가한 사람들에게 broadcast해줍니다.

화상통화: 시그널 서버는 클라이언트로부터 받은 sdp 정보를 상대방 peer에게 전송하여, 서로 연결을 잘 수립할 수 있도록 합니다. 이후 STUN서버나 TURN서버를 통해 Interaction Connection Establishment 후보를 찾고, 서로의 PEER간 연결이 수립되면, 그 이후부터는 서버의 역할이 매우 작아집니다.
단, TURN서버의 경우 직접 구축하는 것이 어려웠기 때문에 google 공개도메인을 사용했습니다.

OAuth: NextAuth 라이브러리를 통해 구현합니다. 사용자(Resource Owner)는 현 프로젝트의 인증서버에 인증 요청을 보냅니다. 그후 인증서버는 구글의 Resource 서버에 요청을 보내게 되고, Resource Owner의 인증을 위임받은 구글서버에 의해 인증서버에는 사용자의 정보(이름, 메일)이 도착하여 토큰화되어 사용할 수 있게 됩니다.

Portfolio - 글루미투표

img
ConceptPWA(Progressive Web App), react query, mysql, nextjs13, 쿠키, 카카오 공유
FrontendNext.js 13, React-query(서버상태관리)
BackendNext.js 13
DatabaseMariaDB (MySQL)
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%), BE개발(100%)이 프로젝트는 개발중입니다.
사용방법사용자의 정보는 접속해서 쿠키를 허용하는 순간부터 고유한 아이디로 저장됩니다.
이제 투표를 만들고, 카카오톡으로 공유해보세요!

정말 쉽습니다. 그냥 투표를 제작하고, 링크를 뿌려보세요.

자유로운 익명투표의 시작입니다.
포트폴리오 설명

프론트엔드

content image우선 getServerSideProps로 해당 투표의 uuid를 토대로, 투표 데이터가 있는지 확인 후 없으면 custom 404페이지로 안내합니다.

content image존재한다면 실제 투표페이지로 안내합니다.
투표 데이터는 React Query를 통해서 fetch 하며, 데이터가 정상적으로 송/수신 되고 있는지 React-query devtool을 통해 관찰할 수 있습니다.

이 프로젝트는 Build하지 않고, React Query devtool을 보여주기 위해 pm2 - npm run dev로 .env.development 환경으로 돌리고 있는 상태입니다. (꽃 이미지)

content image투표를 간편하게 생성 가능하며, 언제든지, 자유롭게 생성 가능합니다.

content image투표를 하면, 바로 DB에 내용이 업데이트 되고, react query에 설정된 의존성 배열에 의해 한 번 더 fetch를 거치게 됩니다. 이후 투표 결과 화면이 송출됩니다.

나의 데이터는 쿠키에 저장되어있으며, (랜덤으로 배정된 고유한 uuid를 마치 id처럼 사용) 내가 이미 투표를 했으면 투표 결과를 보여줍니다.

content imagecontent image복사하기 및 카카오 공유가 가능합니다.
모바일, PC 어느쪽이든 쉽게 투표 URL을 공유할 수 있습니다.

백엔드

content imagecontent imageDB: 비록 백엔드 전문가는 아니나, 나름대로 DB를 설계도 해보고 효율적인 환경을 구축하기 위해 연구했습니다.

vote table: 투표의 개요를 저장합니다.
votemenu table: 해당 투표의 보기를 저장합니다. parentid로 vote table의 uuid를 추적합니다.
voter table: 투표자들이 어떤 보기에 투표했는지 저장합니다. 몇 번 보기의 index를 선택했는지만 저장하면 됩니다.

백엔드에서는 이를 정제하지 않고 전부 클라이언트로 보내서, 클라이언트에서 알아서 데이터를 정제해서 map으로 뿌려줍니다.

Nextjs API: 크게 네 가지 기능으로 나뉩니다.

1. 단순히 투표 DB내용을 클라이언트로 쏴주는 기능
2. 쿠키 데이터가 있는 사용자에 한해서, 내가 만든 투표방을 보여주고, 내가 선택한 투표 보기에 [선택함]을 노출시켜 줍니다.
다만 쿠키가 제거되면 이는 모두 사용할 수 없게 됩니다.
3. 투표 삭제하기 기능: bcrypt를 사용해서 암호화 및 verify를 실행합니다. 올바른 비밀번호를 입력하면, 투표가 실제로 삭제됩니다.
특정 Flag를 만들어서 투표를 비노출 시키는 방법도 있으나, 투표 row가 무한이 늘어나는 것을 방지하기 위해 실제 row를 삭제하는 방법을 채택했습니다. 집에 비싼 서버가 있고 전기세 감당이 된다면 전자의 방법을 택할 수도 있습니다.
4. 투표 관측기간이 지나면, scheduler가 24시간에 한 번씩 실제 row를 삭제하여 더이상 투표를 볼 수 없게 합니다.
node-cron vs node-schedule 둘 중에 고민을 많이 했으나, 사용자가 많은 후자를 택했습니다.

Portfolio - 풀무원 로하스

img
Concept풀스택 쇼핑몰(MERN스택)
FrontendReact.js
BackendNode.js, PHP
DatabasemongoDB
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%), BE개발(100%), 호스팅(100%), 도메인 구매, 검색광고등록(100%)
사용방법실제 쇼핑몰입니다. 결제까지 전부 진행됩니다. 구매가 완료되면, SMS와 이메일로 구매내역이 날아갑니다. (PHP mailer 및 naver SMS API)
포트폴리오 설명

프론트엔드

풀무원 지점을 운영하고 있는 어머니를 위한 쇼핑몰입니다. 상품 목록페이지, 상품 상세페이지에만 데이터가 들어가기 때문에, 해당페이지에만 데이터를 바인딩 시켜서 보여줍니다. ajax로 데이터를 받아온 뒤, promise와 await로 동기적으로 state를 변경하여 각 상품의 상세 정보를 렌더합니다.

백엔드

모든 서비스를 javascirpt로 구현하기 위해 MERN스택으로 쇼핑몰을 구현했습니다. 실 결제를 위한 모듈은 아임포트를 사용하여, 아임포트 이외에는 전부 스스로의 힘으로 구현했습니다.

프론트에서 상품 고유넘버를 전송하면, mongoDB에서 해당 상품이 실제로 존재하는지 조회한 후, 결제 솔루션 서버로 결제정보를 전송합니다.
결제정보가 전송되어 response값을 성공적으로 전송받으면, 구매내역 DB에 구매정보를 저장한 뒤 네이버 클라우드 서버에 SMS를 전송합니다. 이 때 클라우드 서버로 전송되는 header정보는 sha256으로 암호화 되어 전송됩니다.

최종적으로, PHP서버로 json을 전송하면 PHP mailer가 구매자에게 메일을 전송해줍니다.

Portfolio - 료칸 호에이소

img
Concept풀스택 호텔예약
FrontendReact.js
BackendPHP
DatabaseMariaDB (MySQL)
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%), BE개발(100%)
사용방법id: admin, pw: admin으로 로그인 후,
호텔 예약을 진행해봅니다. 이메일을 본인 메일로 넣을 경우, 예약 내역이 전송됩니다.
포트폴리오 설명

프론트엔드

몇 년전 일본에 가족여행을 갔을 때, 너무나도 훌륭한 서비스와 분위기에 비해 숙소 웹사이트는 90년대에 머물러있어서 안타까움을 느꼈습니다. 이에 해당 료칸 웹사이트만 봐도 고객들이 오고싶게 만들도록 토이프로젝트로 리뉴얼했습니다.

이 사이트는 실제 예약이 가능합니다. 라이브러리 없이 달력을 구현하고, 그 달력에 예약기능을 추가하여 날짜를 선택하면 날짜에 pointing이 됩니다.

실제로 제가 호텔을 운영하고 있는 것이 아니기 때문에 결제 부분만 아무 동작없이 바로 결제완료로 처리합니다.
객실의 등급에 따라, 숙박 인원 수에 따라 자동으로 요금을 계산합니다.

백엔드

게시판, 회원가입, 로그인, 예약 등이 전부 구현되어 있습니다.
또한 고객 문의를 구현해두어 form 내용이 자동으로 관리자와 고객에게 전송됩니다.

이 내용은 전부 PHP와 mariaDB로 구현되어 있습니다.

ES Module - GloomyDate

img
Concept손쉬운 날짜계산
FrontendES Module
DeploymentNPM, 자택 개인서버(NAS)
제작참여도100%
사용하는 법
npm i gloomydate
로 설치합니다.

import {gloomyDate} from 'gloomydate'
useEffect(()=>{
  gloomyDate.date('2022-05-10 08:40:20') 
    // expected returns string '1년 전'
},[])
react에서는 해당 예시와 같이 사용할 수 있습니다.
Module 설명

개요

게시판, 댓글 등에서 일일이 날짜를 계산하기 어려웠을 경우, string을 gloomyDate.date(str)에 담는 것만으로 이 게시글이 며칠전에 작성됐는지 return합니다.

개발자는 간편하게 날짜를 bind할 수 있습니다!


function App() {
  const [data,setData] = useState([{ title: 'title1', date: '2022-05-10 10:55:40'}, { title: 'title2', date: '2023-02-11 15:50:30'}])
  useEffect(()=>{
      const newData = [...data]
      newData.forEach(e=> e.date = gloomyDate.date(e.date))
      setData(newData)
  },[])
  return (
    <div className="list">
      {
        data.map((elm,idx)=>
        <div key={idx}>
          <p className="title">{e.title}</p>
          <p className="date">{e.date}</p> {/* expected: 1년 전 */}
        </div>
        )
      }
    </div>
  );
}


예상 출력결과


title1
1년 전

title2
2달 전



배포

npm publish로 배포합니다.

npm i gloomydate

로 설치할 수 있습니다.

모듈 번들러(웹팩 등)에 대응하기 위해 es module형태로 제작했으며, tree shaking에 대응하기위해 추후 모듈의 기능이 늘어날 경우 named export로 제작할 예정입니다.

(현재는 모듈 기능이 하나뿐이라 tree shaking이 크게 의미를 가지지 않음)

일반 HTML 프로젝트의 경우


<script src="https://cdn.gloomy-store.com/gloomyDate/gloomyDate.js"></script> 

로 commonJS에 대응합니다.

react의 예시와 동일하게 사용가능합니다.



3개 국어에 대응하며, 3가지 타입의 데이터 input을 지원합니다.


gloomyDate.date('2023-04-26 08:10:22','en') // formatted string
gloomyDate.date('20230426081022','jp') // string
gloomyDate.date(20230426081022,'ko') // number

'ko', 'jp', 'en'
3개 국어에 대응합니다.

예상되는 결과:


2days ago
2日前
2일 전

아무 인자도 넣지 않을 경우 'ko'가 default로 작동합니다.

14 length의 string, number에 대응하며,
'YY-mm-dd H:i:s' 형태의 string에도 대응합니다.

Portfolio - 글루미스토어

img
ConceptNext.js Hydrating
FrontendNext.js 13, Typescript
BackendNext.js 13, Typescript, MySQL
Deployment자택 개인서버(NAS)
제작참여도기획(100%), 디자인(100%), FE개발(100%)
포트폴리오 설명

프론트엔드

기존의 CSR형식의 SPA는 검색노출이 어렵고, 설령 구글 검색로봇이라 하더라도 웹서버상에서 index.html을 받았을 때 빈문서 이외에는 내용이 나오지 않습니다.

이러한 점을 해결하기 위해 Next.js의 SSG에 주목했으며, JSX가 서버사이드상에서 이미 html태그로 렌더된 상태로 전송이 되기 때문에 현 포트폴리오의 검색 노출이 더 잘될 것으로 기대하고 있습니다.

최하단 Today, Total은 pages/api 폴더 내에 제작해둔 api를 page에서 GetServerSideProps로 받아오며, DB에 오늘날짜의 테이블이 없다면 오늘 방문자 0명으로 INSERT합니다.

이미지, 폰트 등 모든 컨텐츠가 로딩되고, ajax에서 return을 받아오면 비로소 로딩화면이 사라집니다.
(개발자 도구에서 네트워크를 3G로 하고 강력 새로고침을 하면 로딩화면을 볼 수 있습니다.)

백엔드

서버에서 사용하는 것은 오늘 날짜의 today hit, total hit을 구하는 것입니다.

시간 기준은 클라이언트 기준이 되어야하기 때문에, 클라이언트에서 한국시간을 구해줍니다.
(new Date()에서 9 * 60 * 60 * 1000를 더함)
그리고 이 시간을 getServerSideProps를 사용하여 api로 보내줍니다.
시간은 보안정보가 아니기 때문에 get요청으로 parameter에 붙여서 보내줍니다.


 const [rows] = await pool.query<RowDataPacket[]>("SELECT * FROM visitor_today WHERE REGDATE='${'todayDate'}'");
 const [rows2] = await pool.query<RowDataPacket[]>("SELECT * FROM visitor_total WHERE REGDATE='${'todayDate'}'");
 // const count = rows;
 res.status(200).json([...rows,...rows2]);



api에서는 DB에 오늘날짜의 테이블이 없다면 오늘 방문자 0명으로 INSERT합니다. 만약 존재한다면 오늘 방문자의 배열을 가져와서 클라이언트로 return합니다.