Skip to content

[김예인] 스프린트 미션 6#83

Open
yein0528 wants to merge 2 commits into
codeit-sprint-fullstack:react-김예인from
yein0528:react-김예인-sprint6

Hidden character warning

The head ref may contain hidden characters: "react-\uae40\uc608\uc778-sprint6"
Open

[김예인] 스프린트 미션 6#83
yein0528 wants to merge 2 commits into
codeit-sprint-fullstack:react-김예인from
yein0528:react-김예인-sprint6

Conversation

@yein0528

@yein0528 yein0528 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

기본 요구사항

중고마켓

  • mongoDB에서 PostgreSQL을 사용하도록 코드를 마이그레이션 해주세요.

공통

  • PostgreSQL를 이용해 주세요.
  • 데이터 모델 간의 관계를 고려하여 onDelete를 설정해 주세요.
  • 데이터베이스 시딩 코드를 작성해 주세요.
  • 각 API에 적절한 에러 처리를 해 주세요.
  • 각 API 응답에 적절한 상태 코드를 리턴하도록 해 주세요.

자유게시판

  • Article 스키마를 작성해 주세요.
  • id, title, content, createdAt, updatedAt 필드를 가집니다.
  • 게시글 등록 API를 만들어 주세요.
  • title, content를 입력해 게시글을 등록합니다.
  • 게시글 조회 API를 만들어 주세요.
  • id, title, content, createdAt를 조회합니다.
  • 게시글 수정 API를 만들어 주세요.
  • 게시글 삭제 API를 만들어 주세요.
  • 게시글 목록 조회 API를 만들어 주세요.
  • id, title, content, createdAt를 조회합니다.
  • offset 방식의 페이지네이션 기능을 포함해 주세요.
  • 최신순(recent)으로 정렬할 수 있습니다.
  • title, content에 포함된 단어로 검색할 수 있습니다.

댓글

  • 댓글 등록 API를 만들어 주세요.
  • content를 입력하여 댓글을 등록합니다.
  • 중고마켓, 자유게시판 댓글 등록 API를 따로 만들어 주세요.
  • 댓글 수정 API를 만들어 주세요.
  • PATCH 메서드를 사용해 주세요.
  • 댓글 삭제 API를 만들어 주세요.
  • 댓글 목록 조회 API를 만들어 주세요.
  • id, content, createdAt 를 조회합니다.
  • cursor 방식의 페이지네이션 기능을 포함해 주세요.
  • 중고마켓, 자유게시판 댓글 목록 조회 API를 따로 만들어 주세요.

@devbini devbini left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 고생 많으셨습니다!

이번 PR은 기존 프론트엔드 구현 위에 Express API부터 Prisma ORM, PostgreSQL까지 범위가 꽤 넓었는데... 모델을 나누고 각각 연결한 흐름까지, 처음 백엔드 관계형 모델링을 적용하는 단계치고 굉장히 잘 하신 것 같아요.

특히 onDelete: Cascade라던가 HTTP 요청 샘플까지 준비한 점은 다음 작업자가 프로젝트를 이해하는 데 큰 도움이 됩니다. 유지보수적으로도 좋고, 테스트할 때도 꽤 도움이 될 것 같아요.

그래도 실제 서비스 코드 관점에서는 API의 존재뿐 아니라, 잘못된 입력을 어떻게 막을지라거나, 페이지네이션이 실제 데이터가 늘어났을 때 어떻게 안정적으로 동작할지 조금 더 확인이 필요한 부분이 있기는 했어요. 그럼에도 이 부분은 조금만 정리해도 완성도가 많이 올라갈 것 같습니다.

또 기억에 남는 게, 로딩/에러 상태를 FE에서 분리해서 다루려는 부분도 좋았습니다. 특히 finally에서 로딩 상태를 끄는 흐름은 좋은 습관으로 보여요. 별도 훅을 만들어 검증하는 구조도 좋았고, 어느 정도 캡슐화에 대해서도 이해하고 응용할 줄 아는 것 같습니다.

앞으로도 기대가 되는 코드입니다.
너무나 고생 많으셨고, 파이팅입니다! 👍

tags,
})

navigate(`/items/${product._id}`)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Check Point

상품 등록 후 이동하는 페이지의 매개변수를 product._id로 쓰고 있네요?
제가 알기론 Prisma 데이터 응답 식별자가 _id가 아니라 id를 쓸 텐데
등록이 성공해도 이동하는 nav 주소가 undefined가 되는 불상사가 있을 수도 있을 것 같아요.

