Skip to content

Commit

Permalink
Merge pull request #300 from boostcampwm2023/dev
Browse files Browse the repository at this point in the history
Release: v1.0 릴리즈
  • Loading branch information
tmddus2 authored Dec 14, 2023
2 parents 86f5333 + 8af8d44 commit ef60dfd
Show file tree
Hide file tree
Showing 95 changed files with 9,526 additions and 1,134 deletions.
233 changes: 198 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,220 @@

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


<br/>

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

<br/>

<p align=center>
<a href="https://boarlog.notion.site/">노션</a>
&nbsp; | &nbsp;
<a href="https://weak-sugar-603.notion.site/d1fb2080ff934e859d50c5cd3620e223">백로그</a>
&nbsp; | &nbsp;
<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>
&nbsp; | &nbsp;
<a href="https://github.com/boostcampwm2023/web13_Boarlog/wiki">위키</a>
</p>

<p align=center>
<a href="">시연 영상(예정)</a>
&nbsp; | &nbsp;
<a href="https://boarlog.netlify.app/">서비스 링크</a>
</p>

<br/>

<div align="center">
<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>
</div>

<br/>

## Boarlog의 주요 기능

### 🧑‍🏫 강의 생성 및 진행

> 강의자가 강의를 생성하고, **음성**으로 강의하며 **화이트보드**를 실시간으로 편집할 수 있습니다. 또한, 참여자의 질문을 받아 화이트보드에 포스트잇 형태로 추가할 수 있습니다.
<table align=center>
<tr>
<td>
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/4c24d511-7914-4d2e-aafc-303568c015f4" />
</td>
<td>
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/1e9d5624-71ad-46d3-801f-c0a74317807d" />
</td>
</tr>
<tr>
<td>
<p align=center>강의 생성 및 마이크 설정</p>
</td>
<td>
<p align=center> 화이트보드 편집 및 질문 확인</p>
</td>
</tr>
</table>

<br/>

### 🧑‍🎓 강의 참여 및 피드백

> 강의자가 공유한 **강의번호**를 입력하여 강의에 참여하고, 강의자의 음성과 화이트보드 내용을 실시간으로 볼 수 있습니다. 강의자에게 질문을 보낼 수도 있습니다.
## 프로젝트 소개: 기록으로 남기는 실시간 강의, Boarlog
<table align=center>
<tr>
<td>
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/0e75f788-510b-4ed6-9906-b7349c8092fb" />
</td>
<td>
<video src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/ea59d6f4-b6d3-4f28-9d48-ff12dad66d3b" />
</td>
</tr>
<tr>
<td>
<p align=center>강의실 입장 및 강의 내용 확인</p>
</td>
<td>
<p align=center>스피커 설정 및 질문하기</p>
</td>
</tr>
</table>

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

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

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

<br/>

## 기술 스택
## Boarlog의 기술 스택

