한컴AI 2기

한컴AI 2기[스나이퍼팩토리] 한컴AI 2기 - AI개발자 교육 3주차

싱커 2025. 7. 18. 17:15

회원

카카오 소셜로그인을 구현해봤다.

성공한 결과 화면

전체 과정은 (1) 카카오 개발자 설정 → (2) Supabase 대시보드 설정 → (3) 프런트엔드 코드 구현 순으로 진행된다.

이하 서술은 내가 디스코드 스레드에 올린 내용대로.


1. 카카오 Developers 설정

먼저 카카오 개발자 센터에서 애플리케이션을 설정해야 합니다.

1. 카카오 개발자(Kakao Developers) 사이트에 접속해 로그인하고, **'내 애플리케이션'**으로 이동합니다.

2. 애플리케이션을 추가하거나 기존 애플리케이션을 선택합니다.

3. [제품] 메뉴에서 **'카카오 로그인'**을 활성화합니다.

4. [카카오 로그인] > [Redirect URI] 메뉴로 이동하여 Supabase의 콜백 URL을 등록합니다. URL 형식은 다음과 같습니다.
`https://<자신의-프로젝트-ID>.supabase.co/auth/v1/callback`

5. **[내 애플리케이션] > [앱 설정] > [요약 정보]**에서 **'REST API 키'**를 복사해 둡니다. 이것이 Supabase에서 '클라이언트 ID'로 사용됩니다.

 

2. Supabase 대시보드 설정

1. Supabase 대시보드로 이동하여 프로젝트를 선택합니다.

2. 왼쪽 메뉴에서 [Authentication] 탭으로 이동합니다.

3. [Providers] 섹션에서 **'Kakao'**를 찾아 활성화(Enable)합니다.

4. 'Client ID' 필드에 위에서 복사한 카카오의 **'REST API 키'**를 붙여넣습니다.

5. 'Client Secret'(클라이언트 시크릿)도 카카오 개발자 센터의 [카카오 로그인] > [보안] 탭에서 발급받아 입력합니다.

6. 설정을 **저장(Save)**합니다.


supabase.auth.signInWithOAuth 함수는 사용자가 카카오 계정으로 처음 로그인할 경우, Supabase의 auth.users 테이블에 해당 사용자 정보를 자동으로 생성해 줍니다. 따라서 별도의 회원가입 코드를 작성할 필요가없습니다.

 

그러나, 이후 게시글 쓰기 부분에서 user 값을 주려면 결국 별도의 user테이블이 필요했다...☆

 


게시글

topics 테이블 구조

id를 PK로 주고, title, category, thumbnail, content, updated_at을 추가로 줬다. content는 json으로 자료형을 설정하였다.

글을 발행하려면, (1) 컴포넌트의 각 입력 값을 상태(State)로 관리하고, (2) '토픽 발행하기' 버튼에 Supabase와 통신하는 함수를 연결해야한다.

토픽 작성 UI

 // '토픽 발행하기' 버튼 클릭 시 실행될 함수
    const handlePublish = async () => {
        // 유효성 검사
        if (!user) {
            toast.error("로그인이 필요합니다.");
            return;
        }
        if (!title.trim() || !category || !content) {
            toast.error("제목, 카테고리, 내용은 필수 입력 항목입니다.");
            return;
        }

        setIsSubmitting(true);
        try {
            let thumbnailUrl = null;

            // 4-1. 썸네일 파일이 있으면 Supabase Storage에 업로드
            if (thumbnailFile) {
                const filePath = `public/${user.id}/${Date.now()}_${thumbnailFile.name}`;
                const { error: uploadError } = await supabase.storage
                    .from("thumbnails") // 'thumbnails'는 스토리지 버킷 이름입니다.
                    .upload(filePath, thumbnailFile);

                if (uploadError) throw uploadError;

                // 4-2. 업로드된 파일의 공개 URL 가져오기
                const { data: urlData } = supabase.storage
                    .from("thumbnails")
                    .getPublicUrl(filePath);

                thumbnailUrl = urlData.publicUrl;
            }

            // 4-3. 모든 데이터를 topics 테이블에 삽입
            const { data: topicData, error: insertError } = await supabase
                .from("topics")
                .insert({
                    title,
                    category,
                    content,
                    thumbnail: thumbnailUrl,
                    // user_id 같은 컬럼이 있다면 user.id를 추가해주는 것이 좋습니다.
                })
                .select() // 삽입된 데이터를 반환받기 위해 .select() 추가
                .single();

            if (insertError) throw insertError;

            toast.success("토픽이 성공적으로 발행되었습니다!");
            // 발행 후 해당 토픽 상세 페이지로 이동
            navigate(`/topics/${topicData.id}`);

        } catch (error: any) {
            console.error("발행 중 오류 발생:", error);
            toast.error(`발행에 실패했습니다: ${error.message}`);
        } finally {
            setIsSubmitting(false);
        }
    };

클릭 시 발동하는 함수의 코드는 이러한 구조로 만들어진다.

코드의 방향성

State 관리: useState를 사용해 title, category, content, 썸네일 관련 정보들을 컴포넌트의 상태로 관리

 

blockUI에서 content가 처리되는 것은 해결하지 못했다. onChange가 감지를 하지 못한 문제 해결은 다음기회에...☆


슈퍼베이스 버킷

React-Youtube 프로젝트의 버킷

컨텐트와 썸네일을 담기위한 버킷을 만들었다. 썸네일 이미지는 이곳에 업로드된다.