Giter VIP home page Giter VIP logo

comrade's Introduction

Comrade

일정 조율 웹 어플리케이션

MERN (Mongo + Express + React + Node.js)

공식 문서

mongoose schema를 정의할 땐 자바스크립트 타입을 작성할 것.
타입스크립트 타입 말고!!

nestjs + mongo db(mongoose) YouTube

node js + mongo db(mongoose) + jwt Blog

nest js + mongo db(mongoose) + jwt Blog

Module: DB 정의
MongooseModule.forFeature([ { name: 'Auth', schema: AuthSchema, collection: 'auth' }, ]),
1st param - name model name
2nd param - [schema] schema name
3rd param - [collection] collection name (optional, induced from model name)
4th param - [skipInit] whether to skip initialization (defaults to false)

삽질1

추상화가 무엇인가
동기-비동기 처리
Promise, async, await, rxjs 비교, 장단점을 알아보자

TIMEZONE을 구하는 여러가지 방법

Asia/Seoul console.log(Intl.DateTimeFormat().resolvedOptions().timeZone);

GMT+0900 (한국 표준시) console.log(new Date().toTimeString().slice(9));

9 console.log(new Date().getTimezoneOffset() / -60);

Local Timezone은 OS에 의존한다.

comrade's People

Contributors

ucharles avatar yypp1226 avatar

Stargazers

 avatar

Watchers

 avatar

Forkers

yypp1226

comrade's Issues

stringToAvatar 모듈 분리

목적

프론트엔드의 MyMenu.js에 사용되던 stringToAvatar 함수를 다른 곳에서도 사용하기 위해 모듈을 분리하고자 함.

사용되는 곳

  • MyMenu : 캘린더의 아바타를 표시
  • Calendar(Dashboard) : 캘린더에 참가한 유저의 아바타를 표시
  • ViewDayEvent의 교집합 정보 모달 : 캘린더에 참가한 유저의 아바타를 표시

비밀번호 찾기(재설정), 이메일 보내기

시나리오

  1. 로그인 페이지에서 비밀번호 찾기 링크 클릭
  2. 비밀번호 찾기 페이지에서 이메일 입력
  3. 이메일로 비밀번호 재설정용 링크 전송
  4. 비밀번호를 2번 입력(보통, 확인용)
  5. 변경된 비밀번호를 DB에 반영

필요한 것

frontend

  1. 비밀번호 찾기 페이지(이메일 입력용)
  2. 이메일 전송 확인 페이지
  3. 비밀번호 재설정 이메일 템플릿
  4. 비밀번호 재설정 페이지

backend

  1. 이메일 확인, 토큰 설정, 이메일 전송 API
  2. 이메일 토큰으로 비밀번호 재설정 API

트랜잭션 문제 (현재 Account Setting, EditCalendars(Leave)에서 발생)

현상

  1. Account Setting에서 username(nickname) 변경 시, users model은 업데이트 되나, calendars model의 members Array는 업데이트 되지 않음. (기능:editUser)
  2. Edit Calendars에서 캘린더 탈퇴(기능: deleteItselfFromCalendar)할 시, calendars model은 업데이트 되나, members model의 calendars Array는 업데이트 되지 않음.

해결안

  • PATCH관련 API 전반적인 검토 필요

logout 요청 필요

@ucharles
서버쪽에서 httponly로 쿠키 저장 시, 클라이언트 쪽에서는 접근이 불가하니 로그아웃시 쿠키삭제처리 등을 서버쪽에서 해야합니다. (로그아웃 요청을 보내야함)

로그아웃 라우터 추가 부탁드립니다.

mongoose-unique-validator: validation failed: _id: Error, expected `_id` to be unique.

mongoose-unique-validator 에서 비롯된 버그.
User 모델의 email 요소에 unique 속성을 추가하기 위해 위의 라이브러리를 사용했다.

발각 상황
새롭게 Calendar를 작성하는 API 에서, User 에 작성한 Calendar 정보를 추가 후, save 하는 과정에 위의 에러가 발생.

User 모델에 정의된 mongoose-unique-validator 를 제거하니 정상 작동.
해결책을 찾아야 함.

관련 이슈

[react-admin v4] 버튼 클릭 직후 ::after 요소가 남아 있음

현상

react-admin v4 업데이트 후 발생.
모든 버튼이 클릭 직후 ::after 요소가 사라지지 않음. 버튼이 아닌 다른 곳을 클릭하면 사라짐.
기능상 문제는 없지만 표시가 이상하므로 문제가 있나 생각될 수 있음.

ex) 버튼을 클릭하면 클릭한 그 순간 그 상태로 계속 남아 있음.