실제로 구동 시 문제가 없다면 괜찮겠지만
혹시 모르니 리뷰 남겨둘게요.

Comment thread server/app.js
Comment on lines +19 to +25
app.post('/products', async (req, res) => {
const product = await prisma.product.create({
data: req.body,
})

res.status(201).send(product)
})

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☕ Thinking

상품 등록에서 res body를 그대로 보내고 있네용
문법적으로 저장이 될 수는 있겠지만 (필드가 잘 되어있으니...)
실제로 API를 만든다고 했을 때는 각 데이터들이 요구사항 등에 맞는지 검증하는 단계를 추가하는 게 좋을 것 같아요.
FE쪽에서 넘어오는 데이터는 사용자가 마음만 먹으면 우회하거나 위조할 수 있고, 비정상적인 루트 (postman 등)에서도 실행할 수 있어서... 서버에서도 한번 더 체크 해 주는 습관이 있어도 좋지 않을까 싶습니다 🤗

Comment thread server/app.js
Comment on lines +29 to +30
const offset = Number(req.query.offset) || 0
const limit = Number(req.query.limit) || 10

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☕ Thinking

이것도 문제는 아니지만,
숫자를 바로 DB로 던지고 있는 것 같아요. 페이지네이션 관련 데이터를..

정상적인 상황에서는 문제가 없지만, 실제 환경에서는 어떤 문제가 나올지 몰라요.
예를 들어- limit 데이터가 음수로 들어간다거나, 비정상적으로 엄청 큰 데이터가 들어간다던가...

Math 라이브러리를 활용하면 아마 상/하 제한을 걸 수 있을텐데, 서버 리소스 보호를 생각하는 방법이 하나 더 있지 않을까 싶어 남겨둡니다ㅎㅎ

Comment thread server/app.js

const comments = await prisma.productComment.findMany({
where: { productId },
orderBy: { createdAt: 'desc' },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☕ Thinking

음, 음.. 이건 제 개인적인 경험에 빗대어 말씀드리는 거긴 합니다만

"동일한 시간대"의 데이터를 읽어오는 경우 꼬이는 경우가 종종 있어요.
거의 있을 수는 없겠지만, 그래도 정렬 기준을 하나만 잡기 보다는 유니크한 컬럼을 추가하여 두 개를 써 보는 것도 좋은 방법이지 않을까 싶어요!

예를 들면.. id 같은 컬럼이요!

Comment thread server/app.js
res.sendStatus(404);
} else {
console.error(err);
res.status(500).send({ message: err.message });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Check Point

음.. 이건 조금 위험해요.
요구사항에 500에 대한 응답 에러처리가 있어서 이렇게 해도 되는건지는 잘 모르겠지만..

500의 경우에는 DB 연결 내용이나 구현에 있어 치명적일 수 있는 서버 오류메시지가 사용자에게 그대로 전달되게 됩니다.

가능하면 message를 하드하게 별도로 만들거나, 에러핸들러를 따로 만들어서 관리하는 게 좋을 것 같아요.

블라인드 SQL 인젝션 등, 다양한 보안적 위험요소가 존재한답니다.

자세한 오류 로그는 서버 로그에만 남기는 게 좋아요! 🥹

Comment on lines +39 to +50
const handleAddTag = (e) => {
if (e.key !== 'Enter') return

e.preventDefault()

const newTag = tagInput.trim()
if (!newTag) return
if (tags.includes(newTag)) return

setTags([...tags, newTag])
setTagInput('')
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☕ Thinking

보니까- 실제 summit 폼 에서는 태그 저장 규칙이 있는 것 같아요. (5자 이내)
그런데, 실제 tag를 추가할 때는 그런 제약이 없는 것 같아 보입니다.

지금 구조라면 아주 긴 태그를 추가한 뒤- 등록 버튼을 눌렀을 때 에러가 나오는 느낌이라
UX적으로 조금 혼동이 있을 수 있어 보여요.

태그를 추가하는 시점에서 길이를 제한하는 등 제약사항을 넣어주면 좋지 않을까요?

</div>

<a href="/login" className={styles.loginButton}>
<NavLink to="/login" className={styles.loginButton}>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Check Point

React App Route에서 /login이 등록되지 않아 있네요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants