Skip to content

Commit 3388a45

Browse files
authored
Merge pull request #268 from modern-agile-team/develop
1.0.0 버전업
2 parents c417db7 + 5f0294f commit 3388a45

File tree

69 files changed

+1526
-492
lines changed

Some content is hidden

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

69 files changed

+1526
-492
lines changed

README.md

+71-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
# 멘보샤
1+
# <span style="color:#ff772b">멘보샤</span>
22

33
## 프로젝트 소개
44

55
- 새우를 그냥 튀긴 것보다 양쪽에 빵을 붙여 튀겨서 더 맛있게 만드는 것처럼 서로가 서로에게 빵과 새우의 존재가 될 수 있도록 도와주는 것을 목표로하는 플랫폼
66

7-
## 개발기간
7+
## 개발 기간
88

9-
- 23.12.01 ~ 24.03.01 +a
9+
- 23.12.01 ~ 24.03.17
10+
- 베타 테스트 기간 : 24.03.18 ~ 24.04.01
1011

1112
### 멤버구성
1213

@@ -24,6 +25,73 @@
2425

2526
---
2627

28+
## 기술 스택
29+
30+
<h3 align="center">
31+
Language & Tools
32+
</h3>
33+
<p align="center">
34+
<img src="https://img.shields.io/badge/HTML-white?logo=html5"/>
35+
<img src= "https://img.shields.io/badge/CSS-blue?logo=css3"/>
36+
<img src= "https://img.shields.io/badge/Scss-pink?logo=sass"/>
37+
<img src= "https://img.shields.io/badge/TypeScript-white?logo=typeScript&logoColor=3178C6"/>
38+
<img src= "https://img.shields.io/badge/VScode-white?logo=visualstudiocode&logoColor=007ACC"/>
39+
</p>
40+
41+
<h3 align="center">
42+
FrameWork & Library
43+
</h3>
44+
45+
<p align="center">
46+
<img src= "https://img.shields.io/badge/Next.js-black?logo=next.js&logoColor=white"/>
47+
<img src= "https://img.shields.io/badge/React-blue?logo=react"/>
48+
<img src= "https://img.shields.io/badge/Socket.io-white?logo=socket.io&logoColor=010101"/>
49+
<img src= "https://img.shields.io/badge/MSW-white?logo=mockserviceworker&logoColor=black"/>
50+
<img src= "https://img.shields.io/badge/Axios-white?logo=axios&logoColor=5A29E4"/>
51+
<img src= "https://img.shields.io/badge/Styled--Components-DB7093?logo=styledcomponents&logoColor=white"/>
52+
</p>
53+
54+
<h3 align="center">
55+
Global-State
56+
</h3>
57+
58+
<p align="center">
59+
<img src= "https://img.shields.io/badge/Recoil-3578E5?logo=Recoil&logoColor=white"/>
60+
</p>
61+
62+
<h3 align="center">
63+
Module-Bundler
64+
</h3>
65+
66+
<p align="center">
67+
<img src= "https://img.shields.io/badge/WebPack-white?logo=webpack&logoColor=blue"/>
68+
</p>
69+
70+
<h3 align="center">
71+
Cooperation-Tools
72+
</h3>
73+
74+
<p align="center">
75+
<img src= "https://img.shields.io/badge/ESLint-white?logo=eslint&logoColor=4B32C3"/>
76+
<img src= "https://img.shields.io/badge/Prettier-black?logo=Prettier&logoColor=F7B93E"/>
77+
<img src= "https://img.shields.io/badge/.ENV-black?logo=dotenv&logoColor=#ECD53F"/>
78+
</p>
79+
80+
<h3 align="center">
81+
Communication
82+
</h3>
83+
84+
<p align="center">
85+
<img src= "https://img.shields.io/badge/Git-white?logo=git&logoColor=F05032"/>
86+
<img src= "https://img.shields.io/badge/Github-black?logo=github&logoColor=#181717"/>
87+
<img src= "https://img.shields.io/badge/Github--Actions-white?logo=githubactions&logoColor=2088FF"/>
88+
<img src= "https://img.shields.io/badge/Slack-white?logo=slack&logoColor=4A154B"/>
89+
<img src= "https://img.shields.io/badge/Notion-white?logo=notion&logoColor=000000"/>
90+
<img src= "https://img.shields.io/badge/Discord-white?logo=Discord&logoColor=#5865F2"/>
91+
<img src= "https://img.shields.io/badge/Figma-white?logo=figma&logoColor=#F24E1E"/>
92+
93+
</p>
94+
2795
### 커밋 메시지 컨벤션
2896

