Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
eeef409
docs: README 수정
Shin-Yu-1 Aug 3, 2025
cb03f3e
docs: README 수정
Shin-Yu-1 Aug 3, 2025
8b996ac
docs: README 수정
Shin-Yu-1 Aug 3, 2025
434bb5c
docs: README 수정
Shin-Yu-1 Aug 3, 2025
818c58e
docs: README 수정
Shin-Yu-1 Aug 3, 2025
ce65c67
fix(InvitationLinkForm): lock icon 이미지 import / DP-207
ebbll Aug 3, 2025
5679f4f
docs: README 수정
Shin-Yu-1 Aug 3, 2025
596c9d1
Merge pull request #213 from DeepDirect/fix/DP-207/lock-icon-import
Jammanb0 Aug 3, 2025
deb633c
feat: 채팅 참조 기능 개발 / DP-209
Jammanb0 Aug 3, 2025
1489021
Merge pull request #215 from DeepDirect/feature/DP-209/chating-code-link
Jammanb0 Aug 3, 2025
75ca6ea
hotfix(ChatMessage): 채팅 참조 기능 예외 처리
Jammanb0 Aug 3, 2025
ec80f77
feat(RepoPage): CodeRunner에 repositoryName prop 추가
projectmiluju Aug 3, 2025
a5c5427
fix(Chat): 검색 결과가 없을 때 무한로딩 제거 / DP-211
ebbll Aug 3, 2025
5b00907
fix(Chat): 채팅 초기 데이터 없을 시 무한로딩 현상 제거 / DP-211
ebbll Aug 3, 2025
4146c7c
Merge pull request #218 from DeepDirect/fix/DP-211/chat-infinite-load
ebbll Aug 3, 2025
359ee03
fix: README 수정
Shin-Yu-1 Aug 3, 2025
04506ff
fix(CodeRunner): 채팅 서버 URL을 로컬호스트에서 실제 IP로 변경
projectmiluju Aug 3, 2025
786a138
refactor(CodeRunner): 중복 타입 선언 제거 / DP-210
Jammanb0 Aug 3, 2025
6a5ed63
feat: 터미널 Yjs에 연결 / DP-210
Jammanb0 Aug 3, 2025
3beb582
Merge pull request #219 from DeepDirect/doc/readme
Shin-Yu-1 Aug 3, 2025
9294bf9
Merge pull request #220 from DeepDirect/feature/DP-210/yjs-terminal
Jammanb0 Aug 3, 2025
9e2112e
Update README.md
Shin-Yu-1 Aug 3, 2025
7ef95da
fix: 좋아요 토글 변경 때마다 1페이지로 초기화 / DP-213
Shin-Yu-1 Aug 3, 2025
f1062e9
Merge pull request #223 from DeepDirect/feat/DP-213/favorite
Shin-Yu-1 Aug 3, 2025
944dabd
fix(editor): 무한 로딩 방지용 코드 수정 / DP-204
ssoogit Aug 2, 2025
c0c16b6
Merge pull request #224 from DeepDirect/fix/DP-204/에디터-확장자-세부설정
ssoogit Aug 3, 2025
fc21bba
remove: 더이상 필요 없는 웹소켓 버전 채팅 폐기 / DP-214
ebbll Aug 3, 2025
564ab35
remove: STOMP 연결 테스트용 임시 컴포넌트 제거 / DP-214
ebbll Aug 3, 2025
7539954
fix(chat): 불필요한 1초 로딩 제거 / DP-214
ebbll Aug 3, 2025
505d162
feat(chat): 채팅 파일명 변경 / DP-214
ebbll Aug 3, 2025
84c934d
fix(chat): 채팅 컴포넌트 임포트 경로 수정 / DP-214
ebbll Aug 3, 2025
7e7b5df
fix(chat): 자동 스크롤 조건 수정 / DP-214
ebbll Aug 3, 2025
03baa04
Merge pull request #226 from DeepDirect/fix/DP-214/chat-remove-files
ebbll Aug 3, 2025
19f8c11
fix(settings): 환경설정 사이드바 DELETE 글씨 빨간색으로 변경 / DP-215
ebbll Aug 3, 2025
0c7fb22
style(settings): 환경설정 섹션간 너비 달랐던 부분 통일 / DP-215
ebbll Aug 3, 2025
a86ad01
Merge pull request #228 from DeepDirect/refactor/DP-215/settings-ui
ebbll Aug 3, 2025
1d59b55
feat(repo): 터미널 섹션 배경색 다크모드에 따라 변경 / DP-216
ebbll Aug 3, 2025
1b190dc
Merge pull request #230 from DeepDirect/refactor/DP-216/terminal-ligh…
ebbll Aug 3, 2025
9764096
style(ShareSection): 아이템 간 간격, 공유링크 너비 조정 및 아이콘 호버 효과 통일 / DP-217
ebbll Aug 3, 2025
922926a
style(InfoSection): 아이콘 호버 효과 통일 / DP-217
ebbll Aug 3, 2025
dfbb8f1
Merge pull request #232 from DeepDirect/refactor/DP-217/settings-shar…
ebbll Aug 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 173 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,176 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