<table align=center>
<thead>
<tr>
<th>category</th>
<th>stack</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p align=center>Common</p>
</td>
<td>
<img src="https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=ffffff">
<img src="https://img.shields.io/badge/WebRTC-333333?logo=webrtc">
<img src="https://img.shields.io/badge/Socket.io-010101?logo=Socket.io">
<img src="https://img.shields.io/badge/Prettier-F7B93E?logo=prettier&logoColor=ffffff">
<img src="https://img.shields.io/badge/ESLint-4B32C3?logo=Eslint">
<img src="https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=ffffff">
<img src="https://img.shields.io/badge/.ENV-ECD53F?logo=.ENV&logoColor=ffffff">
</td>
</tr>
<tr>
<td>
<p align=center>Frontend</p>
</td>
<td>
<img src="https://img.shields.io/badge/React-61DAFB?logo=React&logoColor=ffffff">
<img src="https://img.shields.io/badge/Vite-646CFF?logo=Vite&logoColor=ffffff">
<img src="https://img.shields.io/badge/TailwindCSS-06B6D4?logo=tailwindcss&logoColor=ffffff">
<img src="https://img.shields.io/badge/Recoil-3578E5?logo=recoil&logoColor=ffffff">
<img src="https://img.shields.io/badge/Axios-5A29E4?logo=axios&logoColor=ffffff">
<img src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/646e36a9-366d-4b91-9b42-a4e2eef584cd">
<img src="https://github.com/boostcampwm2023/web13_Boarlog/assets/86391351/54880738-cc88-4f63-8cfa-d955dc5721e3">
</td>
</tr>
<tr>
<td>
<p align=center>Backend</p>
</td>
<td>
<img src="https://img.shields.io/badge/Next.js-000000?logo=nextdotjs">
<img src="https://img.shields.io/badge/MongoDB-114411?logo=mongodb">
<img src="https://img.shields.io/badge/Mongoose-114411?logo=mongodb">
</td>
</tr>
<tr>
<td>
<p align=center>Deployment</p>
</td>
<td>
<img src="https://img.shields.io/badge/GitHub Actions-000000?logo=github-actions">
</td>
</tr>
<tr>
<td>
<p align=center>Deployment</p>
</td>
<td>
<img src="https://img.shields.io/badge/Netlify-00C7B7?logo=netlify&logoColor=ffffff&">
<img src="https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=ffffff&">
<img src="https://img.shields.io/badge/nginx-014532?logo=Nginx&logoColor=009639&">
<img src="https://img.shields.io/badge/Naver Cloud Platform-03C75A?logo=naver&logoColor=ffffff">
</td>
</tr>
<tr>
<td>
<p align=center>Collaboration</p>
</td>
<td>
<img src="https://img.shields.io/badge/Notion-000000?logo=Notion">
<img src="https://img.shields.io/badge/Figma-F24E1E?logo=Figma&logoColor=ffffff">
<img src="https://img.shields.io/badge/Slack-4A154B?logo=Slack&logoColor=ffffff">
</td>
</tr>
</tbody>
</table>

### Front-End
<br/>

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

- `NestJS` `MongoDB` `Docker`
<br/>

## 팀 소개: TEAM_528

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

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

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

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