2997
`feat` : 새로운 기능 추가

dockerfile

+13-2
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,25 @@ ENV PORT 80
5757

5858
CMD ["node", "server.js"]
5959

60+
#######################################- 여기서부터 ngninx dockerfile -##########################################
6061
# #nginx 이미지 사용
6162
# FROM nginx:latest
6263

63-
# #nignx와 certbot 설치
64-
# RUN apt-get update && apt-get install -y certbot python3-certbot-nginx
64+
# #nignx와 certbot 설치 -(+인증서 갱신을 위한 cron)
65+
# RUN apt-get update && apt-get install -y certbot python3-certbot-nginx cron
6566

6667
# #nginx.conf(설정파일 복사)
6768
# COPY nginx.conf /etc/nginx/nginx.conf
6869

70+
# #SSL 인증서 갱신을 위한 cron 스크립트 복사
71+
# COPY renew_ssl_cert.sh /renew_ssl_cert.sh
72+
73+
# #스크립트 권한 부여
74+
# RUN chmod +x /renew_ssl_cert.sh
75+
76+
# #cron 작업 추가
77+
# RUN echo "0 0 1 * * root /renew_ssl_cert.sh" >> /etc/crontab
78+
6979
# #port
7080
# EXPOSE 80
7181
# EXPOSE 443
@@ -76,3 +86,4 @@ CMD ["node", "server.js"]
7686

7787
# #컨테이너가 실행될 때 entrypoint.sh 실행
7888
# CMD ["/entrypoint.sh"]
89+

next.config.js

