@restnfeel/agentc-starter-kit
Version:
한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템
347 lines (258 loc) • 8.47 kB
Markdown
AgentC Starter Kit에서 Supabase를 백엔드로 사용하는 완전한 설정 가이드입니다.
- [Supabase 프로젝트 생성](
- [환경 변수 설정](
- [데이터베이스 설정](
- [인증 설정](
- [스토리지 설정](
- [보안 정책](
- [API 사용법](
1. [Supabase Dashboard](https://supabase.com/dashboard) 접속
2. "New Project" 클릭
3. 프로젝트 정보 입력:
- **Project Name**: `customer-website`
- **Database Password**: 강력한 비밀번호 생성 (저장 필요!)
- **Region**: `Asia Pacific (Seoul)` 선택 (한국 사용자용)
### 2. 프로젝트 정보 확인
프로젝트 생성 후 다음 정보를 복사:
1. **Settings > API**에서:
- Project URL
- anon/public key
- service_role key (관리자용)
2. **Settings > Database**에서:
- Connection string
## 🔧 환경 변수 설정
### .env.local 파일 생성
```env
# Supabase Configuration
DATABASE_URL="postgresql://postgres:[YOUR-PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres"
SUPABASE_URL="https://[PROJECT-REF].supabase.co"
SUPABASE_ANON_KEY="eyJ..."
SUPABASE_SERVICE_ROLE_KEY="eyJ..."
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="your-nextauth-secret-key"
UPLOAD_MAX_SIZE="10485760"
UPLOAD_ALLOWED_TYPES="image/*,video/*,application/pdf"
GOOGLE_ANALYTICS_ID="G-XXXXXXXXXX"
```
| 변수명 | 설명 | 필수 |
|--------|------|------|
| `DATABASE_URL` | PostgreSQL 연결 문자열 | ✅ |
| `SUPABASE_URL` | Supabase 프로젝트 URL | ✅ |
| `SUPABASE_ANON_KEY` | 공개 API 키 | ✅ |
| `SUPABASE_SERVICE_ROLE_KEY` | 관리자 API 키 | 🔒 |
| `NEXTAUTH_SECRET` | 인증 암호화 키 | ✅ |
```bash
npx prisma db push
npx prisma generate
npx prisma studio
```
```sql
-- 관리자 사용자 생성 (Supabase SQL Editor에서 실행)
INSERT INTO users (id, email, name, role) VALUES
('admin-user-id', 'admin@example.com', 'Admin User', 'ADMIN');
-- 기본 페이지 생성
INSERT INTO pages (title, slug, content, published) VALUES
('홈페이지', 'home', '메인 페이지 콘텐츠', true),
('회사 소개', 'about', '회사 소개 콘텐츠', true);
```
**Authentication > Settings**에서:
1. **Site URL**: `http://localhost:3000` (개발용)
2. **Redirect URLs**: `http://localhost:3000/auth/callback`
3. **이메일 템플릿** 커스터마이징 (선택사항)
**Authentication > Providers**에서 원하는 제공자 활성화:
- Google OAuth
- GitHub OAuth
- Discord OAuth
```typescript
// lib/auth.ts
import { createClient } from '@supabase/supabase-js';
import { SupabaseAdapter } from '@auth/supabase-adapter';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
export const authOptions = {
adapter: SupabaseAdapter({
url: process.env.SUPABASE_URL!,
secret: process.env.SUPABASE_SERVICE_ROLE_KEY!,
}),
providers: [
// 인증 제공자 설정
],
};
```
**Storage**에서 다음 버킷 생성:
1. **`media`** - 이미지, 비디오 파일
2. **`documents`** - PDF, 문서 파일
3. **`uploads`** - 일반 업로드 파일
```sql
-- 미디어 버킷 공개 읽기 허용
UPDATE storage.buckets
SET public = true
WHERE id = 'media';
-- 인증된 사용자만 업로드 허용
CREATE POLICY "Authenticated users can upload" ON storage.objects
FOR INSERT TO authenticated
WITH CHECK (bucket_id = 'media');
-- 모든 사용자 읽기 허용
CREATE POLICY "Public read access" ON storage.objects
FOR SELECT TO public
USING (bucket_id = 'media');
```
```typescript
// app/api/upload/route.ts
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
export async function POST(request: Request) {
const formData = await request.formData();
const file = formData.get('file') as File;
const { data, error } = await supabase.storage
.from('media')
.upload(`uploads/${Date.now()}-${file.name}`, file);
if (error) {
return Response.json({ error: error.message }, { status: 500 });
}
return Response.json({
url: `${process.env.SUPABASE_URL}/storage/v1/object/public/media/${data.path}`
});
}
```
```sql
-- 모든 테이블에 RLS 활성화
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE pages ENABLE ROW LEVEL SECURITY;
ALTER TABLE media ENABLE ROW LEVEL SECURITY;
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
```
```sql
-- 사용자는 자신의 데이터만 수정 가능
CREATE POLICY "Users can update own data" ON users
FOR UPDATE TO authenticated
USING (id = auth.uid());
-- 관리자는 모든 페이지 관리 가능
CREATE POLICY "Admins can manage pages" ON pages
FOR ALL TO authenticated
USING (
EXISTS (
SELECT 1 FROM users
WHERE id = auth.uid() AND role = 'ADMIN'
)
);
-- 게시된 페이지는 모든 사용자가 읽기 가능
CREATE POLICY "Published pages are public" ON pages
FOR SELECT TO public
USING (published = true);
```
```typescript
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
// 클라이언트용 (브라우저)
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
// 서버용 (API 라우트)
export const supabaseAdmin = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
```
```typescript
// 페이지 목록 조회
const { data: pages, error } = await supabase
.from('pages')
.select('*')
.eq('published', true)
.order('created_at', { ascending: false });
// 특정 페이지 조회
const { data: page } = await supabase
.from('pages')
.select('*')
.eq('slug', 'about')
.single();
```
```typescript
// 실시간 구독
const subscription = supabase
.channel('page-changes')
.on('postgres_changes',
{ event: 'UPDATE', schema: 'public', table: 'pages' },
(payload) => {
console.log('페이지가 업데이트됨:', payload);
}
)
.subscribe();
// 구독 해제
subscription.unsubscribe();
```
Vercel Dashboard에서 다음 환경 변수 설정:
```env
DATABASE_URL=postgresql://postgres:[PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres
SUPABASE_URL=https://[PROJECT-REF].supabase.co
SUPABASE_ANON_KEY=eyJ...
NEXTAUTH_URL=https://your-domain.com
NEXTAUTH_SECRET=your-production-secret
```
**Authentication > Settings**에서:
1. **Site URL**: `https://your-domain.com`
2. **Redirect URLs**: `https://your-domain.com/auth/callback`
```bash
npx prisma db pull
npx prisma db push --force-reset
```
```sql
-- RLS 정책 확인
SELECT * FROM pg_policies WHERE tablename = 'your_table';
-- 정책 비활성화 (개발용)
ALTER TABLE your_table DISABLE ROW LEVEL SECURITY;
```
Supabase Dashboard > **Logs**에서:
- API 로그
- 데이터베이스 로그
- 인증 로그
- [Supabase 공식 문서](https://supabase.com/docs)
- [Prisma + Supabase 가이드](https://supabase.com/docs/guides/integrations/prisma)
- [NextAuth.js + Supabase](https://supabase.com/docs/guides/auth/auth-helpers/nextjs)
이제 Supabase가 완전히 설정되어 AgentC Starter Kit과 함께 사용할 준비가 완료되었습니다! 🎉