이미지 변경 기능 보완에 대해 (Edit Calendars, Account Setting)

현상

Account Setting에서 회원정보 변경 시, 이미지 파일을 변경하지 않음에도 서버에 같은 파일이나 다른 이름으로 저장되게 됨.
(같은 이미지가 다른 이름으로 복제됨)

해결방법

  • Frontend
    현재 : 이미지 url을 파일 오브젝트로 변경 후, 요청 바디에 담아 전송. (파일이 복제 됨)
    수정 : 이미지 변경이 없을 경우, 이미지 관련 정보를 전송하지 않음.
  • Backend
    수정 : 이미지 정보가 없을 시, 이미지 정보를 업데이트 하지 않음.
    이미지를 추가한 경우, 기존에 존재하던 이미지는 서버에서 삭제

우려되는 점

현재 이미지 삭제 기능은 없으나, 추후 추가될 시 위 수정안은 수정이 필요함.

FullCalendar 로 향하는 Redirect에 대해

현재

  • FullCalendar에서 날짜를 클릭하면 해당 날짜의 이벤트 상세를 확인 가능
  • 상세 이벤트 페이지에서 뒤로가기를 하면 무조건 현재 날짜가 포함된 달이 표시됨

문제에 대한 설명, 재현

  • 현재 날짜가 4월, FullCalendar의 표시월을 5월로 바꾼다
  • FullCalendar의 날짜를 클릭하여 해당 날짜의 이벤트 상세페이지를 표시한다
  • 이벤트 상세 페이지에서 뒤로가기를 하거나 Calendar로 이동하는 버튼을 누르면 현재 날짜가 포함된 달(4월)이 표시된다

향후

  • FullCalendar로 이동 시 현재 달이 아닌, 이벤트 상세페이지에서 표시하던 달로 이동시키고 싶음
  • FullCalendar가 포함된 router에 param으로 날짜를 추가

뒤로가기

  • FullCalendar 에서 month를 변경할 때, URL도 변경한 달에 맞춰 갱신하도록 함

링크

  • 이 경우는 링크에 이동할 날짜를 지정하면 가능

CreateCalendar에서 파일 업로드 시 에러 발생

현상

  • CreateCalendar에서 파일 업로드 후 Create request시 에러 발생

Response 에러 내용

RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: LIMIT_UNEXPECTED_FILE
    at new NodeError 
    at ServerResponse.writeHead (node:_httRangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: LIMIT_UNEXPECTED_FILE
    at new NodeError 
    at ServerResponse.writeHead 
    at ServerResponse._implicitHeader 
    at write_ 
    at ServerResponse.end 
    at ServerResponse.send 
    at ServerResponse.json 
    at Layer.handle_error 
    at trim_prefix 
p_server:274:11)
    at ServerResponse._implicitHeader node:_http_server:265:8)
    at write_ 
    at ServerResponse.end 
    at ServerResponse.send 
    at ServerResponse.json 
    at Layer.handle_error 
    at trim_prefix 

CreateCalendar.js

