NBE6-8-2-Team03 ์ฌ์ด๋ณด์ด์ฆ
TodoDuk์ ๊ฐ์ธ ๋ฐ ํ ํ ์ผ ๊ด๋ฆฌ๋ฅผ ์ํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. Spring Boot๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ REST API ๋ฐฑ์๋๋ก ๊ตฌ์ฑ๋์ด ์์ผ๋ฉฐ, ํ ์ผ ๊ด๋ฆฌ, ํ ํ์ , ๋ผ๋ฒจ๋ง, ์๋ฆผ ๋ฑ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- Backend: Spring Boot 3.5.4, JPA/Hibernate, Spring Security
- Database: H2 (๊ฐ๋ฐํ๊ฒฝ)
- Authentication: JWT + API Key
- Scheduler: Quartz
- API Documentation: Swagger/OpenAPI 3
- Framework: Spring Boot 3.5.3
- Language: Java 21
- Database: H2 (๊ฐ๋ฐ), MySQL (์ด์ ์ง์)
- Cache: Redis (ํ ํฐ ์ ์ฅ์)
- Security: Spring Security + JWT
- Documentation: SpringDoc OpenAPI 3.x (Swagger)
- Build Tool: Gradle 8.14.3 (Kotlin DSL)
- Framework: Next.js 15.4.1
- Language: TypeScript
- Styling: Tailwind CSS 4.0
- State Management: Zustand
- HTTP Client: Axios
- UI Components: Radix UI, Lucide React
- Dev Tools: ESLint, Prettier
- CI/CD: GitHub Actions
- API Generation: swagger-typescript-api
- Development: Docker (Redis)
graph TB
subgraph "Client Layer"
WEB[Web Browser/Frontend]
end
subgraph "API Gateway"
CORS[CORS Handler]
AUTH[Authentication Filter]
CTRL[Spring Controllers]
end
subgraph "Business Logic Layer"
US[User Service]
TS[Team Service]
TMS[TeamMember Service]
TLS[TodoList Service]
TOS[Todo Service]
LS[Label Service]
TLS2[TodoLabel Service]
RS[Reminder Service]
NS[Notification Service]
end
subgraph "Data Access Layer"
UR[User Repository]
TR[Team Repository]
TMR[TeamMember Repository]
TLR[TodoList Repository]
TOR[Todo Repository]
LR[Label Repository]
TLSR[TodoLabel Repository]
RR[Reminder Repository]
NR[Notification Repository]
TAR[TodoAssignment Repository]
end
subgraph "External Systems"
QUARTZ[Quartz Scheduler]
JWT[JWT Token Service]
FILE[File Upload Service]
end
subgraph "Database"
H2[(H2 Database)]
end
WEB --> CORS
CORS --> AUTH
AUTH --> CTRL
CTRL --> US
CTRL --> TS
CTRL --> TMS
CTRL --> TLS
CTRL --> TOS
CTRL --> LS
CTRL --> TLS2
CTRL --> RS
CTRL --> NS
US --> UR
TS --> TR
TMS --> TMR
TLS --> TLR
TOS --> TOR
LS --> LR
TLS2 --> TLSR
RS --> RR
NS --> NR
TS --> TAR
UR --> H2
TR --> H2
TMR --> H2
TLR --> H2
TOR --> H2
LR --> H2
TLSR --> H2
RR --> H2
NR --> H2
TAR --> H2
RS --> QUARTZ
US --> JWT
US --> FILE
erDiagram
Users ||--o{ TodoLists : has
Users ||--o{ TeamMembers : belongs_to
Users ||--o{ Labels : owns
Users ||--o{ Notifications : receives
Teams ||--o{ TeamMembers : has
Teams ||--o{ TodoLists : contains
Teams ||--o{ TodoAssignments : manages
TodoLists ||--o{ Todos : contains
Todos ||--o{ TodoLabels : has
Todos ||--o{ Reminders : scheduled
Todos ||--o{ TodoAssignments : assigned_to
Labels ||--o{ TodoLabels : applied_to
Users {
int id PK
string userEmail UK
string password
string nickName
boolean isAdmin
string profileImgUrl
string apiKey UK
datetime createDate
datetime modifyDate
}
Teams {
int id PK
string teamName
string description
datetime createDate
datetime modifyDate
}
TeamMembers {
int id PK
int user_id FK
int team_id FK
enum role
datetime joinedAt
datetime createDate
datetime modifyDate
}
TodoLists {
int id PK
string name
string description
int user_id FK
int team_id FK
datetime createDate
datetime modifyDate
}
Todos {
int id PK
string title
string description
boolean isCompleted
int priority
datetime startDate
datetime dueDate
int todoList_id FK
datetime createDate
datetime modifyDate
}
Labels {
int id PK
string name
string color
datetime createDate
datetime modifyDate
}
TodoLabels {
int id PK
int todo_id FK
int label_id FK
datetime createDate
datetime modifyDate
}
Reminders {
int id PK
int todo_id FK
datetime remindAt
string method
datetime createDate
datetime modifyDate
}
Notifications {
int id PK
int user_id FK
string title
string description
string url
boolean isRead
datetime createDate
datetime modifyDate
}
TodoAssignments {
int id PK
int todo_id FK
int assigned_user_id FK
int team_id FK
datetime assignedAt
enum status
datetime createDate
datetime modifyDate
}
flowchart TD
START([์์]) --> LOGIN{๋ก๊ทธ์ธ ์์ฒญ}
LOGIN -->|ํ์๊ฐ์
| REGISTER[ํ์๊ฐ์
์ฒ๋ฆฌ]
LOGIN -->|๋ก๊ทธ์ธ| AUTH[์ธ์ฆ ์ฒ๋ฆฌ]
REGISTER --> SAVE_USER[์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ]
SAVE_USER --> GEN_API[API Key ์์ฑ]
GEN_API --> SUCCESS_REG[ํ์๊ฐ์
์ฑ๊ณต]
AUTH --> CHECK_USER{์ฌ์ฉ์ ์กด์ฌ ํ์ธ}
CHECK_USER -->|์์| FAIL[๋ก๊ทธ์ธ ์คํจ]
CHECK_USER -->|์กด์ฌ| CHECK_PWD{๋น๋ฐ๋ฒํธ ํ์ธ}
CHECK_PWD -->|ํ๋ฆผ| FAIL
CHECK_PWD -->|๋ง์| GEN_TOKEN[Access Token ์์ฑ]
GEN_TOKEN --> SET_COOKIE[์ฟ ํค ์ค์ ]
SET_COOKIE --> SUCCESS_LOGIN[๋ก๊ทธ์ธ ์ฑ๊ณต]
SUCCESS_REG --> END([์ข
๋ฃ])
SUCCESS_LOGIN --> END
FAIL --> END
flowchart TD
START([Todo ๊ด๋ฆฌ ์์]) --> ACTION{์ก์
์ ํ}
ACTION -->|Todo ์์ฑ| CREATE_TODO[Todo ์์ฑ]
ACTION -->|Todo ์์ | UPDATE_TODO[Todo ์์ ]
ACTION -->|Todo ์ญ์ | DELETE_TODO[Todo ์ญ์ ]
ACTION -->|์๋ฃ ์ฒ๋ฆฌ| TOGGLE_TODO[์๋ฃ ์ํ ํ ๊ธ]
ACTION -->|๋ด๋น์ ์ง์ | ASSIGN_TODO[๋ด๋น์ ์ง์ ]
CREATE_TODO --> GET_TODOLIST{TodoList ํ์ธ}
GET_TODOLIST -->|์์| CREATE_TODOLIST[TodoList ์์ฑ]
GET_TODOLIST -->|์์| SAVE_TODO[Todo ์ ์ฅ]
CREATE_TODOLIST --> SAVE_TODO
SAVE_TODO --> SUCCESS1[Todo ์์ฑ ์ฑ๊ณต]
UPDATE_TODO --> FIND_TODO{Todo ์กด์ฌ ํ์ธ}
FIND_TODO -->|์์| NOT_FOUND[Todo ์์]
FIND_TODO -->|์์| CHECK_PERMISSION{์์ ๊ถํ ํ์ธ}
CHECK_PERMISSION -->|๊ถํ ์์| PERM_FAIL[๊ถํ ์คํจ]
CHECK_PERMISSION -->|๊ถํ ์์| UPDATE_DATA[Todo ๋ฐ์ดํฐ ์
๋ฐ์ดํธ]
UPDATE_DATA --> SUCCESS2[Todo ์์ ์ฑ๊ณต]
DELETE_TODO --> FIND_TODO2{Todo ์กด์ฌ ํ์ธ}
FIND_TODO2 -->|์์| NOT_FOUND
FIND_TODO2 -->|์์| CHECK_DELETE_PERM{์ญ์ ๊ถํ ํ์ธ}
CHECK_DELETE_PERM -->|๊ถํ ์์| PERM_FAIL
CHECK_DELETE_PERM -->|๊ถํ ์์| DELETE_LABELS[์ฐ๊ด ๋ผ๋ฒจ ์ญ์ ]
DELETE_LABELS --> DELETE_ASSIGNMENTS[๋ด๋น์ ์ ๋ณด ์ญ์ ]
DELETE_ASSIGNMENTS --> DELETE_TODO_DATA[Todo ๋ฐ์ดํฐ ์ญ์ ]
DELETE_TODO_DATA --> SUCCESS3[Todo ์ญ์ ์ฑ๊ณต]
ASSIGN_TODO --> CHECK_TEAM_MEMBER{ํ ๋ฉค๋ฒ ํ์ธ}
CHECK_TEAM_MEMBER -->|์๋| TEAM_FAIL[ํ ๋ฉค๋ฒ ์๋]
CHECK_TEAM_MEMBER -->|๋ง์| CREATE_ASSIGNMENT[๋ด๋น์ ์ง์ ]
CREATE_ASSIGNMENT --> SUCCESS4[๋ด๋น์ ์ง์ ์ฑ๊ณต]
SUCCESS1 --> END([์ข
๋ฃ])
SUCCESS2 --> END
SUCCESS3 --> END
SUCCESS4 --> END
NOT_FOUND --> END
PERM_FAIL --> END
TEAM_FAIL --> END
flowchart TD
START([ํ ๊ด๋ฆฌ ์์]) --> AUTH_CHECK{์ธ์ฆ ํ์ธ}
AUTH_CHECK -->|์คํจ| AUTH_FAIL[์ธ์ฆ ์คํจ]
AUTH_CHECK -->|์ฑ๊ณต| ACTION{์ก์
์ ํ}
ACTION -->|ํ ์์ฑ| CREATE_TEAM[ํ ์์ฑ]
ACTION -->|ํ ์์ | MODIFY_TEAM[ํ ์ ๋ณด ์์ ]
ACTION -->|๋ฉค๋ฒ ๊ด๋ฆฌ| MEMBER_MGMT[๋ฉค๋ฒ ๊ด๋ฆฌ]
ACTION -->|ํ ์ญ์ | DELETE_TEAM[ํ ์ญ์ ]
CREATE_TEAM --> SAVE_TEAM[ํ ์ ๋ณด ์ ์ฅ]
SAVE_TEAM --> CREATE_LEADER[์์ฑ์๋ฅผ ๋ฆฌ๋๋ก ์ถ๊ฐ]
CREATE_LEADER --> SUCCESS1[ํ ์์ฑ ์ฑ๊ณต]
MODIFY_TEAM --> CHECK_LEADER{๋ฆฌ๋ ๊ถํ ํ์ธ}
CHECK_LEADER -->|๊ถํ ์์| PERM_FAIL[๊ถํ ์คํจ]
CHECK_LEADER -->|๊ถํ ์์| UPDATE_TEAM[ํ ์ ๋ณด ์
๋ฐ์ดํธ]
UPDATE_TEAM --> SUCCESS2[์์ ์ฑ๊ณต]
MEMBER_MGMT --> MEMBER_ACTION{๋ฉค๋ฒ ์ก์
}
MEMBER_ACTION -->|๋ฉค๋ฒ ์ถ๊ฐ| ADD_MEMBER[๋ฉค๋ฒ ์ถ๊ฐ]
MEMBER_ACTION -->|์ญํ ๋ณ๊ฒฝ| CHANGE_ROLE[์ญํ ๋ณ๊ฒฝ]
MEMBER_ACTION -->|๋ฉค๋ฒ ์ ๊ฑฐ| REMOVE_MEMBER[๋ฉค๋ฒ ์ ๊ฑฐ]
ADD_MEMBER --> CHECK_EMAIL{์ด๋ฉ์ผ ์กด์ฌ ํ์ธ}
CHECK_EMAIL -->|์์| EMAIL_FAIL[์ฌ์ฉ์ ์์]
CHECK_EMAIL -->|์์| ADD_TO_TEAM[ํ์ ์ถ๊ฐ]
ADD_TO_TEAM --> SUCCESS3[๋ฉค๋ฒ ์ถ๊ฐ ์ฑ๊ณต]
DELETE_TEAM --> CHECK_DELETE_AUTH{์ญ์ ๊ถํ ํ์ธ}
CHECK_DELETE_AUTH -->|๊ถํ ์์| PERM_FAIL
CHECK_DELETE_AUTH -->|๊ถํ ์์| REMOVE_ASSIGNMENTS[๋ด๋น์ ์ ๋ณด ์ญ์ ]
REMOVE_ASSIGNMENTS --> REMOVE_TODOLISTS[ํ ํ ์ผ๋ชฉ๋ก ์ญ์ ]
REMOVE_TODOLISTS --> REMOVE_TEAM_DATA[ํ ๋ฐ์ดํฐ ์ญ์ ]
REMOVE_TEAM_DATA --> SUCCESS4[ํ ์ญ์ ์ฑ๊ณต]
SUCCESS1 --> END([์ข
๋ฃ])
SUCCESS2 --> END
SUCCESS3 --> END
SUCCESS4 --> END
AUTH_FAIL --> END
PERM_FAIL --> END
EMAIL_FAIL --> END
graph LR
subgraph "Actors"
U[User]
TL[Team Leader]
TM[Team Member]
SYS[System]
end
subgraph "Authentication & User Management"
UC1[Register Account]
UC2[Login/Logout]
UC3[View Profile]
UC4[Update Profile]
UC5[Upload Profile Image]
end
subgraph "Todo Management"
UC6[Create Todo]
UC7[Update Todo]
UC8[Delete Todo]
UC9[Mark Complete]
UC10[View Todos]
UC11[Filter Todos]
end
subgraph "Todo List Management"
UC12[Create Todo List]
UC13[Update Todo List]
UC14[Delete Todo List]
UC15[View Todo Lists]
end
subgraph "Label Management"
UC16[Create Label]
UC17[Apply Labels to Todo]
UC18[Remove Labels]
UC19[View Labels]
end
subgraph "Team Management"
UC20[Create Team]
UC21[Update Team Info]
UC22[Delete Team]
UC23[View Team Details]
UC24[Add Team Member]
UC25[Remove Team Member]
UC26[Change Member Role]
UC27[View Team Stats]
end
subgraph "Team Todo Management"
UC28[Create Team Todo]
UC29[Assign Todo to Member]
UC30[Unassign Todo]
UC31[View Team Todos]
UC32[Track Assignment History]
end
subgraph "Reminder & Notification"
UC33[Create Reminder]
UC34[Delete Reminder]
UC35[View Reminders]
UC36[Receive Notifications]
UC37[Mark Notification Read]
UC38[Schedule Reminder Job]
end
%% User relationships
U --> UC1
U --> UC2
U --> UC3
U --> UC4
U --> UC5
U --> UC6
U --> UC7
U --> UC8
U --> UC9
U --> UC10
U --> UC11
U --> UC12
U --> UC13
U --> UC14
U --> UC15
U --> UC16
U --> UC17
U --> UC18
U --> UC19
U --> UC33
U --> UC34
U --> UC35
U --> UC36
U --> UC37
%% Team Leader relationships
TL --> UC20
TL --> UC21
TL --> UC22
TL --> UC24
TL --> UC25
TL --> UC26
%% Team Member relationships
TM --> UC23
TM --> UC27
TM --> UC28
TM --> UC29
TM --> UC30
TM --> UC31
TM --> UC32
%% System relationships
SYS --> UC38
flowchart TD
REQUEST[ํด๋ผ์ด์ธํธ ์์ฒญ] --> CORS_CHECK[CORS ๊ฒ์ฆ]
CORS_CHECK --> AUTH_FILTER[์ธ์ฆ ํํฐ]
AUTH_FILTER --> PERMIT_CHECK{์ธ์ฆ ๋ถํ์ ๊ฒฝ๋ก?}
PERMIT_CHECK -->|Yes| CONTROLLER[์ปจํธ๋กค๋ฌ ์คํ]
PERMIT_CHECK -->|No| TOKEN_CHECK[ํ ํฐ ํ์ธ]
TOKEN_CHECK --> HEADER_CHECK{Authorization ํค๋?}
HEADER_CHECK -->|Yes| EXTRACT_HEADER[ํค๋์์ ํ ํฐ ์ถ์ถ]
HEADER_CHECK -->|No| COOKIE_CHECK[์ฟ ํค์์ ํ ํฐ ์ถ์ถ]
EXTRACT_HEADER --> VALIDATE_TOKEN{ํ ํฐ ์ ํจ์ฑ ๊ฒ์ฆ}
COOKIE_CHECK --> VALIDATE_TOKEN
VALIDATE_TOKEN -->|Valid AccessToken| SET_AUTH[Security Context ์ค์ ]
VALIDATE_TOKEN -->|Invalid AccessToken| API_KEY_CHECK[API Key๋ก ์ฌ์ฉ์ ์กฐํ]
VALIDATE_TOKEN -->|No Token| UNAUTHORIZED[์ธ์ฆ ์คํจ]
API_KEY_CHECK -->|Found| GENERATE_NEW[์ AccessToken ์์ฑ]
API_KEY_CHECK -->|Not Found| UNAUTHORIZED
GENERATE_NEW --> SET_COOKIE[์ฟ ํค ์ค์ ]
SET_COOKIE --> SET_AUTH
SET_AUTH --> CONTROLLER
UNAUTHORIZED --> ERROR_RESPONSE[401 ์๋ฌ ์๋ต]
CONTROLLER --> RESPONSE[์๋ต ๋ฐํ]
- ํ ์์ฑ: ์ฌ์ฉ์๊ฐ ํ์ ์์ฑํ๋ฉด ์๋์ผ๋ก ๋ฆฌ๋ ๊ถํ ๋ถ์ฌ
- ๋ฉค๋ฒ ์ด๋: ๋ฆฌ๋๋ง ์๋ก์ด ๋ฉค๋ฒ ์ถ๊ฐ ๊ฐ๋ฅ (์ด๋ฉ์ผ ๊ธฐ๋ฐ)
- ๊ถํ ๊ด๋ฆฌ: ๋ฆฌ๋๋ ๋ฉค๋ฒ ์ญํ ๋ณ๊ฒฝ ๋ฐ ์ ๊ฑฐ ๊ฐ๋ฅ
- ํ ์ญ์ : ๋ง์ง๋ง ๋ฆฌ๋๋ ์ ๊ฑฐ ๋ถ๊ฐ, ํ ์ญ์ ์ ๊ด๋ จ ๋ฐ์ดํฐ ์ฐ์ ์ญ์
- ๊ฐ์ธ ํ ์ผ: ์ฌ์ฉ์ ๊ฐ๋ณ ๊ด๋ฆฌ
- ํ ํ ์ผ: ํ ๋ฉค๋ฒ๋ง ์์ฑ/์์ ๊ฐ๋ฅ
- ํ ์ผ ํ ๋น: ํ ๋ฉค๋ฒ๋ฅผ ํ ์ผ์ ๋ด๋น์๋ก ์ง์
- ํ ๋น ๊ธฐ๋ก: ๋ชจ๋ ํ ๋น ๋ณ๊ฒฝ์ฌํญ ์ถ์ ๋ฐ ์ด๋ ฅ ๊ด๋ฆฌ
- ๋ฆฌ๋ง์ธ๋ ์ค์ : ํ ์ผ์ ๋ํ ์๊ฐ ๊ธฐ๋ฐ ์๋ฆผ ์ค์
- ์ค์ผ์ค๋ง: Quartz๋ฅผ ํตํ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ ์คํ
- ์๋ฆผ ์์ฑ: ์์ ๋ ์๊ฐ์ ์๋ฆผ ์๋ ์์ฑ
- ์๋ฆผ ๊ด๋ฆฌ: ์ฌ์ฉ์๋ณ ์๋ฆผ ์กฐํ ๋ฐ ์ฝ์ ์ฒ๋ฆฌ
- ์ฌ์ฉ์ ์ธ์ฆ: JWT + API Key ๊ธฐ๋ฐ ๋ณด์ ์์คํ
- ๊ฐ์ธ ํ ์ผ ๊ด๋ฆฌ: CRUD, ์ฐ์ ์์, ๋ง๊ฐ์ผ, ์๋ฃ ์ํ ๊ด๋ฆฌ
- ํ ํ์ : ํ ์์ฑ, ๋ฉค๋ฒ ๊ด๋ฆฌ, ์ญํ ๊ธฐ๋ฐ ๊ถํ ์ ์ด
- ํ ํ ์ผ ๊ด๋ฆฌ: ํ์ ๊ฐ ํ ์ผ ๊ณต์ ๋ฐ ๋ด๋น์ ์ง์
- ๋ผ๋ฒจ๋ง: ์์ ๊ธฐ๋ฐ ๋ผ๋ฒจ๋ก ํ ์ผ ๋ถ๋ฅ
- ๋ฆฌ๋ง์ธ๋: ์๊ฐ ๊ธฐ๋ฐ ์๋ฆผ ์ค์ผ์ค๋ง
- ํ์ผ ์ ๋ก๋: ํ๋กํ ์ด๋ฏธ์ง ๊ด๋ฆฌ
- RESTful API: ํ์ค REST ์ํคํ ์ฒ
- ํธ๋์ญ์ ๊ด๋ฆฌ: Spring์ ์ ์ธ์ ํธ๋์ญ์
- ์์ธ ์ฒ๋ฆฌ: ์ ์ญ ์์ธ ์ฒ๋ฆฌ๊ธฐ๋ก ์ผ๊ด๋ ์ค๋ฅ ์๋ต
- ๋ฐ์ดํฐ ๊ฒ์ฆ: Bean Validation์ ํตํ ์ ๋ ฅ ๋ฐ์ดํฐ ๊ฒ์ฆ
- CORS ์ง์: ํ๋ก ํธ์๋์์ ์์ ํ ํต์
- API ๋ฌธ์ํ: Swagger/OpenAPI 3 ์๋ ๋ฌธ์ ์์ฑ
ํ๊ทธ ์ข ๋ฅ
feature
: ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐ (feature)fix
: ๋ฒ๊ทธ ์์ chore
: ์ฝ๋ ๋ณ๊ฒฝ์ด ์๋ ๋น๋, ์ค์ , ๋ฌธ์ ์์ ๋ฑ ์ก์ผ์ฑ ์์docs
: ๋ฌธ์ ์์ style
: ์ฝ๋ ํฌ๋งทํ , ์ธ๋ฏธ์ฝ๋ก ๋๋ฝ ๋ฑ ์ฝ๋ ์คํ์ผ ๊ด๋ จ ๋ณ๊ฒฝrefactor
: ๋ฆฌํฉํ ๋ง (๊ธฐ๋ฅ ๋ณํ ์์ด ์ฝ๋ ๊ตฌ์กฐ ๊ฐ์ )test
: ํ ์คํธ ์ถ๊ฐ/์์ perf
: ์ฑ๋ฅ ๊ฐ์ [๊ธฐ์ ๋ถ์ผ] / [์์ ์ข ๋ฅ] / [์ด์๋๋ฒ]-[๊ตฌํ ๊ธฐ๋ฅ] Ex)be/feature/1-login
์ฌ๊ธฐ์ ์ด์ ๋๋ฒ๋ git issue ๋ฑ๋ก ์ ๋์ค๋ ์ซ์๋ก ํ๋ค