멀티테넌트 SaaS 구독 플랫폼 - 팀별 격리 & 결제 연동
multi-tenant-saas-subscription-platform
문제 설명
🏢 멀티테넌트 SaaS 구독 플랫폼
실무 수준의 멀티테넌트(Multi-tenant) 아키텍처를 구현하여, 여러 조직이 하나의 애플리케이션을 공유하면서도 데이터가 완전히 격리되는 SaaS 플랫폼을 만듭니다. Laravel 13.x의 고급 기능(테넌트 스코프, 미들웨어, 이벤트/리스너)과 Blade 컴포넌트를 활용하여 구축합니다.
필수 기능
- 🏗️ 멀티테넌트 아키텍처: 서브도메인 기반 테넌트 식별 (team1.app.test, team2.app.test)
- 🔐 완전한 데이터 격리: Global Scope를 사용한 자동 테넌트 필터링
- 👥 조직 관리: 조직 생성, 멤버 초대, 역할 관리 (Owner/Admin/Member)
- 💳 구독 관리: 3가지 플랜(Free/Pro/Enterprise), 플랜별 기능 제한
- 💰 결제 연동: Stripe 테스트 모드 연동, 구독 생성/취소/업그레이드
- 📊 사용량 추적: API 호출 횟수, 저장소 용량 등 플랜별 리소스 제한
- 🔔 알림 시스템: 구독 만료 알림, 사용량 초과 경고
- 📈 관리자 대시보드: 전체 테넌트 현황, 수익 통계, 활성 사용자 분석
- 🎨 Tailwind CSS: 현대적이고 반응형 UI
보너스 기능
- 🌐 커스텀 도메인: 테넌트별 자체 도메인 연결
- 📧 이메일 화이트라벨: 테넌트별 이메일 템플릿 커스터마이징
- 🔍 감사 로그: 테넌트별 모든 액션 추적
- 🚀 API Rate Limiting: 플랜별 차등 적용
- 📦 데이터 Export: 테넌트 데이터 백업 기능
제약 조건
- • Laravel 13.x 사용 (최신 안정 버전)
- • Blade 템플릿 엔진 사용 (React/Vue 금지)
- • Tailwind CSS 3.x로 스타일링
- • SQLite 또는 MySQL 데이터베이스
- • Stripe API (테스트 모드) 연동
- • Laravel의 Global Scope, Middleware, Event/Listener 활용
- • 서브도메인 라우팅 구현
- • Queue를 사용한 비동기 작업 처리
- • Policy와 Gate를 사용한 권한 관리
- • Blade 컴포넌트로 재사용 가능한 UI 구축
프롬프트 레시피
아래 프롬프트를 순서대로 AI에게 보내면 됩니다. 복사 버튼을 눌러 바로 사용하세요.
mkdir multi-tenant-saas-subscription-platform && cd multi-tenant-saas-subscription-platform
이 폴더에서 Laravel 13.x 멀티테넌트 SaaS 플랫폼 프로젝트를 시작합니다.
# Step 1: 프로젝트 초기 설정 및 데이터베이스 스키마 설계
Laravel 13.x 프로젝트를 생성하고 멀티테넌트 아키텍처의 핵심 데이터베이스 스키마를 설계하세요.
## 요구사항:
1. **Laravel 프로젝트 생성**
- `composer create-project laravel/laravel .` 실행
- `.env` 파일 설정 (DB_CONNECTION=sqlite 사용)
- `php artisan key:generate` 실행
2. **데이터베이스 마이그레이션 생성**
- `tenants` 테이블: id, name, subdomain(unique), domain(nullable), plan(enum: free/pro/enterprise), trial_ends_at, subscription_ends_at, is_active, created_at, updated_at
- `users` 테이블 확장: tenant_id(foreign key), role(enum: owner/admin/member) 추가
- `subscriptions` 테이블: id, tenant_id, stripe_id, stripe_status, stripe_plan, quantity, trial_ends_at, ends_at, created_at, updated_at
- `invitations` 테이블: id, tenant_id, email, role, token(unique), expires_at, accepted_at, created_at
- `usage_records` 테이블: id, tenant_id, metric(string: api_calls/storage_mb), value, recorded_at
3. **Tenant 모델 생성**
- `app/Models/Tenant.php` 생성
- 관계 설정: users(), subscriptions(), usageRecords()
- 헬퍼 메서드: isOnPlan($plan), hasFeature($feature), canUseFeature($feature)
- 플랜별 제한 설정: FREE(API 100/일, 저장소 100MB), PRO(API 10000/일, 저장소 10GB), ENTERPRISE(무제한)
4. **Global Scope 생성**
- `app/Scopes/TenantScope.php` 생성
- 모든 쿼리에 자동으로 `where('tenant_id', current_tenant_id())` 조건 추가
- User, Subscription, UsageRecord 모델에 TenantScope 적용
5. **Seeders 생성**
- 2개의 테스트 테넌트 생성 (acme: Free 플랜, techcorp: Pro 플랜)
- 각 테넌트별 Owner 계정 생성
모든 마이그레이션을 실행하고 시더를 실행하세요. Tenant 모델의 플랜 체크 로직이 정상 작동하는지 tinker로 테스트하세요.
기대 결과: Laravel 13.x 프로젝트가 생성되고, 멀티테넌트 데이터베이스 스키마(tenants, users, subscriptions, invitations, usage_records)가 마이그레이션으로 구현됩니다. Tenant 모델에 Global Scope가 적용되어 자동 필터링이 동작하며, 플랜별 기능 제한 로직이 준비됩니다. 2개의 테스트 테넌트와 사용자가 시더로 생성됩니다.
# Step 2: 서브도메인 기반 테넌트 식별 시스템 구축
서브도메인을 통해 현재 테넌트를 자동으로 식별하고, 모든 요청에 테넌트 컨텍스트를 주입하는 미들웨어를 구현하세요.
## 요구사항:
1. **테넌트 식별 미들웨어 생성**
- `app/Http/Middleware/IdentifyTenant.php` 생성
- 요청의 호스트에서 서브도메인 추출 (예: team1.app.test → team1)
- 서브도메인으로 Tenant 조회 (없으면 404)
- `app()` 싱글톤에 현재 테넌트 바인딩: `app()->instance('tenant', $tenant)`
- 세션에도 tenant_id 저장
2. **헬퍼 함수 생성**
- `app/helpers.php` 생성 및 `composer.json`의 autoload.files에 등록
- `tenant()`: 현재 테넌트 객체 반환
- `tenant_id()`: 현재 테넌트 ID 반환
- `tenant_url($path = '')`: 현재 테넌트의 전체 URL 생성
3. **라우트 설정**
- `routes/web.php`에서 서브도메인 라우트 그룹 설정
- `Route::domain('{tenant}.app.test')` 형식으로 테넌트 라우트 그룹 생성
- IdentifyTenant 미들웨어를 테넌트 라우트 그룹에 적용
- 메인 도메인(app.test)에는 랜딩 페이지 및 테넌트 생성 페이지 라우트 설정
4. **User 모델 업데이트**
- User 모델에 TenantScope 적용
- tenant() belongsTo 관계 추가
- creating 이벤트에서 자동으로 tenant_id 설정
5. **테스트 설정**
- `.env`에 `APP_URL=http://app.test` 설정
- `/etc/hosts`에 `127.0.0.1 app.test acme.app.test techcorp.app.test` 추가 안내
- 또는 Valet 사용 시 `valet link app` 및 서브도메인 자동 지원 확인
6. **간단한 테스트 페이지**
- `resources/views/tenant/dashboard.blade.php` 생성
- 현재 테넌트 정보 표시: 이름, 서브도메인, 플랜, 사용자 수
- 라우트: `Route::get('/dashboard', fn() => view('tenant.dashboard'))`
각 서브도메인(acme.app.test, techcorp.app.test)으로 접속 시 해당 테넌트의 대시보드가 표시되는지 확인하세요.
기대 결과: 서브도메인 기반 테넌트 식별 시스템이 완성됩니다. IdentifyTenant 미들웨어가 모든 요청에서 서브도메인을 파싱하여 현재 테넌트를 식별하고, 헬퍼 함수(tenant(), tenant_id())를 통해 어디서든 테넌트 정보에 접근할 수 있습니다. 각 서브도메인으로 접속 시 올바른 테�anten 데이터가 표시되는 대시보드 페이지가 동작합니다.
# Step 3: 인증 시스템 및 조직 관리 기능 구현 테넌트별로 격리된 인증 시스템과 조직 멤버 관리(초대, 역할 변경, 제거) 기능을 구현하세요. ## 요구사항: 1. **Laravel Breeze 설치 (Blade 스택)** - `composer require laravel/breeze --dev` - `php artisan breeze:install blade` - 로그인/회원가입 폼에 tenant_id 자동 주입 로직 추가 - 회원가입 시 현재 테넌트에 자동 연결 (기본 role: member) 2. **TenantController 생성** - `app/Http/Controllers/TenantController.php` - `settings()`: 테넌트 설정 페이지 (이름, 서브도메인 수정) - `updateSettings()`: 설정 업데이트 (Owner만 가능) - Policy 생성: `php artisan make:policy TenantPolicy` - `update` 권한: role이 owner인 경우만 허용 3. **멤버 관리 기능** - `app/Http/Controllers/MemberController.php` 생성 - `index()`: 현재 테넌트의 모든 멤버 목록 (이름, 이메일, 역할, 가입일) - `updateRole(User $user, Request $request)`: 멤버 역할 변경 (Owner/Admin만 가능) - `destroy(User $user)`: 멤버 제거 (Owner/Admin만 가능, 자기 자신 제거 불가) - Policy에 `manageMembers` 권한 추가: role이 owner 또는 admin 4. **초대 시스템** - `app/Http/Controllers/InvitationController.php` 생성 - `create()`: 초대 폼 (이메일, 역할 선택) - `store()`: 초대 생성, 고유 토큰 생성, 이메일 발송 (Queue 사용) - `accept($token)`: 초대 수락, 해당 이메일로 계정 생성 또는 기존 계정 연결 - Invitation 모델 생성 및 관계 설정 - `app/Mail/TenantInvitation.php` Mailable 생성 - Queue 설정: `.env`에서 `QUEUE_CONNECTION=database`, `php artisan queue:table` 및 마이그레이션 5. **Blade 뷰 생성** - `resources/views/tenant/settings.blade.php`: 테넌트 설정 페이지 - `resources/views/tenant/members/index.blade.php`: 멤버 목록 (테이블 형식, 역할 변경 드롭다운, 제거 버튼) - `resources/views/tenant/invitations/create.blade.php`: 초대 폼 - Tailwind CSS로 스타일링, Alpine.js로 간단한 인터랙션 (확인 모달 등) 6. **라우트 설정** - 테넌트 서브도메인 그룹 내에 인증 필요 라우트 추가 - `/settings`, `/members`, `/invitations/create` 등 - 미들웨어: `auth`, `IdentifyTenant` 모든 기능이 정상 작동하는지 테스트하세요. Owner 계정으로 로그인하여 새 멤버를 초대하고, 초대 링크를 통해 가입한 후 역할을 변경해보세요.
기대 결과: 테넌트별로 격리된 인증 시스템이 구축되고, 조직 설정 및 멤버 관리 기능이 완성됩니다. Owner/Admin은 멤버를 초대하고 역할을 변경하거나 제거할 수 있으며, 초대 이메일이 Queue를 통해 비동기로 발송됩니다. Policy를 통해 권한이 명확히 제어되고, Blade 뷰에서 Tailwind CSS로 스타일링된 UI가 제공됩니다.
# Step 4: 구독 플랜 시스템 및 Stripe 결제 연동
3가지 구독 플랜(Free, Pro, Enterprise)을 정의하고, Stripe를 연동하여 실제 결제 및 구독 관리 기능을 구현하세요.
## 요구사항:
1. **Stripe 설정**
- `composer require stripe/stripe-php`
- `.env`에 Stripe 테스트 키 추가: `STRIPE_KEY=pk_test_...`, `STRIPE_SECRET=sk_test_...`
- Stripe 대시보드에서 3개의 상품(Product) 및 가격(Price) 생성:
- Free: $0/월 (trial 없음)
- Pro: $29/월 (14일 trial)
- Enterprise: $99/월 (14일 trial)
- 각 Price ID를 `.env`에 저장: `STRIPE_PRICE_PRO=price_...`, `STRIPE_PRICE_ENTERPRISE=price_...`
2. **플랜 설정 파일 생성**
- `config/plans.php` 생성
- 각 플랜의 기능 제한 정의:
- Free: api_calls_per_day=100, storage_mb=100, members=3
- Pro: api_calls_per_day=10000, storage_mb=10240, members=20
- Enterprise: api_calls_per_day=unlimited, storage_mb=unlimited, members=unlimited
3. **SubscriptionController 생성**
- `app/Http/Controllers/SubscriptionController.php`
- `index()`: 현재 플랜 및 사용량 표시, 업그레이드 옵션 표시
- `checkout(Request $request)`: Stripe Checkout Session 생성 (플랜 선택)
- `success()`: 결제 성공 후 리다이렉트, Subscription 레코드 생성
- `cancel()`: 구독 취소 (Stripe 구독 취소 API 호출)
- `resume()`: 취소된 구독 재개
- `upgrade(Request $request)`: 플랜 업그레이드 (Stripe Subscription Update API)
4. **Stripe Webhook 처리**
- `app/Http/Controllers/WebhookController.php` 생성
- `handleWebhook(Request $request)`: Stripe 웹훅 검증 및 처리
- 이벤트 처리:
- `checkout.session.completed`: 구독 생성
- `customer.subscription.updated`: 구독 업데이트
- `customer.subscription.deleted`: 구독 취소
- `invoice.payment_succeeded`: 결제 성공
- `invoice.payment_failed`: 결제 실패 (알림 발송)
- 라우트: `Route::post('/webhook/stripe', [WebhookController::class, 'handleWebhook'])->withoutMiddleware(VerifyCsrfToken::class)`
5. **Tenant 모델 메서드 확장**
- `subscribe($plan)`: Stripe 구독 생성 및 Subscription 레코드 저장
- `cancelSubscription()`: Stripe 구독 취소
- `upgradeSubscription($newPlan)`: 플랜 변경
- `onTrial()`: trial_ends_at 체크
- `subscribed()`: 활성 구독 여부 체크
6. **Blade 뷰 생성**
- `resources/views/tenant/subscription/index.blade.php`: 현재 플랜 정보, 사용량 진행 바, 업그레이드 버튼
- `resources/views/tenant/subscription/plans.blade.php`: 플랜 비교 테이블 (가격, 기능 목록)
- Tailwind CSS로 프라이싱 카드 스타일링
7. **미들웨어 생성**
- `app/Http/Middleware/CheckSubscription.php`: 특정 기능 접근 시 플랜 체크
- 예: Pro 이상 플랜만 API 사용 가능
Stripe 테스트 카드(4242 4242 4242 4242)로 결제를 테스트하고, 웹훅이 정상 동작하는지 ngrok 등으로 확인하세요.
기대 결과: Stripe 결제 연동이 완료되고, 3가지 구독 플랜(Free, Pro, Enterprise) 시스템이 구현됩니다. 사용자는 Stripe Checkout을 통해 플랜을 구독하고, 업그레이드/취소/재개할 수 있습니다. Stripe 웹훅을 통해 구독 상태가 실시간으로 동기화되며, 플랜별 기능 제한이 미들웨어를 통해 강제됩니다. 프라이싱 페이지와 구독 관리 대시보드가 Tailwind CSS로 스타일링되어 제공됩니다.
# Step 5: 사용량 추적 및 제한 시스템 구현
플랜별 리소스 사용량(API 호출, 저장소)을 실시간으로 추적하고, 제한을 초과하면 경고하거나 차단하는 시스템을 구현하세요.
## 요구사항:
1. **UsageTracker 서비스 생성**
- `app/Services/UsageTracker.php` 생성
- `track($metric, $value = 1)`: 사용량 기록 (usage_records 테이블에 저장)
- `getTodayUsage($metric)`: 오늘 사용량 조회
- `getMonthlyUsage($metric)`: 이번 달 사용량 조회
- `canUse($metric)`: 현재 플랜의 제한 내에서 사용 가능한지 체크
- `getRemainingQuota($metric)`: 남은 할당량 계산
2. **API 사용량 추적**
- `app/Http/Middleware/TrackApiUsage.php` 생성
- API 라우트 그룹에 적용
- 요청마다 `UsageTracker::track('api_calls')` 호출
- 제한 초과 시 429 Too Many Requests 응답
3. **저장소 사용량 추적**
- 파일 업로드 기능 추가 (예: 프로필 이미지, 첨부파일)
- `app/Http/Controllers/FileController.php` 생성
- `upload(Request $request)`: 파일 업로드, 크기 체크, 저장소 사용량 업데이트
- `UsageTracker::track('storage_mb', $fileSizeInMB)` 호출
- 저장소 제한 초과 시 업로드 거부
4. **사용량 대시보드**
- `app/Http/Controllers/UsageController.php` 생성
- `index()`: 사용량 통계 페이지
- 차트 라이브러리 추가: `npm install chart.js` 및 Blade에서 사용
- 일별 API 호출 수 그래프 (최근 30일)
- 저장소 사용량 원형 차트 (사용/남은 용량)
- 플랜별 제한 대비 현재 사용률 진행 바
5. **알림 시스템**
- `app/Notifications/UsageLimitWarning.php` 생성
- 사용량이 80% 도달 시 Owner에게 알림 발송 (메일 + 데이터베이스)
- 사용량이 100% 도달 시 경고 알림 발송
- Notification 테이블 마이그레이션: `php artisan notifications:table`
- 알림 발송 로직을 UsageTracker에 통합
6. **스케줄러 설정**
- `app/Console/Commands/ResetDailyUsage.php` 생성
- 매일 자정에 일일 사용량 초기화 (api_calls_per_day)
- `app/Console/Kernel.php`의 `schedule()` 메서드에 등록
- `$schedule->command('usage:reset-daily')->daily()`
7. **Blade 뷰 생성**
- `resources/views/tenant/usage/index.blade.php`: 사용량 대시보드
- Chart.js를 사용한 그래프 렌더링
- 실시간 사용량 표시 (Livewire 또는 Alpine.js + fetch)
- Tailwind CSS로 스타일링
8. **제한 초과 페이지**
- `resources/views/errors/quota-exceeded.blade.php`: 할당량 초과 안내 페이지
- 업그레이드 버튼 및 현재 사용량 표시
API를 여러 번 호출하여 일일 제한에 도달하는지 테스트하고, 알림이 발송되는지 확인하세요.
기대 결과: 사용량 추적 및 제한 시스템이 완성됩니다. UsageTracker 서비스가 API 호출 수와 저장소 용량을 실시간으로 기록하며, 플랜별 제한을 초과하면 자동으로 차단되거나 알림이 발송됩니다. 사용량 대시보드에서 Chart.js를 통해 시각화된 통계를 확인할 수 있고, 스케줄러를 통해 일일 사용량이 자동으로 리셋됩니다. 제한 초과 시 사용자에게 명확한 안내와 업그레이드 옵션이 제공됩니다.
# Step 6: 슈퍼 관리자 대시보드 및 테넌트 관리 기능
전체 플랫폼을 관리하는 슈퍼 관리자(Super Admin) 대시보드를 구축하여, 모든 테넌트의 현황을 모니터링하고 관리할 수 있도록 하세요.
## 요구사항:
1. **슈퍼 관리자 인증**
- `users` 테이블에 `is_super_admin` 컬럼 추가 (마이그레이션)
- 시더에서 슈퍼 관리자 계정 생성 (tenant_id = null)
- `app/Http/Middleware/SuperAdminMiddleware.php` 생성: is_super_admin 체크
- 슈퍼 관리자는 메인 도메인(app.test/admin)에서 로그인
2. **슈퍼 관리자 라우트 그룹**
- `routes/admin.php` 생성 (메인 도메인용)
- `Route::prefix('admin')->middleware(['auth', 'super_admin'])->group(...)` 설정
- `RouteServiceProvider`에서 admin 라우트 파일 로드
3. **AdminDashboardController 생성**
- `app/Http/Controllers/Admin/DashboardController.php`
- `index()`: 전체 통계 대시보드
- 전체 테넌트 수
- 활성 구독 수 (플랜별 분포)
- 총 수익 (월별)
- 신규 가입 추이 (최근 30일)
- 활성 사용자 수 (DAU, MAU)
- Chart.js로 그래프 렌더링
4. **AdminTenantController 생성**
- `app/Http/Controllers/Admin/TenantController.php`
- `index()`: 전체 테넌트 목록 (검색, 필터링, 페이지네이션)
- 테이블 컬럼: 이름, 서브도메인, 플랜, 멤버 수, 생성일, 상태(활성/비활성)
- `show(Tenant $tenant)`: 특정 테넌트 상세 정보
- 멤버 목록, 구독 히스토리, 사용량 통계
- `impersonate(Tenant $tenant)`: 테넌트로 로그인 (디버깅용)
- 세션에 impersonating_tenant_id 저장, 해당 테넌트 서브도메인으로 리다이렉트
- `suspend(Tenant $tenant)`: 테넌트 비활성화 (is_active = false)
- `activate(Tenant $tenant)`: 테넌트 활성화
5. **AdminRevenueController 생성**
- `app/Http/Controllers/Admin/RevenueController.php`
- `index()`: 수익 분석 페이지
- 월별 수익 차트
- 플랜별 수익 비율 원형 차트
- MRR (Monthly Recurring Revenue) 계산
- Churn Rate (이탈률) 계산
6. **AdminUserController 생성**
- `app/Http/Controllers/Admin/UserController.php`
- `index()`: 전체 사용자 목록 (모든 테넌트)
- `show(User $user)`: 사용자 상세 정보 (소속 테넌트, 역할, 활동 로그)
7. **Blade 뷰 생성**
- `resources/views/admin/layout.blade.php`: 관리자 레이아웃 (사이드바 네비게이션)
- `resources/views/admin/dashboard.blade.php`: 메인 대시보드
- `resources/views/admin/tenants/index.blade.php`: 테넌트 목록
- `resources/views/admin/tenants/show.blade.php`: 테넌트 상세
- `resources/views/admin/revenue/index.blade.php`: 수익 분석
- `resources/views/admin/users/index.blade.php`: 사용자 목록
- Tailwind CSS + Tailwind UI 컴포넌트 사용
8. **감사 로그 시스템**
- `audit_logs` 테이블 생성: id, user_id, tenant_id, action, description, ip_address, user_agent, created_at
- `app/Observers/TenantObserver.php`: 테넌트 생성/수정/삭제 시 로그 기록
- `app/Observers/UserObserver.php`: 사용자 생성/역할 변경 시 로그 기록
- 관리자 대시보드에 최근 활동 로그 표시
슈퍼 관리자로 로그인하여 전체 테넌트를 확인하고, 특정 테넌트로 impersonate 기능을 테스트하세요.
기대 결과: 슈퍼 관리자 대시보드가 완성되어, 전체 플랫폼의 모든 테넌트를 한눈에 모니터링하고 관리할 수 있습니다. 통계 대시보드에서 테넌트 수, 구독 현황, 수익 분석을 Chart.js로 시각화하며, 테넌트 목록에서 검색/필터링/페이지네이션이 가능합니다. Impersonate 기능을 통해 특정 테넌트로 로그인하여 디버깅할 수 있고, 감사 로그 시스템이 모든 중요한 액션을 기록합니다. Tailwind CSS로 전문적인 관리자 UI가 구현됩니다.
# Step 7: 테넌트별 커스터마이징 및 화이트라벨 기능
테넌트가 자신의 조직을 브랜딩할 수 있도록 로고, 색상, 이메일 템플릿 등을 커스터마이징하는 기능을 구현하세요.
## 요구사항:
1. **테넌트 설정 확장**
- `tenants` 테이블에 컬럼 추가 (마이그레이션):
- `logo_path` (nullable): 로고 파일 경로
- `primary_color` (default: #3B82F6): 메인 색상
- `secondary_color` (default: #10B981): 보조 색상
- `custom_domain` (nullable): 커스텀 도메인
- `email_from_name` (default: 조직명)
- `email_from_address` (nullable)
2. **브랜딩 설정 페이지**
- `app/Http/Controllers/BrandingController.php` 생성
- `edit()`: 브랜딩 설정 폼
- `update(Request $request)`: 로고 업로드, 색상 변경, 이메일 설정 저장
- 로고 업로드: Laravel Storage 사용, public 디스크에 저장
- 이미지 검증: mimes:jpg,png,svg, max:2048 (2MB)
3. **동적 스타일 적용**
- `app/View/Components/TenantLayout.php` Blade 컴포넌트 생성
- 테넌트의 primary_color, secondary_color를 CSS 변수로 주입
- `resources/views/components/tenant-layout.blade.php`에서 `<style>` 태그로 동적 색상 적용:
```blade
<style>
:root {
--primary-color: {{ tenant()->primary_color }};
--secondary-color: {{ tenant()->secondary_color }};
}
</style>
```
- Tailwind CSS 설정 확장: `tailwind.config.js`에서 커스텀 색상 사용
4. **로고 표시**
- 네비게이션 바에 테넌트 로고 표시
- `@if(tenant()->logo_path) <img src="{{ Storage::url(tenant()->logo_path) }}"> @else 기본 로고 @endif`
5. **이메일 템플릿 커스터마이징**
- `app/Mail/TenantMail.php` 추상 클래스 생성
- `from()` 메서드 오버라이드: 테넌트의 email_from_name, email_from_address 사용
- 모든 테넌트 이메일(초대, 알림 등)이 TenantMail을 상속하도록 수정
- 이메일 뷰에 테넌트 로고 및 브랜드 색상 적용
6. **커스텀 도메인 지원**
- `custom_domain` 필드가 설정된 경우, IdentifyTenant 미들웨어에서 커스텀 도메인도 인식하도록 수정
- 예: team1.app.test 대신 team1.com으로 접속 가능
- DNS CNAME 설정 안내 페이지 추가
7. **Blade 뷰 생성**
- `resources/views/tenant/branding/edit.blade.php`: 브랜딩 설정 폼
- 로고 업로드 (파일 인풋, 현재 로고 미리보기)
- 색상 선택기 (HTML5 color input)
- 이메일 발신자 정보 입력
- 커스텀 도메인 입력 및 DNS 설정 안내
- Tailwind CSS로 스타일링, Alpine.js로 실시간 미리보기
8. **미리보기 기능**
- 색상 변경 시 실시간으로 페이지에 적용되는 미리보기
- Alpine.js로 구현: `x-bind:style="'--primary-color:' + primaryColor"`
브랜딩 설정을 변경하고, 로고와 색상이 네비게이션과 이메일에 올바르게 적용되는지 테스트하세요.
기대 결과: 테넌트별 커스터마이징 기능이 완성되어, 각 조직이 자신의 브랜드 아이덴티티를 반영할 수 있습니다. 로고 업로드, 메인/보조 색상 설정, 이메일 발신자 정보 커스터마이징이 가능하며, 설정한 스타일이 모든 페이지와 이메일에 동적으로 적용됩니다. 커스텀 도메인 지원으로 완전한 화이트라벨 솔루션이 구현되고, 실시간 미리보기 기능으로 사용자 경험이 향상됩니다. Blade 컴포넌트와 Alpine.js를 활용한 반응형 UI가 제공됩니다.
# Step 8: 보안 강화 및 성능 최적화
SaaS 플랫폼의 보안을 강화하고, 대규모 트래픽을 처리할 수 있도록 성능을 최적화하세요.
## 요구사항:
1. **보안 강화**
- **CSRF 보호**: 모든 폼에 `@csrf` 토큰 적용 확인
- **XSS 방지**: Blade의 `{{ }}` 사용 (자동 이스케이프), `{!! !!}` 사용 최소화
- **SQL Injection 방지**: Eloquent ORM 및 쿼리 빌더 사용, raw 쿼리 금지
- **Rate Limiting**: `app/Http/Middleware/ThrottleRequests.php` 설정
- 로그인: 5회/분
- API: 플랜별 차등 (Free: 100/일, Pro: 10000/일)
- 회원가입: 3회/시간
- **2FA (Two-Factor Authentication)** 추가 (선택사항):
- `composer require pragmarx/google2fa-laravel`
- 사용자 설정 페이지에 2FA 활성화 옵션 추가
2. **데이터 암호화**
- 민감한 필드(Stripe 키 등) 암호화: `encrypted` 캐스트 사용
- `protected $casts = ['stripe_secret' => 'encrypted'];`
3. **캐싱 전략**
- **쿼리 캐싱**: 자주 조회되는 데이터 캐싱
- 테넌트 정보: `Cache::remember('tenant.{id}', 3600, fn() => Tenant::find($id))`
- 플랜 정보: `Cache::remember('plans', 86400, fn() => config('plans'))`
- **뷰 캐싱**: `php artisan view:cache`
- **라우트 캐싱**: `php artisan route:cache`
- **설정 캐싱**: `php artisan config:cache`
4. **데이터베이스 최적화**
- **인덱스 추가**: 자주 검색되는 컬럼에 인덱스 생성
- `tenants.subdomain`, `users.tenant_id`, `subscriptions.tenant_id`
- **Eager Loading**: N+1 쿼리 문제 방지
- `Tenant::with('users', 'subscriptions')->get()`
- **쿼리 최적화**: `select()` 메서드로 필요한 컬럼만 조회
5. **Queue 최적화**
- **Queue Worker 설정**: Supervisor로 큐 워커 관리 (설정 파일 예시 제공)
- **Job 배치 처리**: 대량 이메일 발송 시 배치로 처리
- **Failed Jobs 처리**: `failed_jobs` 테이블 생성 및 재시도 로직
6. **CDN 및 Asset 최적화**
- **Laravel Mix/Vite 설정**: JS/CSS 번들링 및 minify
- **이미지 최적화**: `composer require intervention/image`
- 업로드된 이미지 자동 리사이즈 및 압축
- **Lazy Loading**: 이미지에 `loading="lazy"` 속성 추가
7. **모니터링 및 로깅**
- **Laravel Telescope 설치** (개발 환경):
- `composer require laravel/telescope --dev`
- `php artisan telescope:install`
- 쿼리, 요청, 예외 모니터링
- **Sentry 연동** (프로덕션):
- `composer require sentry/sentry-laravel`
- `.env`에 Sentry DSN 설정
- 에러 자동 리포팅
8. **테스트 작성**
- **Feature Tests**: 주요 기능 테스트
- 테넌트 생성 테스트
- 구독 생성/취소 테스트
- 사용량 제한 테스트
- **Unit Tests**: 핵심 로직 테스트
- UsageTracker 서비스 테스트
- Tenant 모델 메서드 테스트
- `php artisan test` 실행하여 모든 테스트 통과 확인
9. **배포 준비**
- `.env.example` 파일 업데이트
- `README.md` 작성: 설치 방법, 환경 변수 설명, Stripe 설정 가이드
- `DEPLOYMENT.md` 작성: 프로덕션 배포 체크리스트
모든 최적화를 적용하고, Laravel Telescope로 성능을 모니터링하세요. 테스트를 실행하여 모든 기능이 정상 작동하는지 확인하세요.
기대 결과: SaaS 플랫폼의 보안이 대폭 강화되고, 성능이 최적화됩니다. Rate Limiting, CSRF/XSS 방지, 데이터 암호화 등 보안 조치가 적용되며, 캐싱 전략과 데이터베이스 최적화로 응답 속도가 개선됩니다. Queue 최적화로 비동기 작업이 효율적으로 처리되고, CDN 및 Asset 최적화로 프론트엔드 성능이 향상됩니다. Laravel Telescope와 Sentry를 통한 모니터링 시스템이 구축되며, Feature/Unit Tests로 코드 품질이 보장됩니다. 프로덕션 배포를 위한 문서가 완비되어 실무 투입이 가능한 수준의 플랫폼이 완성됩니다.