const formData = new FormData(event.currentTarget);
    formData.append("file", file);

    try {
      const response = await axios({
        url: `${process.env.REACT_APP_BACKEND_URL}/calendar/`,
        method: "post",
        data: formData,
        withCredentials: true,
        headers: {
          "Content-Type": "multipart/form-data",
        },
      });

서버에 저장되는 Image 관리에 대해

결론

Image는 항상 참조 만 할 것.
DB 자체에 Image를 저장하는 것이 아닌, 서버에 저장한 뒤 그 URL을 DB에 저장하므로
Image를 복사하여 다른 곳에 따로 저장하는 것이 어려움.

Image가 사용되는 곳 (Frontend)

읽기

  • ViewDayEvent (user, read) ← 이슈를 개설한 이유
  • EditCalendar (calendar, read, edit)
  • UserSetting (user, read, edit)

쓰기

  • CreateCalendar (calendar, add)

수정

  • EditCalendar (calendar, edit)
  • UserSetting (user, edit)

삭제

  • EditCalendar (calendar, edit, delete)
  • 회원탈퇴 (아직 화면 없음)

/api/users/token-check 가 동시에 2번 호출될 경우 2번째 요청은 403 에러를 반환

현상

  1. 루트 경로(/)에서 getPermission이 2번 호출되고 있음.
  2. getPermission에서 /api/users/token-check을 동시에 2번 호출.
  3. 1번째 응답은 정상, 2번째 응답은 에러.

원인(추측)

  1. Refresh Token이 7일 이하로 남으면 DB update가 일어남.
  2. 백엔드 코드가 잘못되어 매 요청마다 DB update가 일어나고 있었음. (에러의 직접적인 원인은 아님)
  3. 동일한 Refresh Token으로 getPermission에서 /api/users/token-check을 동시에 2번 호출.
  4. 1번째 요청은 정상적으로 처리되어 DB가 update 됨.
  5. 2번째 요청은 update된 DB 정보를 반영하지 못한 채 일어나므로, 에러로 응답.

해결책

  • getPermissionasync/await 추가?
    • 실험결과, 효과 없음
  • getPermission이 동시에 1번만 일어나도록 하게 함.
    • 루트 경로(/)를 <CustomRoutes>로 이동

관련 이슈

#8 Refresh Token 적용하기

Authprovider의 checkAuth 프로퍼티 체크 내용

Authprovider의 checkAuth 프로퍼티의 페이지마다 실행되는데, 로그인 유무 쿠키만으로 처리해도 괜찮을까요?
(페이지에 뿌려주는 정보를 얻어올 때마다 쿠키 토큰을 이용해 인증과정을 거친다면 문제는 안될 거 같네요)

서버에서 클라이언트로 Http Status Code 500 리턴하지 않기

현재

  • Backend 에서 DB 문제 혹은 서버 내 문제가 발생할 경우 500을 리턴하고 있음
  • 서버 측에 로그를 별도로 남기지 않고 있음

향후

  • 클라이언트에게 코드 500은 보이지 않도록 수정
  • DB 에러 혹은 서버 에러가 발생할 경우 Http 응답은 404, 서버측에 console.log을 남기도록 함

Join Calendar의 입력 필드에 대해

확인이 늦어서 죄송합니다. 이하의 수정이 필요합니다.
수정은 @ucharles 가 진행하도록 하겠습니다. @yypp1226 확인만 부탁드립니다.
관련 이슈 #16 #23

현재

Nickname, Timezone 입력을 받고 있음

향후

  • 입력 필드는 Role과 Nickname
  • Role은 관리자, 멤버를 구분하는 것이 아님. 그룹 안의 역할을 의미함. 필수 입력 아님. Null 가능.
  • Timezone은 로그인 시 쿠키에 저장. DB에 저장하지 않음.
  • Timezone 입력 시 사용하는 라이브러리에 이슈가 있으므로 사용을 보류
  • Timezone 편집이 필요하다면 유저 설정에서 일괄적으로 이루어져야 함.
  • 달력별로 Timezone을 다르게 설정할 경우엔 데이터의 저장 방법 검토가 필요함. (Cookie? Local Storage?)

Refresh Token 적용하기

현재 access token 의 유효 기간은 1시간으로 설정되어 있어 매우 짧다.
refresh token 을 도입하여, UX 편의성을 향상시키고자 한다.

시나리오

  1. 로그인을 하면 Access Token과 Refresh Token을 모두 발급한다.
    이때, Refresh Token만 서버측의 DB에 저장하며 Refresh Token과 Access Token을 쿠키(httpOnly, secure)에 저장한다.

  2. 사용자가 인증이 필요한 API에 접근하고자 하면, 가장 먼저 토큰을 검사하는 미들웨어를 검사한다.
    이때, 토큰을 검사함과 동시에 각 경우에 대해서 토큰의 유효기간을 확인하여 재발급 여부를 결정한다.

  • case1: access token과 refresh token 모두가 만료된 경우 -> 에러 발생
  • case2: access token은 만료됐지만, refresh token은 유효한 경우 -> access token 재발급
  • case3: access token은 유효하지만, refresh token은 만료된 경우 -> refresh token 재발급
  • case4: accesss token과 refresh token 모두가 유효한 경우 -> 다음 미들웨어로
  1. 로그아웃을 하면 Access Token과 Refresh Token을 모두 만료시킨다.

참조

https://cotak.tistory.com/102

Frontend API 연결하기

연결이 필요한 곳

Frontend - Backend

  • Signup
    • signup
  • MyUserMenu
    • getUserById
  • EditCalendars
    • getCalendarAdminByUserId
    • setMemberToOwner
    • deleteItselfFromCalendar
  • UserSetting
    • getUserById
    • editUser

연결 완료된 곳

#51

  • MyMenu - getCalendarsByUserId
  • CreateCalendar - createCalendar
  • EditCalendars - deleteCalendar

필요에 따라 목록 수정, 코드 갱신 시 이슈 멘션 부탁드립니다.

회원가입 시 이메일 인증하기

시나리오

  1. 회원가입 시 입력받은 이메일로 인증메일을 보낸다.
  2. 인증 방법은...
    1. 이메일로 링크를 보내, 그것을 클릭하면 인증 완료
    2. 이메일로 인증번호를 보내, 그것을 클라이언트에 입력하면 인증 완료

필요한 것

frontend

  1. 이메일용 템플릿
  2. 인증 페이지 (인증 번호 입력용 or 인증 확인용 (ex. 이메일을 확인해주세요))

backend

  1. 인증 API
  2. 인증키를 관리할 DB

Calendar의 관리자 권한 여부 획득을 위한 API 추가

왜 필요한가

Frontend에서 캘린더의 관리자 권한 여부에 따라 화면 표시가 달라짐.
이를 구분해서 표시하기 위한 정보가 필요.

어디서 사용되는가

  • Calendar의 멤버 편집
  • 교집합 이벤트 확정

어떻게 구현할 것인가

  1. 단독 API 작성 (유력한 방법)
    • 장점: 구현하기 쉬움, 기능확장 용이
    • 단점: DB 접속이 늘어날 수 있음(Context로 관리 가능?)
  2. 다른 API에 포함시키기
    • 장점: DB 접속을 줄일 수 있음?
    • 단점: Calendar 관리자 권한 획득이 어느 API에서 가능한지 알기 어려움, 신기능 추가시 이를 매번 고려해야 함.
  3. 쿠키 혹은 로컬 스토리지로 관리하기
    • 언제 발행할 것인지, 언제 갱신할 것인지, 어떻게 데이터를 구성할 것인지 고려 필요
    • 장점: 정보 이용이 편리
    • 단점: 정보 유출의 가능성

[MongoDB] 확정된 교집합 이벤트를 저장할 곳에 대해

고려사항

  • 해당 데이터를 어떤 상황에서 어떻게 읽는지 확인
    • 한달 Calendar, 하루 Calendar 에서 읽고 있음
  • CRUD가 얼마나 빈번하게 일어나는지 확인
    • Create: 교집합이라면 확정 가능, 개수에 제한 없음
      (유저들이 여러 timezone을 갖고 있을 수 있으므로, "하루"의 정의가 어려움)
    • Read: 상단에 기재되어 있음
    • Update: 업데이트는 지원하지 않음
    • Delete: 삭제 가능

구현 방법

  1. Calendar 모델 안에 확정 교집합 이벤트를 포함
    • CRUD가 전체적으로 까다로움
  2. Event 모델에서 함께 관리
    • 유저가 등록하는(교집합 확정이 아닌) 이벤트와 구분할 필요 있음
    • 하나의 Collection에서 모든 Event를 관리하므로 읽기가 간편
  3. 새로운 Collection을 작성하여 관리
    • 유저가 등록하는(교집합 확정이 아닌) 이벵트와 구분할 필요 없음
    • 항상 읽어야 함. 확정 이벤트가 없을 경우에도 읽기가 반드시 발생함.

관련 이슈

#28 Event API와 Event 표시용 Library의 데이터 양식 통일하기

웹 서버가 보낸 쿠키가 클라이언트에 저장되지 않음

@yypp1226
관련 코드 commit 시 이 이슈 번호 추가하시고, 이슈 close 시 관련 commit 링크 부탁드립니다.

프론트 쪽 API 요청에 이하를 추가하십시오.

credentials: "include"

ex)