<table align=center>
<thead>
Expand All @@ -64,19 +228,19 @@ const teamName = camperIdArray.reduce((team, camperId) => {
</thead>
<tbody align=center>
<tr>
<td>
<td width="150">
<a href="https://github.com/Byeonjin"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/54176384?v=4" /></a>
</td>
<td>
<td width="150">
<a href="https://github.com/LellowMellow"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/79556112?v=4" /></a>
</td>
<td>
<td width="150">
<a href="https://github.com/tmddus2"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/49530253?v=4" /></a>
</td>
<td>
<td width="150">
<a href="https://github.com/platinouss"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/70827921?v=4" /></a>
</td>
<td>
<td width="150">
<a href="https://github.com/Jw705"><img width="120" height="120" src="https://avatars.githubusercontent.com/u/86391351?v=4" /></a>
</td>
</tr>
Expand All @@ -88,11 +252,11 @@ const teamName = camperIdArray.reduce((team, camperId) => {
<td><a href="https://github.com/Jw705">@Jw705</a></td>
</tr>
<tr align=left>
<td width="200">깊이있게 고민하고 기록하기</td>
<td width="200">괜한 걱정 하지 않고 차근차근 쌓아올리기</td>
<td width="200">두려워하지 않고 문제 해결하기</td>
<td width="200">기술 선택에 나만의 근거를 만들기</td>
<td width="200">작성한 코드에 대한 의도를 잘 기록하기</td>
<td width="150">깊이있게 고민하고 기록하기</td>
<td width="150">괜한 걱정 하지 않고 차근차근 쌓아올리기</td>
<td width="150">두려워하지 않고 문제 해결하기</td>
<td width="150">기술 선택에 나만의 근거를 만들기</td>
<td width="150">작성한 코드에 대한 의도를 잘 기록하기</td>
</tr>
</tbody>
</table>
Expand All @@ -105,7 +269,6 @@ const teamName = camperIdArray.reduce((team, camperId) => {
- [branch/conmmit 컨벤션](https://weak-sugar-603.notion.site/Git-Branch-Commmit-882a35cba1cc433eb0f01abf2e3b134d?pvs=4)
- [기획/디자인](https://www.figma.com/file/vd1TPvzMNwy6OfVmNFw8cI/Untitled?type=design&node-id=4%3A22&mode=design&t=NS1IQkeFYsr7lSuf-1)
- [위키](https://github.com/boostcampwm2023/web13_TEAM_528/wiki)
- [노션](https://weak-sugar-603.notion.site/TEAM_528-7780e03d7e9847b89fdf9f926036987b?pvs=4)
- [노션](https://boarlog.notion.site/)
- [백로그](https://www.notion.so/d1fb2080ff934e859d50c5cd3620e223)
- [데모 링크](https://boarlog.netlify.app)

22 changes: 9 additions & 13 deletions backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Body, Controller, Get, HttpException, HttpStatus, Post, Req, Res, UseGuards } from '@nestjs/common';
import { ApiBody, ApiResponse, ApiTags } from '@nestjs/swagger';
import { Body, Controller, HttpException, HttpStatus, Post, Res } from '@nestjs/common';
import { ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { Response } from 'express';
import { CustomAuthGuard } from './auth.guard';
import { AuthService } from './auth.service';
import { SignInDto } from './dto/auth.signin.dto';
import { SignUpDto } from './dto/auth.signup.dto';
import { ResponseSignInDto } from './dto/response-signin.dto';
import { SignInDto } from './dto/sign-in.dto';
import { SignUpDto } from './dto/sign-up.dto';

@ApiTags('auth')
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}

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

@Post('/signin')
@ApiOperation({ summary: '로그인 API' })
@ApiBody({ type: SignInDto })
@ApiResponse({ status: 200 })
@ApiResponse({ status: 200, type: ResponseSignInDto })
@ApiResponse({ status: 404, description: '해당 사용자가 없습니다.' })
async signIn(@Body() signInDto: SignInDto, @Res() res: Response) {
const user = this.authService.findUserByEmail(signInDto.email);
if (!user) {
throw new HttpException('해당 사용자가 없습니다.', HttpStatus.NOT_FOUND);
}
const result = await this.authService.signIn(signInDto);
return res.status(HttpStatus.OK).send({ token: result });
}

@UseGuards(CustomAuthGuard)
@Get('profile')
getProfile(@Req() req: any) {
return req.user;
return res.status(HttpStatus.OK).send(result);
}
}
3 changes: 1 addition & 2 deletions backend/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from 'src/user/user.schema';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { GoogleStrategy } from './google.strategy';

@Module({
imports: [
Expand All @@ -21,6 +20,6 @@ import { GoogleStrategy } from './google.strategy';
})
],
controllers: [AuthController],
providers: [AuthService, GoogleStrategy]
providers: [AuthService]
})
export class AuthModule {}
17 changes: 11 additions & 6 deletions backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { JwtService } from '@nestjs/jwt';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User } from 'src/user/user.schema';
import { SignUpDto } from './dto/auth.signup.dto';
import { SignInDto } from './dto/auth.signin.dto';
import { ConfigService } from '@nestjs/config';
import { decryptPassword, encryptPassword } from 'src/utils/GenerateUtils';
import { SignUpDto } from './dto/sign-up.dto';
import { SignInDto } from './dto/sign-in.dto';
import { ResponseSignInDto } from './dto/response-signin.dto';

@Injectable()
export class AuthService {
Expand All @@ -22,14 +23,18 @@ export class AuthService {
return { username: user.username, email: user.email };
}

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

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

async findUserByEmail(email: string): Promise<User> {
Expand Down
Loading

0 comments on commit ef60dfd

Please sign in to comment.