```js
export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...

// Remove tseslint.configs.recommended and replace with this
...tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
...tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
...tseslint.configs.stylisticTypeChecked,

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
# 🌐 Web IDE

React, TypeScript, Vite 기반의 실시간 웹 IDE입니다.
실시간 코드 동시 편집, 채팅, 파일 업로드 및 다운로드, GitHub 로그인 기능을 제공합니다.

프로젝트 기간: 2025.07 ~ 2025.08 (기획 및 개발)
Link: https://www.deepdirect.site/
Code: [FE](https://github.com/DeepDirect/deepwebide-fe), [BE](https://github.com/DeepDirect/deepwebide-be)

<br />

---

## 🫶 팀원
| 이름 | 역할 | GitHub 링크 |
|----------|--------------------|------------------------------------------------|
| 정원용 | 팀장, Full Stack | [@projectmiluju](https://github.com/jihun-dev) |
| 권혜진 | Backend | [@sunsetkk](https://github.com/sunsetkk) |
| 박건 | Frontend | [@Jammanb0](https://github.com/Jammanb0) |
| 박소현 | Frontend | [@ssoogit](https://github.com/ssoogit) |
| 박재경 | Full Stack, Infra | [@Shin-Yu-1](https://github.com/Shin-Yu-1) |
| 이은지 | Frontend | [@ebbll](https://github.com/ebbll) |
| 최범근 | Backend | [@vayaconChoi](https://github.com/vayaconChoi) |

<br />

---

## 🚀 주요 기능
- 실시간 협업 코드 편집
- 실시간 채팅

<br />

---

## 🛠️ 기술 스택

### FE
| 분류 | 기술명 |
|----------------|----------------------------------------------------------------|
| 프레임워크/런타임 | React + TypeScript |
| 빌드 도구 | Vite, TypeScript (tsc) |
| 상태 관리 | Zustand (클라이언트 상태), TanStack Query (서버 상태) |
| 라우팅 | TanStack Router (@tanstack/react-router) |
| 폼 관리/검증 | React Hook Form, Zod, @hookform/resolvers |
| 실시간 | Yjs, y-monaco, y-websocket, STOMP, SockJS |
| 코드 에디터 | Monaco Editor (@monaco-editor/react) |
| UI 라이브러리 | Radix UI (Toast, Tooltip, Switch, VisuallyHidden) |
| Drag & Drop | React DnD, react-dnd-html5-backend, @minoru/react-dnd-treeview |
| 날짜 처리 | dayjs |
| 아이콘 | pixelarticons, clsx |
| 네트워크 요청 | Axios |
| 스타일링 | SCSS |
| 코드 품질 도구 | ESLint, Prettier, Stylelint, Husky, lint-staged |

<br />

### BE
| 분류 | 사용 기술 / 라이브러리 | 설명 |
|-----------------|------------------------------------------------------|------|
| 언어 및 프레임워크 | Java 17, Spring Boot 3.4.7 | 백엔드 애플리케이션 기반 |
| 빌드 도구 | Gradle | 의존성 및 빌드 관리 |
| 웹 서버 | Spring Web (`spring-boot-starter-web`) | REST API 및 MVC 구성 |
| 보안 | Spring Security, JWT (`jjwt`), OAuth2 Client | 로그인, 인증, 인가 처리 |
| 데이터베이스 | MySQL, Spring Data JPA (`hibernate`) | 사용자 및 저장소 관리용 RDB |
| 실시간 통신 | WebSocket (`spring-websocket`), STOMP, SockJS | 채팅, 동시 편집용 실시간 통신 |
| Redis | Lettuce (`lettuce-core`), Spring Data Redis | 토큰 저장, Pub/Sub 등 |
| 파일 업로드 | AWS S3 SDK (v1, v2 혼용) | 코드 파일 업로드/다운로드 |
| 이메일 발송 | Spring Mail (`spring-boot-starter-mail`) | 이메일 인증, 알림 전송 |
| 문자 인증 | Coolsms SDK (`net.nurigo:sdk`) | 전화번호 인증 (SMS) |
| API 문서화 | SpringDoc OpenAPI (`springdoc-openapi`) | Swagger 기반 자동 API 문서 |
| 모니터링 | Spring Boot Actuator | Health Check 등 메트릭 제공 |
| 에러 추적 | Sentry (`sentry-spring-boot-starter`, logback 연동) | 런타임 에러 실시간 추적 |
| 로깅 유틸리티 | Logback, Commons IO | 로깅, 파일 유틸리티 |

<br />

---

## 📁 디렉토리 구조

### FE
```bash
src/
├── api/ # API 요청 함수 정의 (axios 등과 연동)
├── assets/ # 이미지 등 정적 리소스
├── components/ # 재사용 가능한 UI 컴포넌트
├── constants/ # 공통 상수 정의
├── features/ # 도메인 단위의 기능 모듈
├── hooks/ # 커스텀 React Hook 모음
├── layouts/ # 페이지 공통 레이아웃 컴포넌트
├── mocks/ # Mock 데이터 (개발/테스트 용)
├── pages/ # 라우팅되는 페이지 컴포넌트
├── router/ # TanStack Router 관련 라우터 설정
├── schemas/ # Zod 기반 스키마 (요청/응답 타입 정의 포함)
├── stores/ # Zustand 상태 저장소
├── styles/ # 전역 스타일 정의 (reset, theme 등)
├── types/ # 전역 타입 정의 (TypeScript interface/type 모음)
└── utils/ # 공통 유틸리티 함수
```

<br />

### BE
```bash
com.deepdirect.deepwebide_be/
├── chat/ # 실시간 채팅 도메인
│ ├── controller/
│ ├── domain/
│ ├── dto/
│ ├── repository/
│ ├── service/
│ ├── util/
│ └── websocket/ # WebSocket 핸들러 및 메시지 처리
├── file/ # 파일 업로드 및 다운로드 (S3)
│ ├── controller/
│ ├── domain/
│ ├── dto/
│ ├── repository/
│ └── service/
├── global/ # 전역 설정 및 공통 모듈
│ ├── config/ # Spring 설정 (CORS, Swagger, Redis 등)
│ ├── dto/ # 공통 응답 DTO
│ ├── exception/ # 글로벌 예외 및 핸들러
│ ├── security/ # JWT, OAuth 관련 보안 설정
│ └── util/ # 전역 유틸 클래스
├── history/ # 코드 실행 이력 관리
│ ├── controller/
│ ├── domain/
│ ├── dto/
│ ├── repository/
│ └── service/
├── member/ # 사용자 및 인증 도메인
│ ├── controller/
│ ├── domain/
│ ├── dto/
│ ├── repository/
│ ├── service/
│ └── util/ # 닉네임 자동 생성 유틸
├── repository/ # 코드 저장소 도메인
│ ├── controller/
│ ├── domain/
│ ├── dto/
│ ├── repository/
│ ├── service/
│ └── util/
└── sandbox/ # 샌드박스(코드 실행 환경) 관리
├── config/
├── controller/
├── dto/
├── exception/
└── service/
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
<br />

