Light Blue Pointer
본문 바로가기
Developing/Journal

[내일배움캠프][팀프로젝트] Trollo (유사 Trello) 개발일지

by Greedy 2023. 12. 27.

 

분석 및 시나리오

사용자

  • 회원가입을 할 수 있다.
  • 로그인할 수 있다.
  • 로그아웃할 수 있다.
  • 회원 탈퇴를 할 수 있다.

초대

  • 다른 사용자를 초대할 수 있다.
  • 초대를 받은 사용자는 초대를 거절/수락할 수 있다.
  • 초대를 거절하면 초대 테이블에서 해당 entity가 삭제된다.
  • 초대를 수락하면 초대 테이블에서 해당 entity가 삭제되고 보드_사용자 테이블에 참여자로 등록된다.

보드

  • 칼럼들의 집합체
  • 보드는 다음과 같은 속성을 갖고 있다.
    • id, 이름, 생성자, 배경 색상, 설명
  • 노션 페이지같은 느낌
  • 사용자가 생성할 수 있다.
  • 생성한 사용자(주인)가 다른 사용자(초대받은 사람)를 초대할 수 있다.
  • 하나의 보드에 여러 명의 사용자가 존재한다.
  • 보드에 속한 사용자들은 보드를 수정/초대할 수 있다.
  • 보드에 속한 사용자들은 나갈 수 있다.
  • 생성자만 보드를 삭제할 수 있다.

컬럼

  • 카드들의 집합체
  • 특정 보드에 속한 사용자만 생성할 수 있다.
  • 컬럼 속성
    • id,이름, 순서
  • 컬럼은 보드에 속한 누구나 생성/수정/삭제가 가능하다.

카드

  • 카드 속성
    • id, 제목, 내용, 칼럼, 색상, 마감일, (체크리스트, 작업자 리스트)
  • 카드는 보드에 속한 누구나 조회/생성/수정/삭제가 가능하다.
    • 조회
      • 해당 보드에 속한 사용자는 해당 보드의 모든 카드를 볼 수 있다.
      • 보드 기준으로 카드를 조회할 수 있다.
      • 칼럼 기준으로 카드를 조회할 수 있다.
        • 칼럼에 속한 카드들은 순서가 정해져있다.
      • 하나의 카드는 제목과 내용, 댓글, 체크리스트, 작업자 목록이 존재한다.
    • 생성
      • 제목과 함께 카드를 생성할 수 있다.
      • 나머지는 빈 내용이다.
      • 위치는 항상 해당 칼럼의 맨 마지막에 생성된다.
    • 수정
      • 내용을 수정할 수 있다.
      • 댓글을 달 수 있다.
        • 하나의 카드에는 여러 개의 댓글이 존재한다.
      • 작업자를 설정해줄 수 있다.
        • 하나의 카드에는 여러 명의 작업자를 정할 수 있다.
      • 보드 내에서 카드를 옮길 수 있다.
        • 특정 카드를 다른 카드의 위 또는 아래로 옮길 수 있다.
          • /api/v1/cards/{cardId}/to/{toCardId}/[above|below]
        • 카드가 없는 빈 칼럼으로 옮길 수 있다.
          • /api/v1/cards/{cardId}/to/columns/{toColumnId}
        • 서도 다른 칼럼으로도 위와 같은 api로 옮길 수 있다.
          • 단, 다른 보드의 칼럼으로는 옮길 수 없다.
    • 삭제
      • 해당 보드에 속한 사용자는 해당 보드의 카드를 삭제할 수 있다.
      • 작성자가 아니여도 삭제할 수 있다.
  • 고급 기능
    • 카드 내에 체크리스트가 존재한다.
    • 체크리스트 생성 URI를 통해 할 일 입력
    • 체크리스트 수정을 통해 입력한 할일의 완료/취소 체크 가능
    • 체크리스트의 진행도가 존재한다.(진행 퍼센트를 응답으로 반환)
    • 첨부 파일을 업/다운로드를 할 수 있다.

알림 기능

  • 카드에 대한 상태변경에 대해 해당 보드의 참여자한테 알림을 보낸다.
    • 카드가 생성/수정/삭제 되었을 때 알림을 보낸다.
    • 카드가 다른 칼럼으로 이동됐을 때도 알람을 보낸다.
    • 카드에 댓글이 달렸을 때 알람을 보낸다.
  • 각 상태변경에 해당하는 메서드가 실행될 때 스프링 이벤트 퍼블리셔는 이벤트를 발행한다.
  • 이벤트 리스너는 이벤트를 받아 이벤트의 정보를 통해 notification과 userNotification을 저장한다.
    • notification은 카드에 변경을 일으킨 당사자의 아이디,해당카드가 속한 보드아이디,변경타입,변경메시지,알림이 저장되는 시간(카드가 변경된 시간)로 구성
    • userNotification은 알림이 생성된시점의 보드 참여자와 알림의 아이디,알림의 상태(UNREAD)로 구성(저장될 때, 한번에 보드 참여자의 수만큼 동일한 아이디의 알림으로 필드가 생성될듯?)
  • 보드의 참여자는 알림을 조회할 수 있다.
  • 조회하면 해당 보드 참여자의 아이디를 지닌 필드의 UNREAD가 READ로 변경
  • 카드가 생성/수정/삭제 되었을 때 알림을 보낸다.

 