+12-17
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,19 @@ const nextConfig = {
3434
// ];
3535
// },
3636
//강제 리다이렉트 실행
37-
async middleware() {
38-
return ['./src/middleware'];
39-
},
4037
rewrites() {
41-
return {
42-
beforeFiles: [
43-
{
44-
source: '/:path*',
45-
has: [
46-
{
47-
type: 'host',
48-
value: 'www.menbosha.kr',
49-
},
50-
],
51-
destination: 'https://menbosha.kr/:path*',
52-
},
53-
],
54-
};
38+
return [
39+
{
40+
source: '/:path*',
41+
has: [
42+
{
43+
type: 'host',
44+
value: 'www.menbosha.kr',
45+
},
46+
],
47+
destination: '//:path*',
48+
},
49+
];
5550
},
5651
generateEtags: false,
5752
images: {

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {
6-
"dev": "next dev",
6+
"dev": "env-cmd -f .env.development next dev",
77
"dev:mock": "env-cmd -f .env.mock next dev",
88
"build": "next build",
99
"start": "next start",

renew_ssl_cert.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/bash
2+
3+
# Certbot을 사용하여 SSL 인증서 갱신
4+
certbot renew --quiet --nginx

src/apis/axiosInstance.ts

+60-49
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,13 @@ import axios from 'axios';
33
const instance = axios.create({
44
baseURL: process.env.NEXT_PUBLIC_API_BASE_URL,
55
withCredentials: true,
6-
timeout: 5000,
6+
timeout: 3000, //3초동안 요청 안가면 timeout
77
});
88

99
//토근 갱신
1010
const reNewToken = async () => {
11-
try {
12-
const response = await axios.get(
13-
`${process.env.NEXT_PUBLIC_API_BASE_URL}auth/new-access-token`,
14-
);
15-
localStorage.setItem('accessToken', response.data.accessToken);
16-
} catch (err) {
17-
if (axios.isAxiosError(err) && err.response) {
18-
//재발급 중 에러 발생 시
19-
if (
20-
(err.response.data.message === 'invalid token' &&
21-
err.response.data.statusCode === 400) ||
22-
(err.response.data.message === 'token not found' &&
23-
err.response.data.statusCode === 404) ||
24-
(err.response.data.message === 'token mismatch' &&
25-
err.response.data.statusCode === 401)
26-
) {
27-
window.location.href = '/';
28-
setTimeout(() => {
29-
window.localStorage.clear();
30-
}, 0);
31-
}
32-
}
33-
}
11+
const response = await instance(`/auth/new-access-token`);
12+
localStorage.setItem('accessToken', response.data.accessToken);
3413
};
3514

3615
//요청 전 인터셉터
@@ -54,56 +33,88 @@ instance.interceptors.request.use(
5433
instance.interceptors.response.use(
5534
(response) => {
5635
if (response.status === 404) {
57-
console.log('404 error');
36+
window.location.href = '/404';
5837
}
5938
return response;
6039
},
6140
async (error) => {
62-
if (
63-
(error.response.data.statusCode === 401 &&
64-
error.response.data.message === 'jwt expired') ||
65-
(error.response.data.statusCode === 404 &&
66-
error.response.data.message === 'token not found') ||
67-
(error.response.data.statusCode === 401 &&
68-
error.response.data.message === 'token mismatch')
41+
console.log('인스턴스에러', error);
42+
//요청 만료시
43+
if (error.message === 'timeout of 3000ms exceeded') {
44+
alert('요청시간이 초과되었습니다.');
45+
window.location.href = '/';
46+
window.localStorage.clear();
47+
return;
48+
}
49+
//토큰 재발급
50+
else if (
51+
error.response.data.statusCode === 401 ||
52+
error.response.data.statusCode === 404
6953
) {
70-
//토큰 재발급
7154
if (
7255
error.response.data.statusCode === 401 &&
7356
error.response.data.message === 'jwt expired'
7457
) {
75-
await reNewToken(); //스토리지에서 토큰 받아서 재발급 받는 로직
76-
const accessToken = localStorage.getItem('accessToken');
58+
try {
59+
await reNewToken(); //스토리지에서 토큰 받아서 재발급 받는 로직
60+
const accessToken = localStorage.getItem('accessToken');
7761

78-
error.config.headers['Authorization'] = ` Bearer ${accessToken}`;
62+
error.config.headers['Authorization'] = `Bearer ${accessToken}`;
7963

80-
// 중단된 요청을(에러난 요청)을 토큰 갱신 후 재요청
81-
const response = await instance(error.config);
82-
return response;
64+
// 중단된 요청을(에러난 요청)을 토큰 갱신 후 재요청
65+
const response = await instance(error.config);
66+
return response;
67+
} catch (err) {
68+
console.log('리프레쉬에레ㅓ', err);
69+
if (axios.isAxiosError(err) && err.response) {
70+
//재발급 중 에러 발생 시
71+
if (
72+
(err.response.data.message === 'invalid token' &&
73+
err.response.data.statusCode === 400) ||
74+
(err.response.data.message === 'token not found' &&
75+
err.response.data.statusCode === 404) ||
76+
(err.response.data.message === 'token mismatch' &&
77+
err.response.data.statusCode === 401) ||
78+
(err.response.data.statusCode === 400 &&
79+
err.response.data.message === 'jwt must be provided')
80+
) {
81+
alert('로그인 갱신에 실패했습니다. 재 로그인 부탁드립니다.');
82+
window.location.href = '/';
83+
window.localStorage.clear();
84+
return;
85+
}
86+
}
87+
}
8388
}
84-
//클라이언트 access와 redis access가 다를 때, 없을 때
89+
//클라이언트 access와 redis access가 다를 때 || 없을 때
8590
if (
8691
(error.response.data.statusCode === 401 &&
8792
error.response.data.message === 'token mismatch') ||
88-
(error.response.data.statusCode === 404 &&
89-
error.response.data.message === 'token not found')
93+
(error.response.data.message === 'token not found' &&
94+
error.response.data.statusCode === 404)
9095
) {
9196
alert(error.response.data.message);
9297
window.location.href = '/';
93-
setTimeout(() => {
94-
window.localStorage.clear();
95-
}, 0);
98+
window.localStorage.clear();
99+
return;
96100
}
97101
} else if (
98-
error.response.data.message === 'jwt malformed' &&
99-
error.response.data.statusCode === 400
102+
error.response.data.statusCode === 400 &&
103+
error.response.data.message === 'jwt malformed'
100104
) {
101105
window.alert('로그인이 필요합니다.');
102106
window.location.href = '/';
103107
return;
108+
} else if (
109+
error.response.data.statusCode === 400 &&
110+
error.response.data.message === 'jwt must be provided'
111+
) {
112+
window.alert('토큰이 만료되었습니다.');
113+
window.location.href = '/';
114+
window.localStorage.clear();
115+
return;
104116
}
105-
return Promise.reject(error);
106-
// return error;
117+
return;
107118
},
108119
);
109120

src/apis/help.ts

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const HELP = {
6464
sortOrder: params.sortOrder,
6565
pageSize: params.pageSize,
6666
page: params.page,
67+
userId: params.userId && params.userId,
6768
},
6869
});
6970
return result.data.contents;

src/apis/mentor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const MENTOR = {
6363
loadOnlyPopular: params.loadOnlyPopular,
6464
orderField: params.orderField,
6565
sortOrder: params.sortOrder,
66-
userId: params.userId ? params.userId : undefined,
66+
userId: params.userId && params.userId,
6767
},
6868
});
6969
return result.data.contents;

src/apis/report.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { AxiosResponse } from 'axios';
2+
import instance from './axiosInstance';
3+
import { CreateReportRequestType } from '@/types/chat';
4+
5+
const REPORT = {
6+
path: `/users`,
7+
8+
/** 유저 신고하기 api [post] */
9+
async createUserReport(content: CreateReportRequestType): Promise<any> {
10+
const result: AxiosResponse = await instance.post(
11+
`${REPORT.path}/${content.userId}/reports`,
12+
{
13+
type: content.isCheck,
14+
report: content.report,
15+
},
16+
);
17+
return result;
18+
},
19+
};
20+
21+
export default REPORT;

src/components/common/Seo.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,29 @@ export default function Seo() {
77
rel="icon"
88
href="https://menbosha-s3.s3.ap-northeast-2.amazonaws.com/public/mainpage/titleLogo.svg"
99
/>
10+
<link
11+
rel="stylesheet"
12+
type="text/css"
13+
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/variable/pretendardvariable.css"
14+
/>
1015
<title>멘보샤</title>
1116
<meta
1217
name="naver-site-verification"
1318
content="f70d229d3e38d57d3101592c57fb452c85668743"
1419
/>
20+
<meta property="og:type" content="website" />
21+
<meta property="og:url" content="https://menbosha.kr/" />
22+
<meta property="og:title" content="멘보샤처럼 맛있게 우리의 멘토멘티" />
23+
<meta property="og:image" content="https://example.com/image.jpg" />
24+
<meta
25+
property="og:description"
26+
content="멘보샤 처럼 맛있는 멘토와 멘티를 진행해 보세요. 누구나 멘토가 될 수 있고, 누구나 멘티가 될 수 있습니다. "
27+
/>
28+
<meta property="og:site_name" content="멘보샤" />
29+
<meta property="og:locale" content="ko_KR" />
30+
31+
<meta property="og:image:width" content="1200" />
32+
<meta property="og:image:height" content="630" />
1533
</Head>
1634
);
1735
}

0 commit comments

Comments
 (0)