테이블명: projects
포함될 컬럼:
- 프로젝트이름: project_name
- 개발환경: development_environment
- 프로젝트 기간: project_duration
- url: project_url
- 깃허브 url: github_url
- 프로젝트 설명: description
- 코멘트: comments
1. Supabase 대시보드에서 projects 테이블 생성하기
순서:
- Supabase 대시보드 접속 후 해당 프로젝트로 이동합니다.
- 왼쪽 사이드바에서 Table Editor (테이블 에디터) 아이콘을 클릭합니다.
- 화면 중앙 또는 상단의 + New table (새 테이블) 버튼을 클릭합니다.
테이블 설정 (New table 팝업창):
- Name: projects 입력
- Description: (선택 사항) 사용자의 포트폴리오 프로젝트 정보를 저장합니다. 입력
- Schema: public (기본값)
- Enable Row Level Security (RLS): 체크된 상태 그대로 유지합니다. (매우 중요!)
컬럼(Column) 추가:
이제 아래 명세에 따라 + Add Column 버튼을 눌러 각 컬럼을 추가합니다.
컬럼 이름 (Name)데이터 타입 (Type)기본값 (Default Value)기본 키 (Is Primary Key)NULL 허용 (Is Nullable)고유값 (Is Unique)설명 (비고)
| id | uuid | gen_random_uuid() (함수 선택) | ✓ (체크) | X (체크 해제) | X (체크 해제) | 테이블의 고유 식별자 |
| project_name | text | (비워둠) | X | X | X | 프로젝트의 이름 (필수) |
| development_environment | text | (비워둠) | X | X | X | React, Vue, Next.js 등 개발 환경 (필수) |
| project_duration | text | (비워둠) | X | X | X | 프로젝트 기간 (예: 2023.01 ~ 2023.03) |
| project_url | text | (비워둠) | X | ✓ (체크) | X | 배포된 프로젝트 URL (선택 사항) |
| github_url | text | (비워둠) | X | ✓ (체크) | X | GitHub 저장소 URL (필수) |
| description | text | (비워둠) | X | ✓ (체크) | X | 프로젝트 상세 설명 (필수) |
| comments | text | (비워둠) | X | ✓ (체크) | X | 기타 코멘트 (선택 사항) |
Project 인터페이스 TypeScript 정의
// src/types/supabase.ts
/**
* Supabase 'projects' 테이블의 데이터 구조를 정의
*/
export interface Project {
id: string;
project_name: string;
development_environment: string[];
project_duration: string;
project_url: string | null;
github_url: string;
description: string;
comments: string[] | null;
// --- 새로 추가된 배열 타입 컬럼 ---
additional_urls: string[] | null; // 기타 URL들 (문자열 배열 혹은 null)
// --- 새로 추가된 배열 타입 컬럼 ---
}
/**
* 프로젝트 생성 또는 업데이트 시 필요한 데이터를 정의하는 타입
*/
export type NewProject = Omit<Project, 'id' | 'created_at'>;
/**
* Supabase에서 데이터를 조회할 때 반환될 수 있는 모든 테이블의 타입을 모아둔 Database
*/
export type Database = {
public: {
Tables: {
projects: {
Row: Project;
Insert: Omit<Project, 'id' | 'created_at'>;
Update: Partial<Omit<Project, 'id' | 'created_at'>>;
};
};
};
};
TypeScript 정의 활용 예시
import { supabase } from '@/lib/supabaseClient'; // Supabase 클라이언트 초기화 파일
import type { Project, NewProject } from '@/types/supabase';
// 프로젝트 목록 가져오기
async function fetchProjects(): Promise<Project[] | null> {
const { data, error } = await supabase
.from('projects')
.select('*')
.order('created_at', { ascending: false }); // 최신순 정렬
if (error) {
console.error('프로젝트 조회 중 오류 발생:', error.message);
return null;
}
return data as Project[]; // 가져온 데이터를 Project 타입으로 캐스팅
}
// 새 프로젝트 추가하기
async function addProject(newProjectData: NewProject): Promise<Project | null> {
const { data, error } = await supabase
.from('projects')
.insert([newProjectData])
.select() // 삽입된 데이터 반환받기
.single(); // 단일 객체로 받기
if (error) {
console.error('프로젝트 추가 중 오류 발생:', error.message);
return null;
}
return data as Project;
}
// 사용 예시
async function runExample() {
// 프로젝트 가져오기
const myProjects = await fetchProjects();
if (myProjects) {
console.log('내 프로젝트 목록:', myProjects);
}
import { supabase } from '@/lib/supabaseClient';
import type { Project, NewProject } from '@/types/supabase';
// 새 프로젝트 추가 예시
const projectToAdd: NewProject = {
project_name: '나의 포트폴리오 사이트',
development_environment: ['Nuxt 4', 'Vue 3', 'TypeScript', 'Tailwind CSS', 'Supabase'],
project_duration: '2024.07 ~ 2024.08',
project_url: 'https://my-portfolio.com',
github_url: 'https://github.com/jey/my-portfolio',
description: '개인 역량과 프로젝트 경험을 보여주는 포트폴리오 사이트입니다.',
comments: ['이 프로젝트를 통해 Supabase 연동 경험을 쌓았습니다.', '반응형 디자인에 중점을 두었습니다.'],
additional_urls: [ // 여기에 기타 URL들을 배열로!
'https://notion.so/my-portfolio-planning',
'https://figma.com/my-portfolio-design'
],
};
// addProject(projectToAdd); // 이 함수를 호출하여 데이터 삽입
<script setup lang="ts">
defineProps<{
name: string;
description: string | null;
project_url: string | null;
github_url: string | null;
development_environment: string[] | null;
}>();
</script>
<template>
<div class="rounded-lg border p-4 hover:shadow">
<h3 class="text-lg font-semibold">{{ name }}</h3>
<p class="mt-2 text-sm text-gray-600" v-if="description">{{ description }}</p>
<div class="mt-3 flex flex-wrap gap-2" v-if="development_environment?.length">
<span class="rounded bg-gray-100 px-2 py-0.5 text-xs" v-for="tag in development_environment" :key="tag">{{ tag }}</span>
</div>
<div class="mt-3 flex gap-3 text-sm">
<a v-if="project_url" :href="project_url" target="_blank" class="text-blue-600 hover:underline">Demo</a>
<a v-if="github_url" :href="github_url" target="_blank" class="text-blue-600 hover:underline">GitHub</a>
</div>
</div>
</template>