API 명세

Domain 기능 method url request response error response
User 회원가입 POST /api/v1/users/signup {
"email" : "
email@dot.com",
"nickname" : "닉2",
"password" : "passpass",
"passwordCheck" : "passpass"
}
{    "status": 201,    "message": "회원가입 성공",    "data": null} {    "status": 400,    "message": "이미 존재하는 이메일입니다.",    "data": null

}
,
{
"status": 400,
"message": "잘못된 입력값",
"data": [
{
"field": "email",
"message": "must be a well-formed email address"
}
]
}
User 로그인 POST /api/v1/users/login {
"email" : "
email@dot.com",
"password" : "passpass"
}
{    "status": 200,    "message": "로그인 성공",    "data": null} {
"status": 400,
"message": "이메일 또는 패스워드를 확인해주세요.",
"data": null
}
User 로그아웃 PUT /api/v1/users/logout   {    "status": 200,    "message": "로그아웃 성공",    "data": null}  
User 마이페이지 GET /api/v1/users/me   {
"status": 200,
"message": "마이페이지 조회 성공",
"data": {
"email": "
email2@dot.com",
"nickname": "닉2",
"myBoards": [
{
"id": 1,
"name": "이름",
"color": "색깔"
},
{
"id": 2,
"name": "이름2",
"color": "색깔2"
}
]
}
}
 
User 회원정보 수정 PUT /api/v1/users/edit {
"nickname" : "minisun4",
"password" : "passpass"
}
{    "status": 200,    "message": "개인정보 업데이트",    "data": null} {    "status": 400,    "message": "비밀번호가 일치하지 않습니다.",    "data": null}
User 비밀번호 수정 PUT /api/v1/users/pw {
"newPassword" : "minisun2",
"newPasswordCheck" : "minisun2",
"password" : "passpass"
}
{    "status": 200,    "message": "비밀번호 업데이트",    "data": null} {    "status": 400,    "message": "비밀번호가 일치하지 않습니다.",    "data": null}
User 회원탈퇴 DELETE /api/v1/users/withdraw   {    "status": 200,    "message": "회원 탈퇴 성공",    "data": null}  
Board 메인페이지 GET /api/v1/boards   {
"status": 200,
"message": "메인 페이지",
"data": [
{
"id": 1,
"name": "이름",
"color": "색깔"
},
{
"id": 2,
"name": "이름2",
"color": "색깔2"
}
]
}
 
Board 보드 생성 POST /api/v1/boards {
"name" : "보드보드",
"color" : "색상색상"
}
   
Board 보드 수정 PUT /api/v1/boards/{boardId} {
"name" : "보드보드",
"color" : "색상색상"
}
   
Board 보드 삭제 DELETE /api/v1/boards/{boardId}      
Section 컬럼 생성 POST /api/v1/sections {
"name" : 칼럼이름"
}
   
Section 컬럼 이름 수정 PUT /api/v1/sections/{sectionId} {
"name" : 칼럼이름"
}
   
Section 컬럼 삭제 DELETE /api/v1/sections/{sectionId}      
Section 컬럼 순서 이동 PUT /api/v1/sections/{sectionId}      
Card 카드 단일 조회 GET /api/v1/cards/{cardId}   {
"status": 200,
"message": "카드 조회",
"data": {
"id": 1,
"title": "123",
"content": null,
"color": null,
"deadline": null,
"checkList": […],
"rate": 33.333336,
"comments": […]
}
}
 
Card 보드 기준 카드 조회 GET /api/v1/boards/{boardId}/cards   [
{
"id": "id",
"title": "title",
"color": "color",
}, …
]
 
Card 칼럼 기준 카드 조회 GET /api/v1/sections/{sectionId}/cards   [
{
"id": "id",
"title": "title",
"color": "color",
}, …
]
 
