온라인 코스 수강증 발급 플랫폼 - 학습 완료 인증서 자동 생성
course-certificate-generator-inertia
문제 설명
🎓 온라인 코스 수강증 발급 플랫폼
온라인 교육 플랫폼이나 소규모 강의 사업자를 위한 수강증 자동 발급 시스템을 만듭니다. 학생이 코스를 완료하면 자동으로 PDF 수강증을 생성하고, 이메일로 발송하며, 수강증 진위 여부를 확인할 수 있는 고유 인증 번호를 부여합니다.
필수 기능
- 📚 코스 관리: 강사가 코스 제목, 설명, 수료 기준(예: 80% 이상 진도율)을 등록
- 👤 학생 등록: 학생이 코스에 등록하고 학습 진행률을 기록
- 📊 진도율 추적: 학생별 코스 진행률을 자동 계산 (예: 챕터별 완료 체크)
- 🎖️ 수강증 자동 발급: 수료 조건 달성 시 PDF 수강증 자동 생성 (학생 이름, 코스명, 발급일, 고유 인증번호 포함)
- ✉️ 이메일 발송: 수강증 PDF를 학생 이메일로 자동 전송 (Laravel Mail + Queue)
- 🔍 수강증 검증: 인증번호로 수강증 진위 여부를 공개 페이지에서 확인 가능
- 📜 수강증 목록: 학생이 자신의 모든 수강증을 한눈에 확인하고 재다운로드 가능
보너스 기능
- 🎨 커스텀 디자인: 강사가 수강증 템플릿 색상/로고를 커스터마이징
- 📈 통계 대시보드: 강사가 코스별 수료율, 발급된 수강증 수 확인
- 🏆 배지 시스템: 특정 조건(예: 3개 코스 수료) 달성 시 특별 배지 부여
- 🌐 소셜 공유: 학생이 수강증을 LinkedIn, Twitter에 공유 가능한 링크 생성
이 프로젝트는 Laravel 13.x + Inertia.js + React 19 모노리스 풀스택으로 구현하며, PDF 생성(DomPDF/Snappy), 이메일 큐, 파일 스토리지를 다루는 실무 기술을 학습할 수 있습니다.
제약 조건
- • Laravel 13.x + Inertia.js + React 19 사용 (모노리스 풀스택)
- • npx create laravel 또는 Laravel Breeze (React + Inertia) starter kit으로 프로젝트 생성
- • Inertia.js로 Laravel 컨트롤러와 React 컴포넌트 연결 (별도 API 라우트 없음)
- • SQLite 데이터베이스 사용 (개발 편의성)
- • PDF 생성 라이브러리 사용 (예: barryvdh/laravel-dompdf 또는 spatie/browsershot)
- • Laravel Mail + Queue를 사용한 이메일 비동기 발송
- • 파일 스토리지는 Laravel Storage (local 또는 public disk)
- • Tailwind CSS로 UI 스타일링
- • React 컴포넌트는 함수형 컴포넌트 + Hooks (useState, useEffect) 사용
- • 수강증 인증번호는 UUID 또는 랜덤 문자열로 생성하여 DB에 저장
- • 수강증 검증은 인증 불필요한 공개 페이지로 제공
프롬프트 레시피
아래 프롬프트를 순서대로 AI에게 보내면 됩니다. 복사 버튼을 눌러 바로 사용하세요.
mkdir course-certificate-generator-inertia && cd course-certificate-generator-inertia 이 폴더에서 Laravel 13.x + Inertia.js + React 19 프로젝트를 생성합니다. 다음 명령으로 Laravel Breeze (React + Inertia) starter kit을 설치하세요: ```bash composer create-project laravel/laravel . composer require laravel/breeze --dev php artisan breeze:install react npm install npm run build ``` 데이터베이스는 SQLite를 사용합니다. `.env` 파일을 다음과 같이 수정하세요: ``` DB_CONNECTION=sqlite # DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD 주석 처리 ``` `database/database.sqlite` 파일을 생성하고 마이그레이션을 실행하세요: ```bash touch database/database.sqlite php artisan migrate ``` 이제 기본 인증 시스템(회원가입/로그인)이 포함된 Laravel + Inertia + React 프로젝트가 준비되었습니다. `php artisan serve`로 서버를 실행하고 `http://localhost:8000`에 접속하여 확인하세요.
기대 결과: Laravel Breeze (React + Inertia) 프로젝트가 생성되고, 기본 인증 시스템이 작동합니다. 회원가입/로그인 페이지가 정상적으로 렌더링되고, SQLite 데이터베이스가 연결됩니다.
코스(Course)와 수강 등록(Enrollment), 수강증(Certificate) 모델을 생성하고 마이그레이션을 작성하세요. ### 요구사항: 1. **Course 모델**: 강사가 생성한 코스 정보를 저장 - 필드: `id`, `user_id` (강사, users 테이블 FK), `title`, `description`, `completion_threshold` (수료 기준 진도율, 기본값 80), `created_at`, `updated_at` 2. **Enrollment 모델**: 학생이 코스에 등록한 정보 - 필드: `id`, `user_id` (학생, users 테이블 FK), `course_id` (courses 테이블 FK), `progress` (진도율, 0~100, 기본값 0), `completed_at` (수료 일시, nullable), `created_at`, `updated_at` - 인덱스: `user_id`, `course_id` 복합 유니크 인덱스 (중복 등록 방지) 3. **Certificate 모델**: 발급된 수강증 정보 - 필드: `id`, `enrollment_id` (enrollments 테이블 FK), `certificate_number` (고유 인증번호, UUID), `issued_at`, `pdf_path` (PDF 파일 경로), `created_at`, `updated_at` - 인덱스: `certificate_number` 유니크 인덱스 다음 명령으로 모델과 마이그레이션을 생성하세요: ```bash php artisan make:model Course -m php artisan make:model Enrollment -m php artisan make:model Certificate -m ``` 각 마이그레이션 파일을 위 스키마대로 작성하고, 모델에 관계(relationship)를 정의하세요: - `User` 모델: `hasMany(Course)`, `hasMany(Enrollment)` - `Course` 모델: `belongsTo(User)`, `hasMany(Enrollment)`, `hasManyThrough(Certificate, Enrollment)` - `Enrollment` 모델: `belongsTo(User)`, `belongsTo(Course)`, `hasOne(Certificate)` - `Certificate` 모델: `belongsTo(Enrollment)` 마이그레이션을 실행하세요: ```bash php artisan migrate ```
기대 결과: Course, Enrollment, Certificate 모델과 마이그레이션이 생성되고, 데이터베이스 테이블이 생성됩니다. 모델 간 관계가 정의되어 Eloquent로 연관 데이터를 쉽게 조회할 수 있습니다.
강사가 코스를 생성/조회/수정/삭제할 수 있는 CRUD 기능을 구현하세요.
### 요구사항:
1. **CourseController 생성**:
```bash
php artisan make:controller CourseController
```
2. **라우트 정의** (`routes/web.php`):
- `GET /courses` → `CourseController@index` (코스 목록)
- `GET /courses/create` → `CourseController@create` (코스 생성 폼)
- `POST /courses` → `CourseController@store` (코스 저장)
- `GET /courses/{id}/edit` → `CourseController@edit` (코스 수정 폼)
- `PUT /courses/{id}` → `CourseController@update` (코스 업데이트)
- `DELETE /courses/{id}` → `CourseController@destroy` (코스 삭제)
- 모든 라우트는 `auth` 미들웨어로 보호
3. **컨트롤러 메서드 구현**:
- `index`: 로그인한 사용자가 생성한 코스 목록을 `Inertia::render('Courses/Index')`로 전달
- `create`: 빈 폼을 `Inertia::render('Courses/Create')`로 렌더링
- `store`: 폼 데이터를 검증(title 필수, completion_threshold 0~100)하고 코스 생성 후 `/courses`로 리다이렉트
- `edit`: 특정 코스를 조회하여 `Inertia::render('Courses/Edit')`로 전달
- `update`: 코스 정보 업데이트 후 `/courses`로 리다이렉트
- `destroy`: 코스 삭제 후 `/courses`로 리다이렉트
4. **React 페이지 컴포넌트 생성**:
- `resources/js/Pages/Courses/Index.jsx`: 코스 목록 테이블, 생성/수정/삭제 버튼
- `resources/js/Pages/Courses/Create.jsx`: 코스 생성 폼 (title, description, completion_threshold 입력)
- `resources/js/Pages/Courses/Edit.jsx`: 코스 수정 폼
- Inertia `useForm` 훅을 사용하여 폼 제출 처리
- Tailwind CSS로 스타일링 (카드 레이아웃, 버튼, 입력 필드)
5. **네비게이션 추가**: `resources/js/Layouts/AuthenticatedLayout.jsx`에 "내 코스" 메뉴 추가
구현 후 브라우저에서 코스를 생성/수정/삭제할 수 있는지 테스트하세요.
기대 결과: 강사가 로그인 후 코스를 생성하고, 목록을 확인하며, 수정/삭제할 수 있습니다. React 컴포넌트가 Inertia.js를 통해 Laravel 컨트롤러와 원활하게 통신하고, 데이터가 DB에 저장됩니다.
학생이 코스에 등록하고 진도율을 업데이트하는 기능을 구현하세요.
### 요구사항:
1. **EnrollmentController 생성**:
```bash
php artisan make:controller EnrollmentController
```
2. **라우트 정의** (`routes/web.php`):
- `GET /courses/{id}` → `CourseController@show` (코스 상세 페이지, 학생이 등록 가능)
- `POST /enrollments` → `EnrollmentController@store` (코스 등록)
- `PUT /enrollments/{id}/progress` → `EnrollmentController@updateProgress` (진도율 업데이트)
- `GET /my-courses` → `EnrollmentController@myCourses` (내가 등록한 코스 목록)
3. **CourseController@show 구현**:
- 코스 정보와 현재 사용자의 등록 여부(enrollment)를 조회
- `Inertia::render('Courses/Show', ['course' => $course, 'enrollment' => $enrollment])`로 전달
4. **EnrollmentController 구현**:
- `store`: 로그인한 사용자를 코스에 등록 (중복 등록 방지)
- `updateProgress`: 진도율(progress)을 0~100 범위로 업데이트. 진도율이 `completion_threshold` 이상이면 `completed_at`을 현재 시각으로 설정하고, 수강증 발급 로직 호출 (다음 단계에서 구현)
- `myCourses`: 로그인한 사용자가 등록한 코스 목록을 `Inertia::render('Enrollments/MyCourses')`로 전달
5. **React 페이지 컴포넌트 생성**:
- `resources/js/Pages/Courses/Show.jsx`: 코스 상세 정보, "등록하기" 버튼 (미등록 시), 진도율 슬라이더 (등록 시)
- `resources/js/Pages/Enrollments/MyCourses.jsx`: 내가 등록한 코스 목록, 진도율 표시, 수료 여부 표시
- 진도율 슬라이더는 `<input type="range" min="0" max="100" />` 사용, 변경 시 `PUT /enrollments/{id}/progress`로 업데이트
6. **네비게이션 추가**: AuthenticatedLayout에 "내 수강 코스" 메� 추가
구현 후 학생이 코스에 등록하고 진도율을 조정할 수 있는지 테스트하세요.
기대 결과: 학생이 코스 상세 페이지에서 등록 버튼을 클릭하여 코스에 등록할 수 있고, 진도율 슬라이더로 학습 진행률을 업데이트할 수 있습니다. 진도율이 수료 기준에 도달하면 completed_at이 자동으로 설정됩니다.
수강증 자동 발급 기능을 구현하세요. 학생이 코스를 수료하면 PDF 수강증을 자동 생성하고 DB에 저장합니다.
### 요구사항:
1. **PDF 생성 라이브러리 설치**:
```bash
composer require barryvdh/laravel-dompdf
```
2. **CertificateService 생성**: 수강증 발급 로직을 서비스 클래스로 분리
- `app/Services/CertificateService.php` 파일 생성
- `generateCertificate(Enrollment $enrollment)` 메서드 구현:
- UUID로 고유 인증번호 생성 (`Str::uuid()`)
- PDF 뷰 템플릿 렌더링 (학생 이름, 코스명, 발급일, 인증번호 포함)
- PDF 파일을 `storage/app/public/certificates/{certificate_number}.pdf`에 저장
- Certificate 모델 레코드 생성 (enrollment_id, certificate_number, issued_at, pdf_path)
3. **PDF 뷰 템플릿 생성**:
- `resources/views/certificates/template.blade.php` 생성
- HTML/CSS로 수강증 디자인 (A4 크기, 중앙 정렬, 학생 이름, 코스명, 발급일, 인증번호 표시)
- 예시:
```blade
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
.certificate { border: 5px solid #4F46E5; padding: 40px; }
.title { font-size: 36px; font-weight: bold; color: #4F46E5; }
.name { font-size: 28px; margin: 20px 0; }
.course { font-size: 20px; margin: 10px 0; }
.number { font-size: 14px; color: #666; margin-top: 30px; }
</style>
</head>
<body>
<div class="certificate">
<div class="title">수강증</div>
<div class="name">{{ $studentName }}</div>
<div class="course">{{ $courseName }}</div>
<p>위 과정을 성실히 이수하였음을 증명합니다.</p>
<div>발급일: {{ $issuedAt }}</div>
<div class="number">인증번호: {{ $certificateNumber }}</div>
</div>
</body>
</html>
```
4. **EnrollmentController@updateProgress 수정**:
- 진도율이 수료 기준에 도달하고 `completed_at`이 null일 때 `CertificateService@generateCertificate` 호출
5. **Storage 심볼릭 링크 생성**:
```bash
php artisan storage:link
```
구현 후 학생이 진도율을 100%로 올렸을 때 PDF 수강증이 자동 생성되고 DB에 저장되는지 확인하세요.
기대 결과: 학생이 코스를 수료하면 자동으로 PDF 수강증이 생성되어 storage/app/public/certificates 폴더에 저장되고, certificates 테이블에 레코드가 추가됩니다. PDF 파일은 브라우저에서 다운로드 가능합니다.
수강증 이메일 자동 발송 기능을 구현하세요. 수강증 발급 시 학생에게 PDF 파일을 첨부한 이메일을 비동기로 발송합니다.
### 요구사항:
1. **메일 설정** (`.env`):
- 개발 환경에서는 `MAIL_MAILER=log`로 설정하여 이메일을 로그 파일에 기록
- 실제 서비스에서는 SMTP 또는 Mailgun 등 사용
2. **Mailable 클래스 생성**:
```bash
php artisan make:mail CertificateIssued
```
- `app/Mail/CertificateIssued.php`에서 생성자로 `Certificate` 모델 주입
- `build()` 메서드에서 이메일 제목, 본문 뷰, PDF 첨부 구현:
```php
public function build()
{
return $this->subject('수강증이 발급되었습니다!')
->view('emails.certificate-issued')
->attach(storage_path('app/public/' . $this->certificate->pdf_path));
}
```
3. **이메일 뷰 템플릿 생성**:
- `resources/views/emails/certificate-issued.blade.php`
- 간단한 축하 메시지와 수강증 다운로드 안내
4. **Queue 설정**:
- `.env`에서 `QUEUE_CONNECTION=database` 설정
- 마이그레이션 생성 및 실행:
```bash
php artisan queue:table
php artisan migrate
```
5. **CertificateService 수정**:
- `generateCertificate` 메서드 끝에 이메일 발송 로직 추가:
```php
Mail::to($enrollment->user->email)->queue(new CertificateIssued($certificate));
```
6. **Queue Worker 실행**:
```bash
php artisan queue:work
```
- 개발 중에는 별도 터미널에서 실행하여 큐 작업 처리
구현 후 학생이 코스를 수료했을 때 이메일이 큐에 추가되고, `storage/logs/laravel.log`에 이메일 내용이 기록되는지 확인하세요.
기대 결과: 수강증 발급 시 이메일이 큐에 추가되고, Queue Worker가 실행 중이면 비동기로 이메일이 발송됩니다. 개발 환경에서는 로그 파일에 이메일 내용이 기록되어 확인할 수 있습니다.
학생이 자신의 수강증 목록을 확인하고 재다운로드할 수 있는 페이지를 구현하세요. 또한 수강증 인증번호로 진위 여부를 확인할 수 있는 공개 페이지를 만드세요.
### 요구사항:
1. **CertificateController 생성**:
```bash
php artisan make:controller CertificateController
```
2. **라우트 정의** (`routes/web.php`):
- `GET /my-certificates` → `CertificateController@index` (내 수강증 목록, 인증 필요)
- `GET /certificates/{id}/download` → `CertificateController@download` (PDF 다운로드, 인증 필요)
- `GET /verify-certificate` → `CertificateController@verify` (수강증 검증 페이지, 공개)
- `GET /verify-certificate/{number}` → `CertificateController@show` (특정 수강증 정보 조회, 공개)
3. **CertificateController 구현**:
- `index`: 로그인한 사용자의 모든 수강증을 조회 (enrollments → certificates 관계 활용), `Inertia::render('Certificates/Index')`로 전달
- `download`: 특정 수강증의 PDF 파일을 다운로드 응답으로 반환 (`Storage::download()`)
- `verify`: 수강증 검증 폼을 `Inertia::render('Certificates/Verify')`로 렌더링
- `show`: 인증번호로 수강증을 조회하여 정보(학생명, 코스명, 발급일) 반환. 존재하지 않으면 404 에러
4. **React 페이지 컴포넌트 생성**:
- `resources/js/Pages/Certificates/Index.jsx`: 수강증 목록 (코스명, 발급일, 인증번호, 다운로드 버튼)
- `resources/js/Pages/Certificates/Verify.jsx`: 인증번호 입력 폼, 검증 결과 표시 (학생명, 코스명, 발급일, "유효한 수강증입니다" 메시지)
- Tailwind CSS로 카드 레이아웃, 배지, 버튼 스타일링
5. **네비게이션 추가**: AuthenticatedLayout에 "내 수강증" 메뉴, 공개 헤더에 "수강증 검증" 링크 추가
구현 후 학생이 수강증 목록을 확인하고 PDF를 다운로드할 수 있는지, 공개 페이지에서 인증번호로 수강증을 검증할 수 있는지 테스트하세요.
기대 결과: 학생이 로그인 후 자신의 수강증 목록을 확인하고 PDF 파일을 다운로드할 수 있습니다. 공개 검증 페이지에서 인증번호를 입력하면 수강증 진위 여부와 상세 정보가 표시됩니다.
제출된 작품 (0)
로그인 후 제출아직 제출된 작품이 없습니다. 첫 번째 도전자가 되어보세요!