묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨GraphQL 완전정복 (키오스크를 만들며 배우는 풀스택 과정) - [2024 부분 리뉴얼]
섹션7 디자인요소배치 이후 흰색화면..
선생님 안녕하세요,섹션7 디자인요소배치 코드를 따라쳤으나흰색 화면이 떠서 문의드렸습니다.https://github.com/jungsikjeong/smart-menu-study제가 여태까지 작성한 코드인데요.. 혹시 실수한 부분이있을까요?..선생님 강의 영상 코드랑 계속 대조해보기도하고,선생님 깃허브 코드랑 비교도해보고있는데..쉽지않네요..
-
미해결이미지 관리 풀스택(feat. Node.js, React, MongoDB, AWS)
Presigned URL 사용시 데이터베이스 저장 시점
데이터베이스 저장 시점현재 이미지 업로드 관련해서 프로젝트를 진행하고있는데, 이미지를 불러오기 위해 별도의 데이터베이스 저장이 필요해서 클라이언트에서 presigned URL을 사용하여 이미지 업로드가 완료된 후, 서버에 이미지 이름과 부가적인 정보를 보내주면 서버가 이를 데이터베이스에 저장하는 방식으로 구현하는게 맞을까요??
-
해결됨GraphQL 완전정복 (키오스크를 만들며 배우는 풀스택 과정) - [2024 부분 리뉴얼]
accessToken과 리프레시토큰 구현
토큰이 만료되면 리프레시토큰을 확인하고,리프레시토큰 기간이 남아있다면 access토큰을 재발급해주고,리프레시토큰도 유효기간이 끝났다면 로그아웃을 시켜주는 기능은어떤식으로 개발할 수 있을까요?..프론트쪽에서 서버에게 통신하는 방법이 궁금합니다..커리큘럼에 로그인 인증관련 제목이있어서 이런방법이있을줄알고 구매후 다섯시간가량 듣고있는데 없는거 같아서 절망스럽습니다ㅠ_ㅠ
-
해결됨Azure Native로 나만의 GPT 만들기
훌륭한 강의 입니다!!
너무 좋은 강의 입니다 ㅎㅎ강의 전달력도 좋고 단순 기술을 설명하기 보다 왜 이기술을 쓰는게 좋은지 논리적으로 설명해주셔서 이해가 잘되네요 ㅎㅎ앞으로도 계속 좋은 강의 부탁드립니다.사내에서 여러번 검증받고 피드백받은 흔적이 느껴지네요. 좋은 팀 좋은 회사에 계시는 것 같습니다.
-
해결됨Azure Native로 나만의 GPT 만들기
동형형 잘 들을게요
사랑해
-
미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
강의 다 듣고 수료증 받을 수 있죠?
강의 다 들으면 수료증 받을 수 있죠?제출해야되서요..
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 쇼핑몰 사이트 만들기[전체 리뉴얼]
파일 등록하면 이미지는 안나오고 파일명만 나와요..
import React from 'react'; import Dropzone from 'react-dropzone'; import axiosInstance from '../utils/axios'; const FileUpload = ({ onImageChange, images }) => { const handleDrop = async (files) =>{ let formData = new FormData(); const config = { header: {'content-type': 'multipart/form-data'} } formData.append('file', files[0]); try{ const response = await axiosInstance.post('/products/image', formData, config); onImageChange([...images, response.data.fileName]); }catch(error){ console.error(error); } } return ( <div className='flex gap-4'> <Dropzone onDrop={handleDrop}> {({ getRootProps, getInputProps }) => ( <section className='min-w-[300px] h-[300px] border flex items-center justify-center' > <div {...getRootProps()}> <input {...getInputProps()} /> <p className='text-3xl'> + </p> </div> </section> )} </Dropzone> <div className='flex-grow h-[300px] border flex items-center justify-center overflow-x-scroll overflow-y-hidden'> {images.map(image => ( <div key={image}> <img className='min-w-[300px] h-[300px]' src={`${import.meta.env.VITE_SERVER_URL}/${image}`} alt={image} /> </div> ))} </div> </div> ); }; export default FileUpload; 파일도 uploads에 다 들어가는데 파일명만 계속 나와요
-
미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
소셜로그인 User 테이블 관련 질문 있습니다.
소셜로그인을 구현하다가 의문점이 생긴 부분이 있어 어떠한 방식으로 접근하는 것이 궁금하여 질문을 남깁니다.상황일반 회원가입시에는, 이메일 비밀번호 + 해당 서비스에 필요한 필수 정보들을 받고, 해당 내용을 클라이언트로 부터 받아 user테이블에 저장하는 상황입니다.소셜 로그인 같은 경우에는, 정보를 받을 수 있는 것이 제한이 되어있어, 추가적으로 필요한 정보들을, 소셜 로그인 성공 이후, 클라이언트 측에서 회원가입시 필요한 정보들을 받을 수 있는 화면으로 이동시켜, 해당 정보를 받아서, 부족한 정보들을 채워넣는 것으로 알고 있습니다.궁금점.소셜로그인 로그인 후, 신규 유저이기에 서비스 이용에 필요한 필수 부가정보 입력을 받기위해, 회원가입 창으로 이동시켜, 부가 정보를 입력받는다면 크게 문제가 없습니다.하지만, 앱을 사용하다보면은 데이터가 끊긴다거나, 배터리가 방전된다거나, 알수없는 이유로, 로그인은 되었으나, 필수 부가정보를 입력하지 못하고, 꺼지는 경우가 있습니다. 필수 부가정보를 꼭 받아야 하는 경우라면 이 부분에 대해서 어떻게 처리해야하나요?필수 정보를 채웠는지 여부를 확인하는 column을 boolean으로 User 테이블에 추가하여, 클라이언트에서 해당 Column으로 부가정보를 입력받지 않았으면 메인화면으로 가지않고, 회원가입 스크린으로 리다이렉 시키는 이런 로직을 작성해야하나요?필수 정보를 채웠는지 여부를 확인하는 column 없이 이런 경우에 처리할 수 있는 방안이 있는지 궁금하고, 현업에서는 어떤식으로 테이블을 설계하는지 궁금합니다!
-
미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
SequelizeEagerLoadingError: User is not associated to Post!
안녕하세요 제로초님, User 테이블이랑 Post테이블이 관계설정이 안되어있다는 에러가 떠서 문의드립니다. 분명 시퀄라이즈 관계설정하는 부분 빠짐없이 모두 따라했는데 이런 오류가 뜹니다.
-
미해결이미지 관리 풀스택(feat. Node.js, React, MongoDB, AWS)
이미지 등록시 자동 등록 오류
이미지 등록시에 아래 사진과 같이 이미지가 리스트에 등록이 되긴하는데 이미지 형태가 깨져서 등록이 됩니다. 새로고침을 해야 정상적으로 반영되는 오류가 있는데 어느 코드가 잘못된지를 모르겠습니다ㅠㅠhttps://github.com/jjeongdong/ImageUpload_front
-
미해결파이썬 Streamlit 활용한 웹 자동화 업무, 데이터 검색 및 시각화
Streamlit 오류
사진의 동그라미 부분이 왜 이렇게 나오는 걸까요?
-
미해결배달앱은 어떻게 내 주변의 맛집을 찾을까?
강사님께서 entity를 사용하신 이유가 궁금합니다
안녕하세요강사님의 강의를 수강 중인 주니어 개발자입니다!요즘 디자인 패턴을 공부하면서 강사님 강의를 듣다보니까 궁금한 점이 생겼습니다저는 요즘 service, repo, controller(apis) + dto 기반의 간단한 레이어드 기반 아키텍처를 차용해서 디렉토리를 구성하고 있는데요아직 DDD를 조금 밖에 학습하지 않아, 잘은 모르지만,entity를 사용한 강사님 코드를 보면, DDD가 많이 떠오릅니다entities가 도메인 객체인 것 같은 느낌도 들고요그래서 그런지 강의를 절반 이상 2번씩 들은 지금도강사님의 디렉토리 구조가 익숙치 않습니다 강사님께서 이 강의를 만드실 때, 디렉토리 구조를 entity 기반으로 만드신 이유가 따로 있으실까요?강사님께서 디렉토리 구조를 구성할 때, 어떤 방식으로 디렉토리 구조를 구성하시는 지도 궁금합니다 ㅎㅎ
-
미해결기획자님 이 정도 웹 개발은 배워보면 어떨까요? [이론+실습]
mongoDB에서의 데이터 중복일 때 1건만 수정되는 이유
CRUD 실습 - 2 중 문의사항이 있어 작성합니다.제가 실수로 이전 CREATE 에서 두번 실행하는 바람에 현재 제 DB에 데이터가 중복으로 들어갔습니다. 그리고 현재 UPDATE를 하였을 때 데이터가 한 건만 수정되는 것을 확인하였습니다.원래대로라면 '김현수'라는 이름을 가진 데이터가 2건이기 때문에 2건 모두 바뀌어야 하는 거 아닐까요? 왜 1건만 변경되는 지 문의드립니다.
-
해결됨파이썬 Streamlit 활용한 웹 자동화 업무, 데이터 검색 및 시각화
OMDb API Url
OMDb API url 주소 작성방법 알려주세요. API key를 발급 받았는데 유효한 key가 아니라고 합니다.
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 유튜브 사이트 만들기
자료 없음
https://github.com/jaewonhimnae/%20boilerplate-mern-stack this is not the ~~~~~ 없네요 자료를 다운받을 수 없는 것인가요?
-
해결됨MongoDB를 활용하여, 200억건 이상의 데이터 파이프라인 작성법
여러 thread에서 Upsert를 실행하면 괜찮을까요?
MYSQL 강의에서는 ON DUPLICATE KEY UPDATE 를 쓰면 여러 쓰레드에서 호출시, lock이 걸릴 수 있다고 강의에서 보았습니다 혹시 몽고DB는 여러 thread에서 upsert 시도시, lock이슈가 있을까요>?
-
미해결코로나맵 개발자가 알려주는 React + Express로 지도서비스 만들기 (Typescript)
MongoDB Compass 관련 질문
MongoDB compass에서 new connection에서 말씀하신 대로 mern, merntest, admin 이렇게 설정해주고, connect 버튼을 눌렀는데 Authentication failed라는 오류가 뜹니다. 어느 부분에서 오류가 난 건가요..?
-
해결됨200억건의 데이터를 MySQL로 마이그레이션 할 때 고려했던 개념과 튜닝 방법
안녕하세요 좋은 강의 감사합니다. 혹시 실습 코드는 따로 제공 안되나요??
강의 영상에 나오는 실습 코드도 공유해주시면 정말 감사드리겠습니다 :)
-
미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
실시간 채팅방에서 GIF uploads 하면 GIF가 바로 화면에 보이지 않고 새로 고침을 해야 보이는데 어떻게 해야 할까요?
실시간 채팅방 강좌 코드를 작성하여 작동 시켜 본 결과 메시지 전송 까지는 잘 되는 것을 확인 하였는데 GIF 업로드 시 다음 그림과 같은 현상이 발생하고 있습니다그림 하단에 표시한 부분 처럼 처음에 GIF 올리기를 하면 그림이 보이지 않다가 새로 고침을 하면 위의 다른 GIF 처럼 잘 보이긴 하는데 무슨 문제 일까요?참고로 관련 코드를 같이 올립니다chat.html {% extends 'layout.html' %} {% block content %} <h1>{{title}}</h1> <a href="/" id="exit-btn">방 나가기</a> <fieldset> <legend>채팅 내용</legend> <div id="chat-list"> {% for chat in chats %} {% if chat.user === user %} <div class="mine" style="color: {{chat.user}}"> <div>{{chat.user}}</div> {% if chat.gif %}} <img src="/gif/{{chat.gif}}"> {% else %} <div>{{chat.chat}}</div> {% endif %} </div> {% elif chat.user === 'system' %} <div class="system"> <div>{{chat.chat}}</div> </div> {% else %} <div class="other" style="color: {{chat.user}}"> <div>{{chat.user}}</div> {% if chat.gif %} <img src="/gif/{{chat.gif}}"> {% else %} <div>{{chat.chat}}</div> {% endif %} </div> {% endif %} {% endfor %} </div> </fieldset> <form action="/chat" id="chat-form" method="post" enctype="multipart/form-data"> <label for="gif">GIF 올리기</label> <input type="file" id="gif" name="gif" accept="image/gif"> <input type="text" id="chat" name="chat"> <button type="submit">전송</button> </form> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script> const socket = io.connect('http://localhost:8005/chat', { path: '/socket.io', }); socket.emit('join', new URL(location).pathname.split('/').at(-1)); socket.on('join', function (data) { const div = document.createElement('div'); div.classList.add('system'); const chat = document.createElement('div'); div.textContent = data.chat; div.appendChild(chat); document.querySelector('#chat-list').appendChild(div); }); socket.on('exit', function (data) { const div = document.createElement('div'); div.classList.add('system'); const chat = document.createElement('div'); div.textContent = data.chat; div.appendChild(chat); document.querySelector('#chat-list').appendChild(div); }); socket.on('chat', function (data) { const div = document.createElement('div'); if (data.user === '{{user}}') { div.classList.add('mine'); } else { div.classList.add('other'); } const name = document.createElement('div'); name.textContent = data.user; div.appendChild(name); if (data.chat){ const chat = document.createElement('div'); chat.textContent = data.chat; div.appendChild(chat); } else { const gif = document.createElement('img'); gif.sr = '/gif/' + data.gif; div.appendChild(gif); } div.style.color = data.user; document.querySelector('#chat-list').appendChild(div); }); document.querySelector('#chat-form').addEventListener('submit', function (e) { e.preventDefault(); if (e.target.chat.value) { axios.post('/room/{{room._id}}/chat', { chat: this.chat.value, }) .then( () => { e.target.chat.value = ''; }) .catch( (err) => { console.error(err); }); } }); document.querySelector('#gif').addEventListener('change', function (e) { console.log('******',e.target.files); const formData = new FormData(); formData.append('gif', e.target.files[0]); axios.post('/room/{{room._id}}/gif', formData) .then( () => { e.target.file = null; }) .catch( (err) => { console.error(err); }); }); </script> {% endblock %} routes/index.jsconst express = require('express'); const { renderMain, renderRoom, createRoom, enterRoom, removeRoom, sendChat, sendGif } = require('../controllers'); const multer = require('multer'); const fs = require('fs'); const path = require('path'); const router = express.Router(); router.get('/', renderMain); router.get('/room', renderRoom); router.post('/room', createRoom); router.get('/room/:id', enterRoom); router.delete('/room/:id', removeRoom); router.post('/room/:id/chat', sendChat); try {fs.readdirSync('uploads'); } catch (err) { console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.'); fs.mkdirSync('uploads'); } const upload = multer({ storage: multer.diskStorage({ destination(req, file, done) { done(null, 'uploads/'); }, filename(req, file, done ) { const ext = path.extname(file.originalname); done(null, path.basename(file.originalname, ext) + Date.now() + ext); }, }), limits: {fileSize: 5 * 1024 *1024 }, }) router.post('/room/:id/gif', upload.single('gif'), sendGif); module.exports = router;controllers/index.jsconst Room = require('../schemas/room'); const Chat = require('../schemas/chat'); const { removeRoom: removeRoomService } = require('../services'); exports.renderMain = async ( req, res, next ) => { try{ const rooms = await Room.find({}); res.render('main', {rooms, title: 'GIF 채팅방'}); } catch (error) { console.error(error); next(error); } }; exports.renderRoom = ( req, res, next ) => { res.render('room', { title: 'GIF 채팅방 생성'}); }; exports.createRoom = async ( req, res, next ) => { try{ const newRoom = await Room.create({ title: req.body.title, max: req.body.max, owner: req.session.color, password: req.body.password, //session data 에서 옮 }); const io = req.app.get('io'); io.of('/room').emit('newRoom', newRoom); // 방에 들어가는 부분 if (req.body.password ) { res.redirect(`/room/${newRoom._id}?password=${req.body.password}`); } else { res.redirect(`/room/${newRoom._id}`); } } catch (error) { console.error(error); next(error); } }; exports.enterRoom = async( req, res, next ) => { try{ const room = await Room.findOne({_id: req.params.id}); if (!room){ return res.redirect('/?error=존재하지 않는 방입니다.'); } if (room.password && room.password !== req.query.password ){ return res.redirect('/?error=비밀번호가 틀렸습니다.'); } const io = req.app.get('io'); const { rooms } = io.of('/chat').adapter; if (room.max <= rooms.get(req.params.id)?.size) { return res.redirect('/?error=허용 인원을 초과하였습니다.'); } const chats = await Chat.find({room: room._id }).sort('createdAt'); res.render('chat', { title: 'GIF 채팅방 생성', chats , room, user: req.session.color }); } catch (error) { console.error(error); next(error); } }; exports.removeRoom = async ( req, res, next ) => { try { await removeRoomService(req.params.id ); res.send('ok'); setTimeout(() => { req.app.get('io').of('/room').emit('removeRoom', req.params.id); }, 2000) } catch (error) { console.error(error); next(error); } }; exports.sendChat = async (req, res, next ) =>{ try { const chat = await Chat.create({ room: req.params.id, user: req.session.color, chat: req.body.chat, }); req.app.get('io').of('/chat').to(req.params.id).emit('chat', chat); res.send('ok'); } catch( error ){ console.error(error); next(error); } } exports.sendGif = async (req, res, next ) => { try { const chat = await Chat.create({ room : req.params.id, user: req.session.color, gif: req.file.filename, }) setTimeout(() => { req.app.get('io').of('/chat').to(req.params.id).emit('chat',chat); }, 1000); res.send('ok'); } catch (error) { console.error(error); next(error); } } [제로초 강좌 질문 필독 사항입니다]질문에는 여러분에게 도움이 되는 질문과 도움이 되지 않는 질문이 있습니다.도움이 되는 질문을 하는 방법을 알려드립니다.https://www.youtube.com/watch?v=PUKOWrOuC0c0. 숫자 0부터 시작한 이유는 1보다 더 중요한 것이기 때문입니다. 에러가 났을 때 해결을 하는 게 중요한 게 아닙니다. 왜 여러분은 해결을 못 하고 저는 해결을 하는지, 어디서 힌트를 얻은 것이고 어떻게 해결한 건지 그걸 알아가셔야 합니다. 그렇지 못한 질문은 무의미한 질문입니다.1. 에러 메시지를 올리기 전에 반드시 스스로 번역을 해야 합니다. 번역기 요즘 잘 되어 있습니다. 에러 메시지가 에러 해결 단서의 90%를 차지합니다. 한글로 번역만 해도 대부분 풀립니다. 그냥 에러메시지를 올리고(심지어 안 올리는 분도 있습니다. 저는 독심술사가 아닙니다) 해결해달라고 하시면 아무런 도움이 안 됩니다.2. 에러 메시지를 잘라서 올리지 않아야 합니다. 입문자일수록 에러메시지에서 어떤 부분이 가장 중요한 부분인지 모르실 겁니다. 그러니 통째로 올리셔야 합니다.3. 코드도 같이 올려주세요. 다만 코드 전체를 다 올리거나, 깃헙 주소만 띡 던지지는 마세요. 여러분이 "가장" 의심스럽다고 생각하는 코드를 올려주세요.4. 이 강좌를 바탕으로 여러분이 응용을 해보다가 막히는 부분, 여러 개의 선택지 중에서 조언이 필요한 부분, 제 경험이 궁금한 부분에 대한 질문은 대환영입니다. 다만 여러분의 회사 일은 질문하지 마세요.5. 강좌 하나 끝날 때마다 남의 질문들을 읽어보세요. 여러분이 곧 만나게 될 에러들입니다.6. 위에 적은 내용을 명심하지 않으시면 백날 강좌를 봐도(제 강좌가 아니더라도) 실력이 늘지 않고 그냥 코딩쇼 관람 및 한컴타자연습을 한 셈이 될 겁니다.
-
미해결이미지 관리 풀스택(feat. Node.js, React, MongoDB, AWS)
강의에 사용된 코드 다운 받는 사이트 주소 있나요?
강의에 사용된 코드 다운 받는 사이트 주소 있나요?