---

## 🏃‍➡️ 설치 및 실행
```bash
# 패키지 설치
pnpm install

# 개발 서버 실행
pnpm dev

# 빌드
pnpm build
```
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
],
"words": [
"Avenir",
"coderunner",
"eslint",
"filetree",
"partialize",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import PasswordInput from '@/components/atoms/Input/PasswordInput';
import InvitationFormActions from '@/components/molecules/InvitationFormActions/InvitationFormActions';
import lockIcon from '../../../assets/icons/lock.svg';

import './InvitationLinkForm.scss';

Expand Down Expand Up @@ -35,7 +36,7 @@ const InvitationLinkForm: React.FC<InvitationLinkFormProps> = ({
<div className="invitation-form__header">
{/* 자물쇠 아이콘 */}
<div className="invitation-form__icon">
<img src="/src/assets/icons/lock.svg" alt="잠금 아이콘" />
<img src={lockIcon} alt="잠금 아이콘" />
</div>

<h1 className="invitation-form__title">입장 코드 입력</h1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
align-items: center;
justify-content: space-between;
gap: 0 2rem;
width: 883px;
width: 700px;
height: 92px;
font-family: $font-family-inter;
transition-duration: 0.5s;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@
.icon {
width: 20px;
height: 20px;
cursor: pointer;

&:hover {
opacity: 1;
transform: scale(1.1);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
flex-direction: row;
align-items: center;
justify-content: space-between;
width: 883px;
width: 700px;
height: 92px;

@include mobile {
Expand All @@ -89,7 +89,9 @@
}

.linkWrapper {
width: 424px;
display: flex;
flex-direction: row;
padding-right: 37px;

@include mobile {
width: 100%;
Expand All @@ -110,7 +112,7 @@
.input {
box-sizing: border-box;
width: 100%;
max-width: 424px;
max-width: 350px;
padding: 0.75rem 1rem;
border: 1px solid $gray-8;
border-radius: 6px;
Expand Down Expand Up @@ -177,10 +179,15 @@
flex-direction: row;
align-items: center;
gap: 10px;
cursor: pointer;

.icon {
width: 20px;
height: 20px;
cursor: pointer;

&:hover {
opacity: 1;
transform: scale(1.1);
}
}
}
11 changes: 6 additions & 5 deletions src/components/organisms/Settings/ShareSection/ShareSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const ShareSection = ({ onShareLinkCopy }: shareSectionProps) => {
<ShareIcon className={styles.nameIcon} />
<h2 className={styles.sectionTitle}>SHARE</h2>
</div>

{/* 링크 공유 */}
{settingsData.isShared && (
<div className={`${styles.itemWrapper} ${styles.shareWrapper}`}>
Expand All @@ -127,14 +128,14 @@ const ShareSection = ({ onShareLinkCopy }: shareSectionProps) => {
<CopyIcon className={styles.icon} />
</div>
</div>

{/* 공유 링크 인풋 */}
{settingsData.shareLink && (
<input type="text" value={settingsData.shareLink} readOnly className={styles.input} />
)}
</div>
{/* 공유 링크 인풋 */}
{settingsData.shareLink && (
<input type="text" value={settingsData.shareLink} readOnly className={styles.input} />
)}
</div>
)}

{/* 입장 코드 */}
{settingsData.isShared && isCurrentUserOwner(settingsData.members) && (
<div className={`${styles.itemWrapper} ${styles.entryCodeWrapper}`}>
Expand Down
Loading