Skip to content

Commit ef60dfd

Browse files
authored
Merge pull request #300 from boostcampwm2023/dev
Release: v1.0 릴리즈
2 parents 86f5333 + 8af8d44 commit ef60dfd

File tree

95 files changed

+9526
-1134
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+9526
-1134
lines changed

README.md

+198-35
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,220 @@
11

2-
![Group 9798](https://github.com/boostcampwm2023/web13_Boarlog/assets/79556112/f81c9aa9-51cf-4c48-84af-d10575fa8d26)
2+
![boarlog1](https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/89de8827-e5ac-4494-a196-982af8ea2c5f)
33

44

5-
<br/>
6-
75
<p align="center">
86
<a href="https://boarlog.netlify.app">
9-
<img src="https://github.com/boostcampwm2023/web13_Boarlog/assets/79556112/b51a0131-4112-4f86-909d-acbeb7a6c5c2"/>
7+
<img width="300" alt="배포 패이지로 이동" src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/2465c664-cf4f-405b-ae2c-d09cbe86e597"/>
108
</a>
119
</p>
1210

1311
<br/>
1412

13+
<p align=center>
14+
<a href="https://boarlog.notion.site/">노션</a>
15+
&nbsp; | &nbsp;
16+
<a href="https://weak-sugar-603.notion.site/d1fb2080ff934e859d50c5cd3620e223">백로그</a>
17+
&nbsp; | &nbsp;
18+
<a href="https://www.figma.com/file/1wp3yrrwOU6M7y7v5WOXet/%EB%94%94%EC%9E%90%EC%9D%B8-%EC%8B%9C%EC%95%88?type=design&node-id=33-8035&mode=design&t=kKUoymq1TBmjD0HR-0">피그마</a>
19+
&nbsp; | &nbsp;
20+
<a href="https://github.com/boostcampwm2023/web13_Boarlog/wiki">위키</a>
21+
</p>
22+
23+
<p align=center>
24+
<a href="">시연 영상(예정)</a>
25+
&nbsp; | &nbsp;
26+
<a href="https://boarlog.netlify.app/">서비스 링크</a>
27+
</p>
28+
29+
<br/>
30+
31+
<div align="center">
32+
<a href="https://hits.seeyoufarm.com"><img src="https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fboostcampwm2023%2Fweb13_Boarlog&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false"/></a>
33+
</div>
34+
35+
<br/>
36+
37+
## Boarlog의 주요 기능
38+
39+
### 🧑‍🏫 강의 생성 및 진행
40+
41+
> 강의자가 강의를 생성하고, **음성**으로 강의하며 **화이트보드**를 실시간으로 편집할 수 있습니다. 또한, 참여자의 질문을 받아 화이트보드에 포스트잇 형태로 추가할 수 있습니다.
42+
43+
<table align=center>
44+
<tr>
45+
<td>
46+
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/4c24d511-7914-4d2e-aafc-303568c015f4" />
47+
</td>
48+
<td>
49+
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/1e9d5624-71ad-46d3-801f-c0a74317807d" />
50+
</td>
51+
</tr>
52+
<tr>
53+
<td>
54+
<p align=center>강의 생성 및 마이크 설정</p>
55+
</td>
56+
<td>
57+
<p align=center> 화이트보드 편집 및 질문 확인</p>
58+
</td>
59+
</tr>
60+
</table>
61+
62+
<br/>
63+
64+
### 🧑‍🎓 강의 참여 및 피드백
65+
66+
> 강의자가 공유한 **강의번호**를 입력하여 강의에 참여하고, 강의자의 음성과 화이트보드 내용을 실시간으로 볼 수 있습니다. 강의자에게 질문을 보낼 수도 있습니다.
1567
16-
## 프로젝트 소개: 기록으로 남기는 실시간 강의, Boarlog
68+
<table align=center>
69+
<tr>
70+
<td>
71+
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/0e75f788-510b-4ed6-9906-b7349c8092fb" />
72+
</td>
73+
<td>
74+
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/ea59d6f4-b6d3-4f28-9d48-ff12dad66d3b" />
75+
</td>
76+
</tr>
77+
<tr>
78+
<td>
79+
<p align=center>강의실 입장 및 강의 내용 확인</p>
80+
</td>
81+
<td>
82+
<p align=center>스피커 설정 및 질문하기</p>
83+
</td>
84+
</tr>
85+
</table>
1786

18-
> **필기앱처럼 강의도 기록으로 남기면 어떨까?**
87+
<br/>
1988

20-
**Boarlog**는 교육 및 협업을 위한 실시간 화이트보드 강의 플랫폼입니다. 음성 기반 강의와 시각적 상호작용을 결합하여 참여자들에게 효과적이고 몰입도 높은 학습 경험을 제공합니다.
89+
### 🎥 강의 다시보기
2190

22-
- **강의 생성 및 진행**: 강의자는 손쉽게 강의방을 열고, 음성으로 강의하며 화이트보드를 실시간으로 편집할 수 있습니다.
23-
- **강의 참여**: 참여자들은 강의에 접속하여 강의자의 음성과 화이트보드 내용을 실시간으로 볼 수 있습니다.
24-
- **상호작용 및 피드백**: 참여자들은 질문을 보내고, 강의자는 이를 포스트잇 형태로 화이트보드에 추가하여 답변할 수 있습니다.
25-
- **강의 기록 및 재생**: 강의 종료 후에는 AI를 활용하여 음성을 스크립트로 변환, 이를 화이트보드 내용과 함께 저장하여 언제든지 다시볼 수 있습니다.
91+
> 강의 종료 후에는 서버에서 화이트보드와 음성, AI를 이용한 음성 스크립트를 저장하여 언제든지 다시볼 수 있습니다.
92+
93+
<table align=center>
94+
<tr>
95+
<td>
96+
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/0e75f788-510b-4ed6-9906-b7349c8092fb" />
97+
</td>
98+
<td>
99+
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/0e75f788-510b-4ed6-9906-b7349c8092fb" />
100+
</td>
101+
</tr>
102+
<tr>
103+
<td>
104+
<p align=center>참여한 강의 내역 확인</p>
105+
</td>
106+
<td>
107+
<p align=center>강의 다시보기</p>
108+
</td>
109+
</tr>
110+
</table>
26111

27112
<br/>
28113

29-
## 기술 스택
114+
## Boarlog의 기술 스택
115+
116+
<table align=center>
117+
<thead>
118+
<tr>
119+
<th>category</th>
120+
<th>stack</th>
121+
</tr>
122+
</thead>
123+
<tbody>
124+
<tr>
125+
<td>
126+
<p align=center>Common</p>
127+
</td>
128+
<td>
129+
<img src="https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=ffffff">
130+
<img src="https://img.shields.io/badge/WebRTC-333333?logo=webrtc">
131+
<img src="https://img.shields.io/badge/Socket.io-010101?logo=Socket.io">
132+
<img src="https://img.shields.io/badge/Prettier-F7B93E?logo=prettier&logoColor=ffffff">
133+
<img src="https://img.shields.io/badge/ESLint-4B32C3?logo=Eslint">
134+
<img src="https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=ffffff">
135+
<img src="https://img.shields.io/badge/.ENV-ECD53F?logo=.ENV&logoColor=ffffff">
136+
</td>
137+
</tr>
138+
<tr>
139+
<td>
140+
<p align=center>Frontend</p>
141+
</td>
142+
<td>
143+
<img src="https://img.shields.io/badge/React-61DAFB?logo=React&logoColor=ffffff">
144+
<img src="https://img.shields.io/badge/Vite-646CFF?logo=Vite&logoColor=ffffff">
145+
<img src="https://img.shields.io/badge/TailwindCSS-06B6D4?logo=tailwindcss&logoColor=ffffff">
146+
<img src="https://img.shields.io/badge/Recoil-3578E5?logo=recoil&logoColor=ffffff">
147+
<img src="https://img.shields.io/badge/Axios-5A29E4?logo=axios&logoColor=ffffff">
148+
<img src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/646e36a9-366d-4b91-9b42-a4e2eef584cd">
149+
<img src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/54880738-cc88-4f63-8cfa-d955dc5721e3">
150+
</td>
151+
</tr>
152+
<tr>
153+
<td>
154+
<p align=center>Backend</p>
155+
</td>
156+
<td>
157+
<img src="https://img.shields.io/badge/Next.js-000000?logo=nextdotjs">
158+
<img src="https://img.shields.io/badge/MongoDB-114411?logo=mongodb">
159+
<img src="https://img.shields.io/badge/Mongoose-114411?logo=mongodb">
160+
</td>
161+
</tr>
162+
<tr>
163+
<td>
164+
<p align=center>Deployment</p>
165+
</td>
166+
<td>
167+
<img src="https://img.shields.io/badge/GitHub Actions-000000?logo=github-actions">
168+
</td>
169+
</tr>
170+
<tr>
171+
<td>
172+
<p align=center>Deployment</p>
173+
</td>
174+
<td>
175+
<img src="https://img.shields.io/badge/Netlify-00C7B7?logo=netlify&logoColor=ffffff&">
176+
<img src="https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=ffffff&">
177+
<img src="https://img.shields.io/badge/nginx-014532?logo=Nginx&logoColor=009639&">
178+
<img src="https://img.shields.io/badge/Naver Cloud Platform-03C75A?logo=naver&logoColor=ffffff">
179+
</td>
180+
</tr>
181+
<tr>
182+
<td>
183+
<p align=center>Collaboration</p>
184+
</td>
185+
<td>
186+
<img src="https://img.shields.io/badge/Notion-000000?logo=Notion">
187+
<img src="https://img.shields.io/badge/Figma-F24E1E?logo=Figma&logoColor=ffffff">
188+
<img src="https://img.shields.io/badge/Slack-4A154B?logo=Slack&logoColor=ffffff">
189+
</td>
190+
</tr>
191+
</tbody>
192+
</table>
30193

31-
### Front-End
194+
<br/>
32195

33-
- `JavaScript` `HTML5` `CSS3` `React` `Socket.io` `Fabric.js` `React Router` `TailwindCSS` `Modernizr`
196+
## 핵심 개발 일지
197+
> **🔗 프로젝트 진행 과정에서 고민하고 도전한 과정이 담긴 핵심 개발 일지입니다.**
34198
35-
### Back-End
199+
- []()
36200

37-
- `NestJS` `MongoDB` `Docker`
201+
<br/>
38202

39203
## 팀 소개: TEAM_528
40204

41205
```jsx
42-
const teamName = camperIdArray.reduce((team, camperId) => {
43-
return team += parseInt(camperId.replace(/[^0-9]/g, ""));
44-
}, 0)
206+
const camperIdArray = ["J063", "J095", "J105", "J124", "J141"];
45207

46-
// 팀에 우리를 더하다.
208+
const teamName = camperIdArray.reduce((team, camperId) => {
209+
return (team += parseInt(camperId.replace(/[^0-9]/g, "")));
210+
}, 0);
47211
```
48212

49-
> **5명이 모여 하나의 개발자처럼.**
213+
> 5명이 모여 **하나의** 개발자처럼 : J0**63** + J0**95** + J**105** + J**124** + J**141**
50214
51-
`528`은 팀원 5명의 캠퍼 번호를 더한 숫자입니다(63+95+105+124+141).
215+
`528`은 팀원 5명의 캠퍼 번호를 더한 숫자입니다. 5명의 캠퍼가 하나의 번호를 가지고 서로 다른 기술, 경험, 및 아이디어를 결합하여 시너지를 발휘하겠다는 의미입니다.
52216

53-
5명의 캠퍼가 하나의 번호를 가지고 서로 다른 기술, 경험, 및 아이디어를 결합하여 시너지를 발휘하고자 합니다.
217+
<br/>
54218

55219
<table align=center>
56220
<thead>
@@ -64,19 +228,19 @@ const teamName = camperIdArray.reduce((team, camperId) => {
64228
</thead>
65229
<tbody align=center>
66230
<tr>
67-
<td>
231+
<td width="150">
68232
<a href="https://github.com/Byeonjin"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/54176384?v=4" /></a>
69233
</td>
70-
<td>
234+
<td width="150">
71235
<a href="https://github.com/LellowMellow"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/79556112?v=4" /></a>
72236
</td>
73-
<td>
237+
<td width="150">
74238
<a href="https://github.com/tmddus2"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/49530253?v=4" /></a>
75239
</td>
76-
<td>
240+
<td width="150">
77241
<a href="https://github.com/platinouss"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/70827921?v=4" /></a>
78242
</td>
79-
<td>
243+
<td width="150">
80244
<a href="https://github.com/Jw705"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/86391351?v=4" /></a>
81245
</td>
82246
</tr>
@@ -88,11 +252,11 @@ const teamName = camperIdArray.reduce((team, camperId) => {
88252
<td><a href="https://github.com/Jw705">@Jw705</a></td>
89253
</tr>
90254
<tr align=left>
91-
<td width="200">깊이있게 고민하고 기록하기</td>
92-
<td width="200">괜한 걱정 하지 않고 차근차근 쌓아올리기</td>
93-
<td width="200">두려워하지 않고 문제 해결하기</td>
94-
<td width="200">기술 선택에 나만의 근거를 만들기</td>
95-
<td width="200">작성한 코드에 대한 의도를 잘 기록하기</td>
255+
<td width="150">깊이있게 고민하고 기록하기</td>
256+
<td width="150">괜한 걱정 하지 않고 차근차근 쌓아올리기</td>
257+
<td width="150">두려워하지 않고 문제 해결하기</td>
258+
<td width="150">기술 선택에 나만의 근거를 만들기</td>
259+
<td width="150">작성한 코드에 대한 의도를 잘 기록하기</td>
96260
</tr>
97261
</tbody>
98262
</table>
@@ -105,7 +269,6 @@ const teamName = camperIdArray.reduce((team, camperId) => {
105269
- [branch/conmmit 컨벤션](https://weak-sugar-603.notion.site/Git-Branch-Commmit-882a35cba1cc433eb0f01abf2e3b134d?pvs=4)
106270
- [기획/디자인](https://www.figma.com/file/vd1TPvzMNwy6OfVmNFw8cI/Untitled?type=design&node-id=4%3A22&mode=design&t=NS1IQkeFYsr7lSuf-1)
107271
- [위키](https://github.com/boostcampwm2023/web13_TEAM_528/wiki)
108-
- [노션](https://weak-sugar-603.notion.site/TEAM_528-7780e03d7e9847b89fdf9f926036987b?pvs=4)
272+
- [노션](https://boarlog.notion.site/)
109273
- [백로그](https://www.notion.so/d1fb2080ff934e859d50c5cd3620e223)
110274
- [데모 링크](https://boarlog.netlify.app)
111-

backend/src/auth/auth.controller.ts

+9-13
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
import { Body, Controller, Get, HttpException, HttpStatus, Post, Req, Res, UseGuards } from '@nestjs/common';
2-
import { ApiBody, ApiResponse, ApiTags } from '@nestjs/swagger';
1+
import { Body, Controller, HttpException, HttpStatus, Post, Res } from '@nestjs/common';
2+
import { ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
33
import { Response } from 'express';
4-
import { CustomAuthGuard } from './auth.guard';
54
import { AuthService } from './auth.service';
6-
import { SignInDto } from './dto/auth.signin.dto';
7-
import { SignUpDto } from './dto/auth.signup.dto';
5+
import { ResponseSignInDto } from './dto/response-signin.dto';
6+
import { SignInDto } from './dto/sign-in.dto';
7+
import { SignUpDto } from './dto/sign-up.dto';
88

99
@ApiTags('auth')
1010
@Controller('auth')
1111
export class AuthController {
1212
constructor(private authService: AuthService) {}
1313

1414
@Post('/signup')
15+
@ApiOperation({ summary: '회원가입 API' })
1516
@ApiBody({ type: SignUpDto })
1617
@ApiResponse({ status: 201 })
1718
@ApiResponse({ status: 409, description: '이미 가입되어 있는 사용자입니다.' })
@@ -24,21 +25,16 @@ export class AuthController {
2425
}
2526

2627
@Post('/signin')
28+
@ApiOperation({ summary: '로그인 API' })
2729
@ApiBody({ type: SignInDto })
28-
@ApiResponse({ status: 200 })
30+
@ApiResponse({ status: 200, type: ResponseSignInDto })
2931
@ApiResponse({ status: 404, description: '해당 사용자가 없습니다.' })
3032
async signIn(@Body() signInDto: SignInDto, @Res() res: Response) {
3133
const user = this.authService.findUserByEmail(signInDto.email);
3234
if (!user) {
3335
throw new HttpException('해당 사용자가 없습니다.', HttpStatus.NOT_FOUND);
3436
}
3537
const result = await this.authService.signIn(signInDto);
36-
return res.status(HttpStatus.OK).send({ token: result });
37-
}
38-
39-
@UseGuards(CustomAuthGuard)
40-
@Get('profile')
41-
getProfile(@Req() req: any) {
42-
return req.user;
38+
return res.status(HttpStatus.OK).send(result);
4339
}
4440
}

backend/src/auth/auth.module.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { MongooseModule } from '@nestjs/mongoose';
55
import { User, UserSchema } from 'src/user/user.schema';
66
import { AuthController } from './auth.controller';
77
import { AuthService } from './auth.service';
8-
import { GoogleStrategy } from './google.strategy';
98

109
@Module({
1110
imports: [
@@ -21,6 +20,6 @@ import { GoogleStrategy } from './google.strategy';
2120
})
2221
],
2322
controllers: [AuthController],
24-
providers: [AuthService, GoogleStrategy]
23+
providers: [AuthService]
2524
})
2625
export class AuthModule {}

backend/src/auth/auth.service.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import { JwtService } from '@nestjs/jwt';
33
import { InjectModel } from '@nestjs/mongoose';
44
import { Model } from 'mongoose';
55
import { User } from 'src/user/user.schema';
6-
import { SignUpDto } from './dto/auth.signup.dto';
7-
import { SignInDto } from './dto/auth.signin.dto';
86
import { ConfigService } from '@nestjs/config';
97
import { decryptPassword, encryptPassword } from 'src/utils/GenerateUtils';
8+
import { SignUpDto } from './dto/sign-up.dto';
9+
import { SignInDto } from './dto/sign-in.dto';
10+
import { ResponseSignInDto } from './dto/response-signin.dto';
1011

1112
@Injectable()
1213
export class AuthService {
@@ -22,14 +23,18 @@ export class AuthService {
2223
return { username: user.username, email: user.email };
2324
}
2425

25-
async signIn(signInDto: SignInDto): Promise<string> {
26+
async signIn(signInDto: SignInDto): Promise<ResponseSignInDto> {
2627
const user = await this.findUserByEmail(signInDto.email);
27-
const validatedPassword = await decryptPassword(signInDto.password, user.password);
28-
if (!user || !validatedPassword) {
28+
if (!user) {
2929
throw new HttpException('해당 사용자가 없습니다.', HttpStatus.NOT_FOUND);
3030
}
3131

32-
return await this.generateCookie({ username: user.username, email: user.email });
32+
const validatedPassword = await decryptPassword(signInDto.password, user?.password);
33+
if (!validatedPassword) {
34+
throw new HttpException('해당 사용자가 없습니다.', HttpStatus.NOT_FOUND);
35+
}
36+
const token = await this.generateCookie({ username: user.username, email: user.email });
37+
return new ResponseSignInDto(token, user.email, user.username);
3338
}
3439

3540
async findUserByEmail(email: string): Promise<User> {

0 commit comments

Comments
 (0)