풀스택 운동 챌린지 참여 앱
fitness-challenge-tracker
문제 설명
📋 프로젝트 개요
30일 운동 챌린지에 참여하고 매일 인증하는 간단한 풀스택 웹 앱을 만듭니다. Laravel 13.x로 RESTful API 백엔드를 구축하고, React 19로 사용자 친화적인 프론트엔드를 개발합니다.
✅ 필수 기능
- 챌린지 목록 조회: 현재 진행 중인 챌린지 목록 표시 (예: 30일 플랭크, 스쿼트 100개 등)
- 챌린지 생성: 새로운 챌린지 추가 (제목, 설명, 목표 일수)
- 일일 인증 체크: 오늘 운동했는지 체크박스로 기록
- 진행률 표시: 챌린지별 달성률을 프로그레스 바로 시각화
- SQLite 데이터베이스: 간단한 로컬 DB로 챌린지와 인증 기록 저장
🎁 보너스 기능
- 연속 인증 일수(Streak) 표시
- 챌린지 완료 시 축하 메시지
- 간단한 애니메이션 효과 (체크 시 confetti 등)
- 다크 모드 지원
🛠 기술 스택
- 백엔드: Laravel 13.x (API 모드, SQLite)
- 프론트엔드: React 19 (Vite)
- 스타일링: Tailwind CSS
- HTTP 클라이언트: Axios
이 프로젝트를 통해 Laravel API 개발과 React 컴포넌트 구성, 그리고 두 시스템 간 데이터 통신의 기초를 배울 수 있습니다.
제약 조건
- • Laravel 13.x 사용 (구버전 금지)
- • React 19 사용 (구버전 금지)
- • SQLite 데이터베이스 사용 (설치 불필요)
- • Laravel은 API 전용 백엔드로 구성 (api.php 라우트 사용)
- • React는 별도 Vite 프로젝트로 구성
- • CORS 설정 필수 (Laravel에서 React 접근 허용)
- • 복잡한 상태관리 라이브러리 사용 금지 (useState만 사용)
- • 인증/로그인 기능 제외 (단순 CRUD에 집중)
- • Tailwind CSS로 깔끔한 UI 구성
프롬프트 레시피
아래 프롬프트를 순서대로 AI에게 보내면 됩니다. 복사 버튼을 눌러 바로 사용하세요.
mkdir fitness-challenge-tracker && cd fitness-challenge-tracker 이 폴더에서 프로젝트를 시작합니다. # Laravel 13.x API 백엔드 프로젝트 생성 1. `backend` 폴더에 Laravel 13.x 프로젝트를 생성해주세요. - `composer create-project laravel/laravel:^13.0 backend` 명령 사용 2. `.env` 파일 설정: - DB_CONNECTION을 sqlite로 변경 - database/database.sqlite 파일 생성 3. 다음 마이그레이션 파일 2개를 생성해주세요: **challenges 테이블** (`create_challenges_table.php`): - id (primary key) - title (string, 챌린지 제목) - description (text, 설명) - target_days (integer, 목표 일수, 기본값 30) - created_at, updated_at **check_ins 테이블** (`create_check_ins_table.php`): - id (primary key) - challenge_id (foreign key → challenges.id) - check_date (date, 인증 날짜, unique with challenge_id) - created_at, updated_at 4. 마이그레이션 실행: `php artisan migrate` 5. CORS 설정: - `config/cors.php`에서 'paths' => ['api/*']로 설정 - 'allowed_origins' => ['http://localhost:5173'] (Vite 기본 포트) - 'supports_credentials' => true 6. 서버 실행 확인: - `php artisan serve`로 http://127.0.0.1:8000에서 실행 확인
기대 결과: Laravel 13.x 프로젝트가 backend 폴더에 생성되고, SQLite 데이터베이스에 challenges와 check_ins 테이블이 생성됩니다. CORS가 설정되어 React에서 API 호출이 가능한 상태가 됩니다.
# Laravel API 엔드포인트 구현
1. Challenge 모델 생성:
- `php artisan make:model Challenge`
- CheckIn과 hasMany 관계 설정
- fillable: ['title', 'description', 'target_days']
2. CheckIn 모델 생성:
- `php artisan make:model CheckIn`
- Challenge와 belongsTo 관계 설정
- fillable: ['challenge_id', 'check_date']
3. ChallengeController 생성 (`php artisan make:controller Api/ChallengeController --api`):
- `index()`: 모든 챌린지 조회 (check_ins 카운트 포함, withCount 사용)
- `store()`: 새 챌린지 생성 (title, description, target_days 검증)
- `show($id)`: 특정 챌린지 상세 조회 (check_ins 관계 로드)
- `destroy($id)`: 챌린지 삭제
4. CheckInController 생성 (`php artisan make:controller Api/CheckInController`):
- `store()`: 특정 챌린지에 오늘 날짜로 체크인 생성
- challenge_id와 오늘 날짜(Carbon::today())로 중복 체크
- 이미 오늘 체크인했으면 에러 반환
- `destroy($id)`: 체크인 삭제 (체크 취소)
5. `routes/api.php`에 라우트 등록:
```php
Route::apiResource('challenges', ChallengeController::class);
Route::post('challenges/{challenge}/check-in', [CheckInController::class, 'store']);
Route::delete('check-ins/{checkIn}', [CheckInController::class, 'destroy']);
```
6. Postman 또는 curl로 API 테스트:
- POST /api/challenges (챌린지 생성)
- GET /api/challenges (목록 조회)
- POST /api/challenges/1/check-in (체크인)
기대 결과: Laravel API가 완성되어 챌린지 CRUD와 체크인 생성/삭제가 가능합니다. /api/challenges 엔드포인트에서 JSON 응답을 받을 수 있으며, 각 챌린지의 check_ins_count가 포함됩니다.
# React 19 프론트엔드 프로젝트 생성
1. 프로젝트 루트에서 `frontend` 폴더에 React + Vite 프로젝트 생성:
- `npm create vite@latest frontend -- --template react`
- `cd frontend && npm install`
2. 필요한 패키지 설치:
- `npm install axios`
- `npm install -D tailwindcss postcss autoprefixer`
- `npx tailwindcss init -p`
3. Tailwind CSS 설정:
- `tailwind.config.js`의 content에 `"./index.html", "./src/**/*.{js,jsx}"`추가
- `src/index.css`에 Tailwind directives 추가:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
4. Axios 인스턴스 설정 (`src/api/axios.js`):
```javascript
import axios from 'axios';
const api = axios.create({
baseURL: 'http://127.0.0.1:8000/api',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
});
export default api;
```
5. 기본 컴포넌트 구조 생성:
- `src/components/ChallengeList.jsx` (빈 컴포넌트)
- `src/components/ChallengeForm.jsx` (빈 컴포넌트)
- `src/components/ChallengeCard.jsx` (빈 컴포넌트)
6. `src/App.jsx`를 다음과 같이 수정:
- Tailwind 스타일 적용된 레이아웃
- 헤더에 "운동 챌린지 트래커" 제목
- ChallengeForm과 ChallengeList 컴포넌트 import 및 배치
7. 개발 서버 실행: `npm run dev` (http://localhost:5173)
기대 결과: React 프로젝트가 frontend 폴더에 생성되고, Tailwind CSS가 설정됩니다. Axios 인스턴스가 Laravel API와 통신할 준비가 되며, 기본 컴포넌트 구조가 갖춰집니다.
# 챌린지 목록 조회 및 카드 UI 구현
1. `ChallengeList.jsx` 구현:
- useState로 challenges 배열 상태 관리
- useEffect에서 api.get('/challenges')로 데이터 fetch
- loading 상태 추가 ("로딩 중..." 표시)
- challenges.map()으로 각 챌린지를 ChallengeCard에 전달
- 빈 상태일 때 "아직 챌린지가 없습니다" 메시지
2. `ChallengeCard.jsx` 구현:
- props로 challenge 객체 받기 (title, description, target_days, check_ins_count)
- Tailwind로 카드 스타일링:
- 흰색 배경, 그림자, 둥근 모서리
- 제목은 font-bold text-lg
- 설명은 text-gray-600
- 진행률 계산: `(check_ins_count / target_days) * 100`
- 프로그레스 바 표시:
- 전체 너비 회색 배경
- 진행률만큼 파란색으로 채워진 바
- 퍼센트 텍스트 표시 (예: "45%")
- "오늘 인증하기" 버튼 (일단 클릭 이벤트는 비워둠)
- "삭제" 버튼 (일단 클릭 이벤트는 비워둠)
3. 스타일링 개선:
- 카드들을 grid로 배치 (grid-cols-1 md:grid-cols-2 lg:grid-cols-3)
- 간격 gap-4
- 반응형 디자인 적용
4. 브라우저에서 확인:
- Laravel 서버와 React 서버 둘 다 실행 중인지 확인
- 챌린지 목록이 표시되는지 확인 (아직 데이터가 없으면 빈 상태 메시지)
기대 결과: React 앱에서 Laravel API로부터 챌린지 목록을 불러와 카드 형태로 표시합니다. 각 카드에는 제목, 설명, 진행률 바가 표시되며, Tailwind CSS로 깔끔하게 스타일링됩니다.
# 챌린지 생성 폼 및 체크인 기능 구현
1. `ChallengeForm.jsx` 구현:
- useState로 폼 필드 관리 (title, description, targetDays)
- targetDays 기본값은 30
- 폼 제출 시:
- api.post('/challenges', { title, description, target_days: targetDays })
- 성공 시 폼 초기화
- props로 받은 onChallengeCreated 콜백 호출 (목록 새로고침용)
- Tailwind로 폼 스타일링:
- input, textarea에 border, padding, rounded 적용
- "챌린지 추가" 버튼은 파란색 배경
2. `App.jsx` 수정:
- refreshChallenges 함수 생성 (ChallengeList의 데이터 새로고침)
- ChallengeForm에 onChallengeCreated={refreshChallenges} 전달
- ChallengeList에도 refresh 함수 전달
3. `ChallengeCard.jsx`에 체크인 기능 추가:
- "오늘 인증하기" 버튼 클릭 시:
- api.post(`/challenges/${challenge.id}/check-in`)
- 성공 시 alert("오늘 운동 인증 완료!") 또는 토스트 메시지
- props로 받은 onCheckIn 콜백 호출 (목록 새로고침)
- 이미 오늘 체크인했으면 버튼 비활성화 또는 "완료" 표시
- 이를 위해 API에서 today_checked 필드 추가 필요 (Laravel 컨트롤러 수정)
4. Laravel ChallengeController의 index() 메서드 수정:
- 각 챌린지에 오늘 체크인 여부 추가:
```php
$challenges = Challenge::withCount('checkIns')
->get()
->map(function ($challenge) {
$challenge->today_checked = $challenge->checkIns()
->whereDate('check_date', Carbon::today())
->exists();
return $challenge;
});
```
5. 체크인 삭제 기능:
- 오늘 체크인한 경우 "취소" 버튼 표시
- 클릭 시 해당 check_in id로 DELETE 요청
6. 챌린지 삭제 기능:
- "삭제" 버튼 클릭 시 확인 다이얼로그
- api.delete(`/challenges/${challenge.id}`)
- 성공 시 목록 새로고침
기대 결과: 사용자가 새 챌린지를 추가하고, 매일 운동 인증을 체크할 수 있습니다. 체크인 시 진행률이 실시간으로 업데이트되며, 오늘 이미 체크인한 경우 버튼이 비활성화되거나 "완료" 상태로 표시됩니다. 챌린지 삭제도 가능합니다.
제출된 작품 (0)
로그인 후 제출아직 제출된 작품이 없습니다. 첫 번째 도전자가 되어보세요!