안녕하세요
${site.name}에 가입해 주셔서 감사합니다!
계정을 활성화하려면 아래 버튼을 클릭하여 이메일 주소를 인증해 주세요.
만약 버튼이 작동하지 않는다면, 아래 링크를 복사하여 주소창에 붙여넣고 엔터를 눌러 주세요.
${site.validUrl}
<준비>
1.API 명세
사전 준비를 하는 과정에서 가장 많이 반성하는 것은 충분한 대화를 하지 않고 실제 프로젝트에 투입했다는 것이다.
충분한 대화를 하지 않으면 프로젝트에 대한 공감대가 형성되지 않고, 결과적으로 싱크가 맞지 않게 되는 것 같다.
다음 프로젝트에서는 충분한 대화를 거쳐 공감대를 형성한 후에 프로젝트를 시작해야겠다.
<프로젝트 중>
1. 나는 1시간 ~ 3시간 정도 단위로 계속해서 팀원들의 진행 상황을 점검하였다. 필요한 점, 어려운 점, 원하는 점을 지속적으로 체크하며 이에 맞추어 유동적으로 업무 분장을 바꾸며 프로젝트를 진행하였다. 나쁘지 않은 방식이었다고 생각한다.
그래서 결론을 말하자면 좋은 팀이었다고 생각한다. 소통에 막힘이 없었기 때문에 우리의 의사결정은 항상 빨랐고, 아무리 늦어도 10분 안에 결정됐다. 프로젝트 진행 중에는 모두가 각자의 자원을 최대한 활용했고, 최선을 다했다. 그래서 명예의 전당 같은 아직 생소하고 어려운 개념을 시도했음에도 불구하고 우리는 유의미한 결과를 낼 수 있었다.
만약 이들과 또다시 이 팀을 해야 한다 해도, 난 좋다고 생각한다.
<코드 리뷰>
<좋아요>
const transporter = nodemailer.createTransport({
service: "Naver",
host: "smtp.naver.com",
port: 587,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
});
const emailTemplate = (code) => {
const site = {
name: "TravAll",
validUrl: http://localhost:${process.env.PORT}/api/emailValid?code=${code}
,
};
return `
${site.name}이메일 인증export const emailCodeTransporter = (code, email) => {
const mailOptions = {
from: process.env.EMAIL_USER, // 발신자
to: email, // 수신자
subject: "TravAll 인증 코드 발송", // 제목
html: emailTemplate(code), // 본문
};
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
console.log(err);
} else {
console.log("Email sent: " + info.response);
}
});
};
<refreshToken/accessToken>
import jwt from "jsonwebtoken";
import { prisma } from "../utils/prisma/index.js";
import "dotenv/config"
const { TOKEN_SECRET_KEY } = process.env;
export const createEmailToken = (userData) => {
return jwt.sign(userData, TOKEN_SECRET_KEY, {
expiresIn: "1h"
})
}
/**
* @param {Object} userData
* @returns {String}
*/
export const createAccessToken = (userData) => {
return jwt.sign(userData, TOKEN_SECRET_KEY, {
expiresIn: "12h",
});
};
/**
* @param {String} token
* @returns {Object}
*/
export const verifyToken = (token) => {
try {
return jwt.verify(token, TOKEN_SECRET_KEY);
} catch (err) {
throw err;
}
};
/**
* @param {Object} userData
* @returns {String}
*/
export const createRefreshToken = (userData) => {
return jwt.sign(userData, TOKEN_SECRET_KEY, {
expiresIn: "2d",
});
};
export const generateTokens = async (res, userData) => {
const accessToken = createAccessToken(userData);
const refreshToken = createRefreshToken(userData);
res.cookie("accessToken", accessToken);
res.cookie("refreshToken", refreshToken);
const user = await prisma.refreshToken.findFirst({
where: {
userId: userData.userId,
},
});
if (user) {
await prisma.refreshToken.update({
where: {
userId: userData.userId,
},
data: {
refreshToken,
},
});
}else{
await prisma.refreshToken.create({
data:{
userId: userData.userId,
refreshToken
}
})
}
return { accessToken, refreshToken };
};
<-ejs->
<%- -%> 는 서버사이드 렌더링 데이터이다. 받아서 요긴하게 사용할 수 있다.(핸들바라는게 있다는데 이거보다 좋은 거라고 한다. 다음 프로젝트때 써봐야지)
fetch를 통해서 통신할 때는 JSON 데이터형 자료의 경우 문자열로 바꿔서 보내야 한다.(그게 fetch의 작동 방식이다)
참고로 fetch는 인섬니아라고 생각하면 편하다. fetch(url, options)는 인섬니아 본체, url은 fetch에서 경로 적는 곳, options는 req body, headers 등이다.
여기서 보이는 것 처럼, fetch등의 함수를 통해 라우터를 호출하는 것이 가장 안정적이고 좋다. 프론트와 서버를 연결할 땐 가급적 router, 즉 서버에서 return을 render로 하지 말자.(조금만 잘못하면 바로 에러가 난다.)
- ejs 등의 프론트에서 router로 요청을 보내고, router는 이에 대한 응답을 response 객체에 담아 보내고 종료하도록 해야 한다.
- res.render(), res.redirect는 가급적 사용하지 않는 것이 좋음.
ejs >> fetch >> router >> router의 return >> ejs >> ejs에서 다른 ejs로 리다이렉트, 혹은 fetch를 다시 써서 필요한 router로 다시 요청 전송 >>.... 필요한 만큼 반복
패스포트는 여기엔 적지 않겠다. 아직 이해도 제대로 안돼서, 다음 프로젝트 때 써보고 기록해야지
협업에서 설계와 문서화, 그리고 소통은 너무 중요하죠.
회사에 가시면 같은 개발자 뿐만 아니라 디자이너, PM/PO, 마케터 등
각자 다른 배경 지식을 가지고 있는 사람들과 함께 일해야하기 때문에
이런 것들이 더욱 중요해지는 것 같습니다.
앞으로도 계속 많은 시행착오 겪어보시기 바랍니다!