전체 글 60

채팅방-갤러리 탭 분리하기

이중 탭으로 구성된 채팅방 UI가 필요하다.현재 구조에서 채팅방을 두 개의 탭으로 나누고, 각 탭에서 서로 다른 콘텐츠(채팅 메시지 + 입력창 / 채팅방 갤러리)를 표시하려면 탭 컴포넌트를 별도로 분리하는 것이 유지보수성과 재사용성을 높이는 데 유리하다.탭 컴포넌트 분리하기탭의 전환을 관리하는 상태와 UI를 캡슐화한 Tabs 컴포넌트를 생성하자. 각 탭의 콘텐츠는 props.children 또는 특정 컴포넌트를 렌더링하도록 설계할 수 있다.ChatRoomPage 컴포넌트에서는 탭 컴포넌트를 사용해 두 개의 탭을 표시할 것이다.탭 1: 채팅 메시지, 채팅 입력창탭 2: 갤러리Tabs 컴포넌트 만들기import { useState } from "react";interface TabProps { labels..

채팅방 테이블 수정 / 멤버 수 제한

채팅방 데이터 테이블 스키마 수정chat_roomsroom_id(PK) user_id(FK) room_title room_subtitle room_description room_thumbnail_url room_hashtags isActive created_attypeuuiduuid(users table)texttexttexttexttext[]booltimestampzchat_members (복합 고유 키)member_id(PK) room_id(PK) isAdmin isActivetypeuuid(usres table)uuid(chat_rooms table)boolbool복합 고유 키 설정고민 과정: member_id와 room_id 의 조합이 고유해야 하므로, 중복 데이터를 방지하기 위한 방법이 필요했다..

카테고리 없음 2025.01.10

Funnel 패턴 공부하기

퍼널 패턴이란?퍼널 패턴은 단계별로 사용자 데이터를 입력받고 처리하는 과정을 설계하는 방법이다. 퍼널이라는 단어에서 유추할 수 있듯이, 여러 단계를 거치며 데이터를 점진적으로 모으고 필터링한다. 특히, 사용자 경험이 중요한 멀티스텝 폼이나 단계별 입력이 필요한 서비스(예: 회원가입, 예약 시스템)에서 유용하다.퍼널 패턴의 주요 특징단계적 데이터 관리:여러 단계를 나누어 데이터를 입력받고 처리한다.각 단계에서 입력된 데이터는 별도로 저장되고, 최종적으로 전체 데이터를 하나로 합친다.사용자 경험 최적화:한 번에 모든 데이터를 입력받기보다 단계를 나눠 부담을 줄인다.단계별로 사용자의 진행 상황을 보여줄 수 있다.유지보수성 향상:각 단계를 컴포넌트로 분리하여 독립적으로 관리 가능하다.비즈니스 로직과 UI를 명확..

카테고리 없음 2025.01.08

[최종 프로젝트] supabase realtime(1) Broadcast

Supabase RealtimeSupabase Realtime은 클라이언트와 데이터베이스 간에 실시간 동기화를 지원합니다. 이를 통해 사용자는 데이터가 변경된 부분을 즉시 반영할 수 있습니다. Realtime에는 세 가지 주요 작동 방식이 있습니다. Broadcast클라이언트 간에 메시지를 주고받는 기본 방식입니다.데이터베이스와 관계없이 클라이언트 간에 실시간 이벤트를 공유할 수 있습니다.채팅에서 실시간으로 메시지를 전송, 다수의 사용자에게 동시에 알림 보내기 가능// 채널이 특정 이벤트를 구독하도록 활성화하기// room/topic을 구독합니다. 채널은 'realtime'을 제외한 어떤 이름이든 사용 가능!const channelA = supabase.channel('room-1')// 수신한 메시지를..

카테고리 없음 2025.01.07

[최종 프로젝트] 기획 단계(3)

튜터님 피드백- 룩북에 대한 게시글을 작성하면서 사용자가 직접 상품에 대한 구매처까지 등록하는 것은 번거로움을 유발할 수 있을 듯 합니다. - 데이터가 필요하다면 크롤링을 시도해도 좋지만 기술적으로 구현이 어려울 수 있습니다. - 오픈 api를 활용한 룩북 가상 시착 시스템 커뮤니티로서의 속성을 강화해서 유저 중심의 기능이 추가되면 좋을 것 같습니다.   [Next.js] Puppeteer로 CSR 페이지 크롤링하기Chrome Headless 모드로 CSR 페이지 크롤링하기🤖velog.io Puppeteer란? Puppeteer는 Chrome DevTools 프로토콜을 이용해 Chrome/Chromium을 제어할 수 있는 Node.js 라이브러리로, 기본적으로 헤드리스 모드(백그라운드에서 UI 없이 브..

카테고리 없음 2025.01.03

[최종 프로젝트] 기획 단계(2)

오전 피드백- 검색 기능은 query parameter를 활용하기- 홈 페이지에서 너무 많은 기능을 처리하지 않도록 하기 위해 따로 페이지를 생성하는 방향 고려하기- npm 라이브러리(예시: 웹 에디터) 선정은 패키지 비교를 활용해서 선정하기- 개발자는 이전에 구현해봤던 기능 반, 해보지 않은 기능 반 정도를 도전해보기- 수정 사항은 회의를 거친 후 확정이 되었을때 진행하기 - 회의를 거치지 않고 수정한 기능/디자인은 갈등으로 이어질 수 있으므로 꼭 사전에 팀원들과 공유하기오후 피드백- 기능 개발 방식에 대한 논의- 필터링 구현 방식 2가지1. supabase query 날리기2. 모든 데이터 받아와서 필터링 - query parameter 구현할때 검색 페이지가 있는 것이 선호 마이 페이지-> pral..

카테고리 없음 2025.01.02

[최종 프로젝트] 기획 단계 (1)

프로젝트 명 : 피버러소개한 줄 정리 : 나의 스타일을 등록하고 다른 사람의 스타일 구매처를 확인하는 사이트내용 : 사용자들이 직접 코디한 룩을 등록하는프로젝트 핵심 기술룩북 형태로 스타일 사진을 업로드하고,오늘의 집 처럼 룩북 구매처를 연계시켜주는 어플리케이션, (상세 페이지 아래 부분에 작성자가 직접 등록하는 방식)커뮤니케이션 형성을 어플의 중심 기능으로 개발 예정CRUD 기능C: 자신만의 룩북 등록R: 다른 사람의 룩북 조회U: 룩 수정 및 코멘트 추가D: 룩북 삭제C: 자신만의 룩북 등록R: 다른 사람의 룩북 조회U: 룩 수정 및 코멘트 추가D: 룩북 삭제도전 개발 요소룩북별 스타일 점수 부여특정 룩북은 구매 가능 (즉시 거래)사용자 레벨업 시스템 (룩북 많이 교환할수록 상위 랭크)유튜브 룩북 큐..

카테고리 없음 2024.12.31

채팅 시스템 기록

Supabase 실시간 데이터 타입 불일치 문제문제: payload.new의 타입이 Message와 맞지 않아 TypeScript 에러 발생.원인: Supabase의 실시간 이벤트에서 반환된 데이터(payload.new)는 기본적으로 any 타입으로 처리되며, 정의된 Message 타입과 불일치. Supabase에서 반환된 데이터 타입을 명시적으로 캐스팅해줌.const message = payload.new as Message;  Supabase-React 채팅 메시지 순서 문제 해결문제: 채팅 모달을 닫았다가 다시 열면 메시지 순서가 뒤섞임. Supabase에서 메시지를 가져오는 과정과 실시간 업데이트 로직에서 발생한 문제로 생각됨.원인: fetchMessages 함수에서 Supabase 쿼리에 명시적..

postgres_changes로 전달된 데이터 타입

'(prev: { chatroom_id: string; content: string; created_at: string; id: string; sender_id: string; }[]) => ({ chatroom_id: string; content: string; created_at: string; id: string; sender_id: string; } | { ...; })[]' 형식의 인수는 'SetStateAction' 형식의 매개 변수에 할당될 수 없습니다. payload.new의 타입이 정확히 지정되지 않았기 때문에 에러가 발생한다. payload.new가 Supabase의 postgres_changes 이벤트로 전달된 데이터인데, 타입 추론이 제대로 이루어지지 않았다. payload.new에..

Zustand 모달 open/close

Zustand를 사용해서 모달 상태를 간단하고 효율적으로 관리할 수 있다. Zustand는 경량 상태 관리 라이브러리로, 전역 상태와 모달의 열림/닫힘 상태 관리에 적합하다.  1. Zustand 스토어를 설정해서 모달의 상태와 상태 변경 함수를 정의한다.import create from 'zustand';interface ModalState { isOpen: boolean; openModal: () => void; closeModal: () => void;}const useModalStore = create((set) => ({ isOpen: false, openModal: () => set({ isOpen: true }), closeModal: () => set({ isOpen: false..