Card 카드 생성 POST /api/v1/boards/{boardId}/sections/{sectionId}/cards {
"title": "제목"
}
{    "status": 201,    "message": "카드 생성",    "data": null}  
Card 카드 수정 PUT /api/v1/cards/{cardId} {
"title": "제목2",
"content": "내용2",
"color": "색상2",
"deadline": "2024-01-02T16:08:22.256Z"
}
{    "status": 200,    "message": "카드 수정",    "data": null}  
Card 카드 이동 PUT /api/v1/cards/{fromCardId}/to/{toCardId}/[previous|next]   {    "status": 200,    "message": "카드 위치 변경",    "data": null}  
Card 카드 이동(빈 칼럼으로 이동) PUT /api/v1/cards/{cardId}/to/sections/{toSectionId}   {    "status": 200,    "message": "카드 위치 변경",    "data": null}  
Card 카드 삭제 DELETE /api/v1/cards/{cardId}      
Card 카드 작업자 추가 POST /api/v1/cards/{cardId}/workers      
Card 카드 작업자 삭제 DELETE /api/v1/cards/{cardId}/workers/{workerId}      
CheckList 체크리스트 생성 POST /api/v1/cards/{cardId}/checklist {
”description”:”1번째 할일”
}
   
CheckList 체크리스트 수정 PUT /api/v1/cards/{cardId}/checklist {
”checkSign”:”true”
}
{
”checkSign”:”false”
}
   
CheckList 체크리스트 삭제 DELETE /api/v1/cards/{cardId}/checklist      
File 첨부파일 생성 POST /api/v1/cards/{cardId}      
File 첨부파일 수정 PUT /api/v1/cards/{cardId}      
File 첨부파일 삭제 DELETE /api/v1/cards/{cardId}      
Invitation 보드에 초대 POST /api/v1/boards/{boardId}/invite/{userId}   {    "status": 201,    "message": "successfully invited user",    "data": null} {    "status": 400,    "message": "이미 초대된 사용자입니다.",    "data": null}
Invitation 보드에 초대 취소 DELETE /api/v1/boards/{boardId}/cancel/{userId}   {    "status": 200,    "message": "초대 취소 성공",    "data": null} {    "status": 404,    "message": "초대가 존재하지 않습니다.",    "data": null}
Invitation 초대 목록 조회 GET /api/v1/invitations   {
"status": 200,
"message": "내가 받은/보낸 초대 조회 성공",
"data": {
"receivedInvitations": [
{
"boardId": 1,
"boardname": "보드이름",
"senderId": 1,
"senderNick": "닉2"
}
],
"sentInvitations": [
{
"boardId": 2,
"boardname": "보드이름",
"receiverId": 1,
"receiverNick": "닉2"
}
]
}
}
 
Invitation 초대 거절 PUT /api/v1/boards/{boardId}/reject   {
"status": 200,
"message": "초대 거절 성공",   "data":
null}
{    "status": 404,    "message": "초대가 존재하지 않습니다.",    "data": null}
Invitation 초대 수락 PUT /api/v1/boards/{boardId}/approve   {
"status": 200,
"message": "초대 수락 성공",
"data": {
"email": "
email@dot.com",
"boardId": 1,
"role": "PARTICIPANT"
}
}
{    "status": 404,    "message": "초대가 존재하지 않습니다.",    "data": null}
Comment 댓글 작성 POST /api/v1/cards/{cardId}/comments {    "content":"도대체 무슨 오류야--??"} {    "status": 201,    "message": "save_comment",    "data": null}  
Comment 댓글 수정 PUT /api/v1/comments/{commentId} {    "content":"도대체 무슨 오류임?"} {    "status": 200,    "message": "update_comment",    "data": null}  
Comment 댓글 삭제 DELETE /api/v1/comments/{commentId}   {    "status": 200,    "message": "delete_comment",    "data": null}  
Event 이벤트 조회 GET /api/v1/notification/{boardId}   "status": 200,
"message": "알림 조회",
"data": [
{
"fieldName": "CREATED",
"fieldContent": "user1 회원에 의해 string2 BOARD에서 카드가 생성되었습니다.",
"createdAt": "2024-01-03T14:11:13.24057"
},
{
"fieldName": "UPDATED",
"fieldContent": "user1 회원에 의해 string2 BOARD에서 카드가 수정되었습니다.",
"createdAt": "2024-01-03T14:12:43.226851"
},
{
"fieldName": "DELETED",
"fieldContent": "user1 회원에 의해 string2 BOARD에서 카드가 삭제되었습니다.",
"createdAt": "2024-01-03T14:12:51.445727"
},
{
"fieldName": "ADD_COMMENTS",
"fieldContent": "user1 회원에 의해 string2 BOARD에서 카드에 댓글이 작성되었습니다.",
"createdAt": "2024-01-03T14:13:02.103208"
}
]
}
 

 

 

나는 User랑 Invitaion을 맡았다!

 

 

ERD

 

 

 

와이어프레임

 

설계하면서 생각한 점 :

 

 

프로젝트를 통해 배운 점 :

 

User domain 개발일지

 

Invitation domain 개발일지