const request = new Request(
  process.env.REACT_APP_BACKEND_URL + "/users/login",
  {
    method: "POST",
    body: JSON.stringify({ email, password }),
    headers: new Headers({ "Content-Type": "application/json" }),
    credentials: "include",
  }

참조: https://developer.mozilla.org/ko/docs/Web/API/Request/credentials

Calendar 정보(Name, description) 편집하기

현재

Calendar 정보를 편집할 수 있는 화면이 없음. 생성할 필요 있음.

어떻게 만들까?

  1. FullCalendar 가 표시되는 화면에서 편집할 수 있도록 함
  2. EditCalendar에 버튼을 추가, 모달창으로 Calendar 정보를 표시할 수 있게 함.

주의사항

  • calendar의 기존 정보를 불러올 필요 있음(getCalendarByCalendarId)

Backend 정보

  • API: updateCalendarById
  • 캘린더에 속한 멤버가 아니면 접근 거부
  • admin 이 아니면 접근 거부
  • name은 입력하지 않은 경우 DB를 갱신하지 않음
  • description은 입력 내용 그대로 갱신 (공백인 경우 공백으로 갱신)

react-admin 제거하기

문제

  • <customRoutes> 에서는 AuthProvider의 기능을 제대로 사용할 수 없음
    (가능할지도 모르지만 react-admin의 기능을 거의 사용하지 않게 됨)
    #27
  • 접근권한 제한을 제대로 구현하기 위해 getPermission을 사용했지만 signup 페이지에서도 권한이 적용되는 문제 발생
  • UI 구현에 어려움이 많음
    #17
    #22

해결책

  • react-admin을 사용하지 않고, MUI를 사용하여 페이지를 구현
    • UI 구성, context 관리에 있어서 자유로워지지만, 사소한 부분까지 직접 구현해야 함
    • 인증 관리, 권한 관리, 라우팅, UI 틀 구성 등등...
    • react-calendar-timeline은 UI 틀 안에 사용이 가능해질 것 같음
  • react-adminuseAuthState를 사용하여 페이지 접근 차단
    • 메뉴는 렌더링 차단이 불가능하여 잠깐 보일 가능성이 있지만,
      비 로그인 상태이므로 Calendar 메뉴는 표시되지 않음. 치명적인 영향은 적을 것으로 판단.
    • 현재 시간이 여유롭지 않으므로 새롭게 개발하기는 힘듦

유저 초대 관련 기능 추가

해야할 일

  1. 유저 초대 모달 수정(API 연결, 링크 복사 기능 추가, 만료시간 표시)
  2. 이미 캘린더 참여 상태일 경우 해당 캘린더로 리다이렉트 (서버로부터 calednarId 받을 것)

현재 생각나는 것만 작성, 추후 더 해야할 일이 있을 시 추가하겠습니다.

관련 이슈

#13 Calendar로 유저를 초대하기

react-admin의 checkAuth, getPermission에 대해

react-admincheckAuthgetPermission을 잘못 이해하고 사용했던 것 같습니다.
이 PR의 수정이 필요합니다. #21
관련 이슈 #11

결론

  • checkAuth 에서 사용자가 로그인 상태인지 확인(LoggedIn) & 접근제한을 시킬 수 있음
  • getPermission 은 권한 습득 & 권한에 따른 접근제한에 이용가능
    • Calendar 의 관리자 권한이 필요한 기능에 사용할 수 있음

수정 방법

checkAuth

checkAuth: () => {
  if (!cookies.get("LoggedIn")) {
    return Promise.reject();
  }

  const request = new Request(
    process.env.REACT_APP_BACKEND_URL + "/users/token-check",
    { method: "GET", credentials: "include" }
  );

  return fetch(request)
    .then((response) => {
      return response.status >= 200 && response.status < 300
        ? Promise.resolve()
        : Promise.reject();
    })
    .catch(() => {
      throw new Error("Network error");
    });
},

logout

백엔드 API를 수정했습니다. 로그아웃 호출 시 403 에러를 뱉지 않게 했습니다.
아래의 코드로 로그아웃 처리가 가능합니다.

logout: () => {
  const request = new Request(
    process.env.REACT_APP_BACKEND_URL + "/users/logout",
    { method: "GET", credentials: "include" }
  );

  return fetch(request)
    .then((response) => {
      if (response.ok) {
        return Promise.resolve();
      } else if (response.status < 200 || response.status >= 300) {
        return Promise.reject();
      }
    })
    .catch(() => {
      throw new Error("Network error");
    });
},

getPermission

새롭게 추가된 달력 권한 습득 API를 이용하여 권한을 습득하시면 될 것 같습니다.
GET /api/calendar/admin

이와 같은 객체로 리턴됩니다.
{ calendars: [ {calendarId: "xxx", isAdmin: true}, {...} ] }

관련 이슈: #20

문서 내용

checkError

  • 인증관련 오류가 있는 경우, 보통 백엔드 API는 401 or 403을 리턴함.
  • react-admin 은 API에서 에러 응답이 오는 경우 checkError를 호출하게 할 수 있음.
  • 어떤 상태 코드에 따라 어떻게 에러 핸들링을 할지 이곳에서 정의하면 됨.

checkAuth

  • 사용자가 목록을 탐색하거나, 페이지를 표시, 생성, 편집할 때마다 react-admin은 checkAuth를 호출함.
  • checkAuth에서 reject 한 경우, logout 을 호출.
  • logout 에서 resolve를 호출하여 로그아웃 처리.

getPermission

  • 특정 기능에 대해 권한이 필요할 때 사용함. getPermission 은 role를 리턴함.
  • 리턴값은 문자열, 객체, 세분화된 객체일 수 있음.
  • a string (e.g. 'admin'),
  • an array of roles (e.g. ['post_editor', 'comment_moderator', 'super_admin'])
  • an object with fine-grained permissions (e.g. { postList: { read: true, write: false, delete: false } })
  • or even a function

로그아웃시 마지막 접근 캘린더 기억하기

해야할 일

  1. 로그아웃 시 마지막 접근 캘린더 기억하기 (쿠키에 캘린더 ID 저장)
  2. 재 로그인시 1의 캘린더 로드하기

보충설명

정확히는 마지막으로 접근했던 캘린더입니다. (마지막으로 접근했던 페이지가 아닙니다)

Calendar로 유저를 초대하기

시나리오

  1. 유저가 초대 URL 에 접근
    ex. /invite/:inviteId 초대 URL을 구성하는 방법은...
    • 고유한 값일 것 (uuid)
    • 규칙성을 부여하지 말 것 (uuid)
    • 접근 가능한 시간을 제한할 것 (DB로 관리)
    • URL의 길이가 너무 길지 않을 것 (/invite/:uuid)
  2. 로그인이 되지 않은 경우, 로그인 화면
  3. 로그인이 된 경우, 해당 캘린더에 이미 속해있는지 확인 (backend, calendarId 만 출력)
  4. 해당 캘린더에 속해있는 경우, 그 캘린더의 페이지로 리다이렉트
    (GET /api/calendars)
  5. 해당 캘린더에 속해있지 않다면, 캘린더에 참여하기 위한 유저 정보를 입력받음.
    (PATCH /api/calendars/member)
  6. 정보 입력 완료 후, 캘린더의 페이지로 이동

필요한 것

frontend

  1. 캘린더에 참가하기 위해 필요한 정보입력 페이지
    입력받을 정보는 아래와 같음
    • 닉네임 (임의)
    • 역할 (임의)

backend

  1. 초대 URL용 API, DB 구성

react-admin v4.0.0 정식 배포 대응

react-admin v4.0.0

v4가 정식출시 되었습니다. 지금까지 4.0.0-alpha.1를 사용해왔습니다만, 버전업이 필요합니다.

업그레이드가 필요한 이유

  • 일부 기능이 v3에 머물러 있음
    • history를 사용 가능했다. v4 부터는 없어짐.
    • useAuthState의 hook 이름이 변경됨 (loading -> isLoading)
    • <MenuItemLInk>의 prop인 leftIcon에서 svgIcon이 아닌 다른 MUI 컴포넌트를 사용해도 경고가 발생하지 않음
      #33

[react-admin v4] HashRouter 삭제하기

#25 Browser Router 사용하기 (HashRouter 제거하기)
react-admin 4.0에서 history를 사용하지 못하게 되었고, Browser Router를 사용하여 대응하려고 한다.

Event API와 Event 표시용 Library의 데이터 양식 통일하기

문제

Event API의 데이터 출력 양식과 Event를 화면에 표시하는 Library의 데이터 입력 양식이 서로 다름.
화면단에 API 데이터를 올바르게 표시하기 위해선 입출력 데이터 양식을 확인해야함.

데이터 양식 정리

Event API

const eventSchema = new Schema(
  {
    title: { type: String },
    startTime: {
      type: Date,
      required: true,
    },
    endTime: {
      type: Date,
      required: true,
    },
    creator: { type: mongoose.Types.ObjectId, ref: "User" },
    calendar: { type: mongoose.Types.ObjectId, ref: "Calendar" },
  },
  { timestamps: true }
);

FullCalendar

  • id: String. event의 고유 식별자.
  • start: Date object. 이벤트의 시작. 현재의 timezone에 따름.
  • end: Date object. 이벤트의 끝. 현재의 timezone에 따름. null 가능.
  • backgroudColor: String. CSS color format 사용 가능. #f00, #ff0000, rgb(255,0,0), or red.
  • borderColor: String. CSS color format 사용 가능.
  • textColor: String. CSS color format 사용 가능.

react-calendar-timeline

item object 와 group object 가 존재함.
각 객체의 key를 따로 정의할 수 있음.

{
  groupIdKey: 'id',
  groupTitleKey: 'title',
  groupRightTitleKey: 'rightTitle',
  itemIdKey: 'id',
  itemTitleKey: 'title',    // key for item div content
  itemDivTitleKey: 'title', // key for item div title (<div title="text"/>)
  itemGroupKey: 'group',
  itemTimeStartKey: 'start_time',
  itemTimeEndKey: 'end_time',
}

react-timezone-select 사용 시 @emotion/react 경고 발생

해결책

  1. JoinCalendar에서 react-timezone-select 제거
  2. 근본적인 원인 파악 후 대응

현상

프론트 쪽에서 아래와 같은 경고 메시지 발생.
정확한 원인은 불명.
다만 react-timezone-select 를 제거하면 경고가 사라지는 것을 확인.

경고 메시지

You are loading @emotion/react when it is already loaded. 
Running multiple instances may cause problems. 
This can happen if multiple versions are used, 
or if multiple builds of the same version are used.
emotion-react.esm.js:389

에러 내용

1 2
  ./node_modules/react-timezone-select/dist/esm/index.js @ emotion-react.esm.js:389
options.factory @ react refresh:6
webpack_require @ bootstrap:24
fn @ hot module replacement:61
./src/calendars/pages/JoinCalendar.js @ EditEvents.js:130
options.factory @ react refresh:6
webpack_require @ bootstrap:24
fn @ hot module replacement:61
./src/App.js @ interopRequireDefault.js:7
options.factory @ react refresh:6
webpack_require @ bootstrap:24
fn @ hot module replacement:61
./src/index.js @ JoinCalendar.js:106
options.factory @ react refresh:6
webpack_require @ bootstrap:24
  (익명) @ startup:7
  (익명) @ startup:7

회원가입 유효성 검사 추가

PullRequest #60 관련

회원가입 페이지 유효성 검사 추가

  • 올바른 email 형식인지
  • 입력받은 두개의 패스워드가 서로 같은지
  • 위 두 검사를 통과하지 못할 경우 Sign up 비활성화

비동기로 만들 것(onChange사용)

EditCalendars의 changeOwner 기능에서 userId 가 필요.

현상

EditCalendars의 changeOwner기능 관련.
deleteUserFromCalendar API의 파라미터로 user id를 받고 있음.
현재 클라이언트에서는 user id를 저장하지 않고 있기 때문에 파라미터로 넘겨주는 것이 불가능.

해결책

서버 쪽에서 쿠키 사용하는 편이 낫지 않을까 합니다.
다른 의견이나 의도하신 바 있으면 얘기해주세요.

Timezone 정보를 쿠키에 저장하기

현재

  • API 요청 시 URL에 timezone 정보를 담을 것을 전제로 하고 있음

향후

  • 쿠키에 timezone 정보를 담음으로써...
    • API URL의 길이를 줄일 수 있음 -> 실수로 인한 error 감소
    • 반복되는 코드를 줄일 수 있음

적용 방법

  • 클라이언트 쪽의 timezone이 필요하기 때문에, 쿠키 설정은 frontend 쪽에서 행함.
  • 쿠키 생성 시점은 로그인 시
  • 사용하는 library는 moment.tz
  • 아래를 사용하면 timezone을 구할 수 있다.
    moment.tz.guess() // Asia/Seoul
  • 쿠키에 timezone 정보 저장시, 이하의 인코딩이 필요함
    encodeURIComponent("Asia/Seoul");
  • 쿠키의 만료기간은 14일
    (향후 적용될 Refresh token과 기간을 같게 함, refresh token 갱신 시 timezone 쿠키도 서버에서 갱신)

react-calendar-timeline가 react-admin의 레이아웃 위에서 정상적으로 동작하지 않음

현상

  • react-calendar-timeline(이하 timeline)이 상단 메뉴바와 좌측 메뉴바를 제외한 최상위 컨테이너의 영역을 벗어남
  • 가로축 드래그가 동작하지 않음(대신 가로 스크롤 바가 생김, 의도하지 않은 영역도 표시함)

해결책

  • 다른 라이브러리의 사용? (big-calendar-timeline)
  • timeline을 react-admin의 noLayout 영역에 표시하기
  • 올바른 적용 방법 찾아보기

고민

  • 본 프로젝트의 가장 핵심적인 기능이기 때문에, 제대로 만들고 싶음

[PR #32] <MenuItemLink>의 leftIcon 속성 관련 버그

현상

#32
<MenuItemLink>leftIcon 속성에는 <svgIcon>만 사용 가능.

현재 <MenuItemLink>로 Calendar의 메뉴를 구성하고 있는데,
leftIcon<Avartar>를 설정할 시, 아래의 에러 내용이 표시됨.
화면 표시에는 문제가 없어보이나, 향후 버그를 일으킬 가능성 존재.

참고
marmelab/react-admin#1926

에러 내용

bundle.js:134227 Warning: React does not recognize the `titleAccess` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `titleaccess` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at Avatar (http://localhost:3000/static/js/bundle.js:31710:82)
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at ListItemIcon (http://localhost:3000/static/js/bundle.js:46031:82)
    at a
    at LinkWithRef (http://localhost:3000/static/js/bundle.js:172546:5)
    at http://localhost:3000/static/js/bundle.js:5248:66
    at ButtonBase (http://localhost:3000/static/js/bundle.js:33041:82)
    at http://localhost:3000/static/js/bundle.js:5248:66
    at MenuItem (http://localhost:3000/static/js/bundle.js:47216:83)
    at http://localhost:3000/static/js/bundle.js:5248:66
    at http://localhost:3000/static/js/bundle.js:122150:16
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at Transition (http://localhost:3000/static/js/bundle.js:174334:30)
    at Collapse (http://localhost:3000/static/js/bundle.js:36174:82)
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at Menu (http://localhost:3000/static/js/bundle.js:122574:67)
    at div
    at MyMenu (http://localhost:3000/static/js/bundle.js:2813:74)
    at div
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at Paper (http://localhost:3000/static/js/bundle.js:48973:82)
    at http://localhost:3000/static/js/bundle.js:5248:66
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at Drawer (http://localhost:3000/static/js/bundle.js:38448:83)
    at http://localhost:3000/static/js/bundle.js:5248:66
    at Sidebar (http://localhost:3000/static/js/bundle.js:122458:15)
    at main
    at div
    at div
    at http://localhost:3000/static/js/bundle.js:5248:66
    at Layout (http://localhost:3000/static/js/bundle.js:122751:13)
    at MyLayout
    at div
    at Routes (http://localhost:3000/static/js/bundle.js:173701:5)
    at CoreAdminRouter (http://localhost:3000/static/js/bundle.js:114499:11)
    at Routes (http://localhost:3000/static/js/bundle.js:173701:5)
    at CoreAdminUI (http://localhost:3000/static/js/bundle.js:114564:15)
    at AdminUI
    at Router (http://localhost:3000/static/js/bundle.js:173634:15)
    at HistoryRouter (http://localhost:3000/static/js/bundle.js:112316:15)
    at TranslationProvider (http://localhost:3000/static/js/bundle.js:114289:19)
    at QueryClientProvider (http://localhost:3000/static/js/bundle.js:169191:21)
    at Provider (http://localhost:3000/static/js/bundle.js:169884:20)
    at CoreAdminContext (http://localhost:3000/static/js/bundle.js:114310:19)
    at InnerThemeProvider (http://localhost:3000/static/js/bundle.js:66153:70)
    at ThemeProvider (http://localhost:3000/static/js/bundle.js:64996:5)
    at ThemeProvider (http://localhost:3000/static/js/bundle.js:66173:5)
    at ThemeProvider (http://localhost:3000/static/js/bundle.js:123094:15)
    at AdminContext (http://localhost:3000/static/js/bundle.js:132897:12)
    at Admin (http://localhost:3000/static/js/bundle.js:132921:16)
    at App
    at AuthContextProvider (http://localhost:3000/static/js/bundle.js:3241:70)

모바일 화면: 좌측 메뉴 모달에서 메뉴 클릭시 모달이 닫히지 않음

현상

모바일 화면 상태에서, 좌측 메뉴 모달의 메뉴를 클릭 시 모달이 닫히지 않음
원래는 메뉴 클릭 시 모달이 닫혀야함.

해결책

이하의 공식문서를 참조하여 메뉴(MyMenu) 코드를 수정할 것
(현재는 MUI의 List를 이용해 구성되어 있음)
https://marmelab.com/react-admin/doc/4.0/Theming.html#using-a-custom-menu

export const Menu = (props) => (
    <Menu {...props}>
        <DashboardMenuItem />
        <MenuItemLink to="/posts" primaryText="Posts" leftIcon={<BookIcon />}/>
        <MenuItemLink to="/comments" primaryText="Comments" leftIcon={<ChatBubbleIcon />}/>
        <MenuItemLink to="/users" primaryText="Users" leftIcon={<PeopleIcon />}/>
        <MenuItemLink to="/custom-route" primaryText="Miscellaneous" leftIcon={<LabelIcon />}/>
    </Menu>
);```

아이디, 닉네임, 롤을 일반 쿠키로 저장할 필요성에 대해

클라이언트 쪽에서도 아이디나 닉네임은 사용 빈도가 높은데(화면 표시용) 매번 서버에서 얻어올 필요가 있을까요?
매번 얻어온다면 상관없지만 그렇지 않다면 아이디와 닉네임은 일반쿠키로 저장 해 놓는 것도 좋을 것 같습니다.

permisson같은 경우에도 Role을 매번 얻어와야하는지 의문입니다. (예를 들어 오너일 경우에만 캘린더 삭제키가 표시된다 거나?)
여러 샘플이나 프로젝트를 찾아본 결과로는 대부분 일반 쿠키에 토큰으로 저장하여 클라이언트쪽에서 디코딩해서 쓰는 것 같습니다.
알고 계신거나 의견있으시면 말씀해주세요

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.