๐ธ ์ธ๋ ์ํฐ์คํธ ํฌ ๋ ํฐ ์์ ํจ - ํฌ๊ณผ์ ์ํต ๊ณต๊ฐ
indie-artist-fanmail-inbox
๋ฌธ์ ์ค๋ช
๐ค ํ๋ก์ ํธ ๊ฐ์
์ธ๋ ๋ฎค์ง์ , ์๊ฐ, ํฌ๋ฆฌ์์ดํฐ๋ฅผ ์ํ ํฌ ๋ ํฐ ์์ ํ๋ซํผ์ ๋๋ค. ํฌ๋ค์ด ์์ ๋ฉ์์ง๋ฅผ ๋จ๊ธฐ๋ฉด ์ํฐ์คํธ๊ฐ ์น์์ ํ์ธํ๊ณ ๋ต์ฅ์ ๋ณด๋ผ ์ ์๋ ๋ฐ๋ปํ ์ํต ๊ณต๊ฐ์ ๋ง๋ญ๋๋ค.
โจ ํ์ ๊ธฐ๋ฅ
- ํฌ ๋ ํฐ ์์ฑ ํผ: ๋๋ค์, ์ ๋ชฉ, ๋ด์ฉ, ์ด๋ฉ์ผ(์ ํ) ์ ๋ ฅ
- ๋ ํฐ ๋ชฉ๋ก ์กฐํ: ์ต์ ์์ผ๋ก ๋ฐ์ ํฌ ๋ ํฐ ๋ฆฌ์คํธ ํ์
- ๋ ํฐ ์์ธ ๋ณด๊ธฐ: ๊ฐ๋ณ ๋ ํฐ ์ ๋ฌธ ์ฝ๊ธฐ
- ๋ต์ฅ ์์ฑ: ์ํฐ์คํธ๊ฐ ํฌ์๊ฒ ๋ต์ฅ ๋จ๊ธฐ๊ธฐ (๊ฐ์ ๋ ํฐ ์ค๋ ๋์ ํ์)
- ๊ฐ์ ์ด๋ชจ์ง: ๊ฐ ๋ ํฐ์ ํํธ/๋ณ/๋ฐ์ ์ด๋ชจ์ง ๋ฐ์ ์ถ๊ฐ
- ๋ฐ์ํ ๋์์ธ: ๋ชจ๋ฐ์ผ์์๋ ํธํ๊ฒ ํฌ ๋ ํฐ ์์ฑ
๐ ๋ณด๋์ค ๊ธฐ๋ฅ
- ๋ ํฐ ๊ฒ์ (์ ๋ชฉ/๋ด์ฉ ํค์๋)
- ์ฝ์/์์ฝ์ ์ํ ํ์
- ์คํธ ํํฐ๋ง (๊ฐ๋จํ ํค์๋ ์ฐจ๋จ)
- ๋ ํฐ ์์ฑ ์ ๊ฐ๋จํ ์ ๋๋ฉ์ด์ ํจ๊ณผ
- ํต๊ณ ๋์๋ณด๋ (์ด๋ฒ ๋ฌ ๋ฐ์ ๋ ํฐ ์, ๊ฐ์ฅ ๋ง์ด ๋ฐ์ ์ด๋ชจ์ง ๋ฑ)
๐ฏ ํ์ต ๋ชฉํ
- Laravel 13.x RESTful API ์ค๊ณ (CRUD)
- React 19 ์ปดํฌ๋ํธ ๊ตฌ์ฑ (ํผ, ๋ฆฌ์คํธ, ์์ธ)
- fetch/axios๋ฅผ ์ด์ฉํ API ํธ์ถ
- useState๋ก ์ํ ๊ด๋ฆฌ
- SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ง์ด๊ทธ๋ ์ด์
- Tailwind CSS๋ก ๊ฐ์ฑ์ ์ธ UI ๋์์ธ
์ ์ฝ ์กฐ๊ฑด
- โข Laravel 13.x ๋ฐฑ์๋ (API ์๋ฒ)
- โข React 19 ํ๋ก ํธ์๋ (Vite)
- โข SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค
- โข Tailwind CSS ์คํ์ผ๋ง
- โข RESTful API ์ค๊ณ (/api/letters)
- โข ๋ณ๋ ์ธ์ฆ ์์คํ ์์ (๊ฐ๋จํ ๋๋ค์ ๊ธฐ๋ฐ)
- โข ์ค์๊ฐ ์ฑํ ๊ธฐ๋ฅ ์์ (HTTP ๊ธฐ๋ฐ ๋๊ธ/๋ต์ฅ๋ง)
- โข ๋ณต์กํ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ๊ธ์ง (useState๋ง ์ฌ์ฉ)
ํ๋กฌํํธ ๋ ์ํผ
์๋ ํ๋กฌํํธ๋ฅผ ์์๋๋ก AI์๊ฒ ๋ณด๋ด๋ฉด ๋ฉ๋๋ค. ๋ณต์ฌ ๋ฒํผ์ ๋๋ฌ ๋ฐ๋ก ์ฌ์ฉํ์ธ์.
mkdir indie-artist-fanmail-inbox && cd indie-artist-fanmail-inbox
์ด ํด๋์์ ํ๋ก์ ํธ๋ฅผ ์์ํฉ๋๋ค.
Laravel 13.x ๋ฐฑ์๋ API ์๋ฒ๋ฅผ ์์ฑํ์ธ์.
1. `backend` ํด๋์ Laravel 13.x ํ๋ก์ ํธ ์์ฑ
2. SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ (.env ํ์ผ์์ DB_CONNECTION=sqlite)
3. `letters` ํ
์ด๋ธ ๋ง์ด๊ทธ๋ ์ด์
์์ฑ:
- id (Primary Key)
- nickname (string, ํฌ ๋๋ค์)
- title (string, ๋ ํฐ ์ ๋ชฉ)
- content (text, ๋ ํฐ ๋ด์ฉ)
- email (string, nullable, ์ ํ์ ์ด๋ฉ์ผ)
- emoji_reaction (string, nullable, ์ด๋ชจ์ง ๋ฐ์: heart/star/clap)
- is_read (boolean, default false, ์ฝ์ ์ฌ๋ถ)
- reply (text, nullable, ์ํฐ์คํธ ๋ต์ฅ)
- timestamps
4. ๋ง์ด๊ทธ๋ ์ด์
์คํ (`php artisan migrate`)
5. CORS ์ค์ (ํ๋ก ํธ์๋ http://localhost:5173์์ ์ ๊ทผ ํ์ฉ)
6. API ๋ผ์ฐํธ ์ค์ (routes/api.php):
- GET /api/letters (๋ชจ๋ ๋ ํฐ ์กฐํ)
- POST /api/letters (์ ๋ ํฐ ์์ฑ)
- GET /api/letters/{id} (๋ ํฐ ์์ธ ์กฐํ)
- PUT /api/letters/{id}/reply (๋ต์ฅ ์์ฑ)
- PATCH /api/letters/{id}/emoji (์ด๋ชจ์ง ๋ฐ์ ์ถ๊ฐ)
- PATCH /api/letters/{id}/read (์ฝ์ ํ์)
7. LetterController ์์ฑ ๋ฐ ๊ฐ ์๋ํฌ์ธํธ ๊ตฌํ
8. ๊ฐ๋ฐ ์๋ฒ ์คํ (`php artisan serve`)
๋ชจ๋ API ์๋ํฌ์ธํธ๊ฐ ์ ์ ์๋ํ๋์ง ํ์ธํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: Laravel ๋ฐฑ์๋ API ์๋ฒ๊ฐ http://localhost:8000์์ ์คํ๋๊ณ , /api/letters ์๋ํฌ์ธํธ๊ฐ ์ ์ ์๋ตํฉ๋๋ค. SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค์ letters ํ ์ด๋ธ์ด ์์ฑ๋๊ณ , CORS๊ฐ ์ค์ ๋์ด ํ๋ก ํธ์๋์์ ์ ๊ทผ ๊ฐ๋ฅํฉ๋๋ค.
React 19 ํ๋ก ํธ์๋ ํ๋ก์ ํธ๋ฅผ ์์ฑํ์ธ์. 1. ํ๋ก์ ํธ ๋ฃจํธ์์ `frontend` ํด๋์ Vite + React 19 ํ๋ก์ ํธ ์์ฑ 2. Tailwind CSS ์ค์น ๋ฐ ์ค์ 3. ๊ธฐ๋ณธ ํด๋ ๊ตฌ์กฐ ์์ฑ: - src/components (์ฌ์ฌ์ฉ ์ปดํฌ๋ํธ) - src/pages (ํ์ด์ง ์ปดํฌ๋ํธ) - src/api (API ํธ์ถ ํจ์) 4. axios ์ค์น ๋ฐ API ๋ฒ ์ด์ค URL ์ค์ (http://localhost:8000/api) 5. ๊ธฐ๋ณธ ๋ ์ด์์ ์ปดํฌ๋ํธ ์์ฑ: - ํค๋: "๐ ํฌ ๋ ํฐํจ" ํ์ดํ, ์ํฐ์คํธ ํ๋กํ ์์ญ - ๋ฉ์ธ ์ปจํ ์ธ ์์ญ - ํธํฐ: ๊ฐ๋จํ ์ ์๊ถ ์ ๋ณด 6. Tailwind๋ก ๋ฐ๋ปํ๊ณ ๊ฐ์ฑ์ ์ธ ๋์์ธ ์ ์ฉ (ํ์คํ ํค, ๋ถ๋๋ฌ์ด ๊ทธ๋ผ๋ฐ์ด์ ) 7. ๊ฐ๋ฐ ์๋ฒ ์คํ (`npm run dev`) React ์ฑ์ด http://localhost:5173์์ ์คํ๋๊ณ ๊ธฐ๋ณธ ๋ ์ด์์์ด ํ์๋๋์ง ํ์ธํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: React ํ๋ก ํธ์๋๊ฐ http://localhost:5173์์ ์คํ๋๊ณ , Tailwind CSS๊ฐ ์ ์ฉ๋ ๊ธฐ๋ณธ ๋ ์ด์์(ํค๋, ๋ฉ์ธ, ํธํฐ)์ด ํ๋ฉด์ ํ์๋ฉ๋๋ค. axios๊ฐ ์ค์น๋์ด API ํธ์ถ ์ค๋น๊ฐ ์๋ฃ๋ฉ๋๋ค.
ํฌ ๋ ํฐ ์์ฑ ํผ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌํํ์ธ์. 1. `src/components/LetterForm.jsx` ์์ฑ 2. ์ ๋ ฅ ํ๋: - ๋๋ค์ (ํ์) - ์ ๋ชฉ (ํ์) - ๋ด์ฉ (textarea, ํ์) - ์ด๋ฉ์ผ (์ ํ) 3. useState๋ก ํผ ์ํ ๊ด๋ฆฌ 4. ์ ์ถ ๋ฒํผ ํด๋ฆญ ์ POST /api/letters API ํธ์ถ 5. ์ ์ถ ์ฑ๊ณต ์: - ํผ ์ด๊ธฐํ - ์ฑ๊ณต ๋ฉ์์ง ํ์ (3์ด ํ ์๋ ์ฌ๋ผ์ง) - ๋ ํฐ ๋ชฉ๋ก ์๋ก๊ณ ์นจ 6. ์ ํจ์ฑ ๊ฒ์ฌ: - ํ์ ํ๋ ๋น์ด์์ผ๋ฉด ์๋ฌ ๋ฉ์์ง - ์ด๋ฉ์ผ ํ์ ๊ฒ์ฆ (์ ํ ํ๋์ด์ง๋ง ์ ๋ ฅ ์) 7. Tailwind๋ก ์๋ฆ๋ค์ด ํผ ๋์์ธ: - ๋ถ๋๋ฌ์ด ์ธํ ์คํ์ผ - ํธ๋ฒ/ํฌ์ปค์ค ํจ๊ณผ - ์ ์ถ ๋ฒํผ ์ ๋๋ฉ์ด์ 8. App.jsx์ LetterForm ์ปดํฌ๋ํธ ์ถ๊ฐ ํฌ ๋ ํฐ ์์ฑ ํผ์ด ํ๋ฉด์ ํ์๋๊ณ , ๋ ํฐ๋ฅผ ์ ์ถํ๋ฉด ๋ฐฑ์๋ API๋ก ๋ฐ์ดํฐ๊ฐ ์ ์ก๋๋์ง ํ์ธํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: ํฌ ๋ ํฐ ์์ฑ ํผ์ด ํ๋ฉด์ ํ์๋๊ณ , ๋๋ค์/์ ๋ชฉ/๋ด์ฉ์ ์ ๋ ฅํ ํ ์ ์ถ ๋ฒํผ์ ๋๋ฅด๋ฉด Laravel API๋ก POST ์์ฒญ์ด ์ ์ก๋ฉ๋๋ค. ์ ์ถ ์ฑ๊ณต ์ ํผ์ด ์ด๊ธฐํ๋๊ณ ์ฑ๊ณต ๋ฉ์์ง๊ฐ ํ์๋ฉ๋๋ค.
ํฌ ๋ ํฐ ๋ชฉ๋ก ๋ฐ ์์ธ ๋ณด๊ธฐ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌํํ์ธ์.
1. `src/components/LetterList.jsx` ์์ฑ:
- useEffect๋ก ์ปดํฌ๋ํธ ๋ง์ดํธ ์ GET /api/letters ํธ์ถ
- useState๋ก ๋ ํฐ ๋ชฉ๋ก ์ํ ๊ด๋ฆฌ
- ๋ ํฐ๋ฅผ ์นด๋ ํํ๋ก ๋ฆฌ์คํธ ๋ ๋๋ง
- ๊ฐ ์นด๋์ ๋๋ค์, ์ ๋ชฉ, ์์ฑ ๋ ์ง, ์ฝ์ ์ฌ๋ถ ๋ฐฐ์ง ํ์
- ์นด๋ ํด๋ฆญ ์ ์์ธ ๋ณด๊ธฐ๋ก ์ด๋
2. `src/components/LetterDetail.jsx` ์์ฑ:
- ๋ ํฐ ID๋ฅผ props๋ก ๋ฐ์ GET /api/letters/{id} ํธ์ถ
- ๋ ํฐ ์ ๋ฌธ ํ์ (๋๋ค์, ์ ๋ชฉ, ๋ด์ฉ, ์ด๋ฉ์ผ, ์์ฑ ๋ ์ง)
- ์ด๋ชจ์ง ๋ฐ์ ๋ฒํผ (ํํธ/๋ณ/๋ฐ์) ์ถ๊ฐ
- ์ด๋ชจ์ง ํด๋ฆญ ์ PATCH /api/letters/{id}/emoji ํธ์ถ
- ๋ต์ฅ ์์ฑ ํผ (textarea + ์ ์ถ ๋ฒํผ)
- ๋ต์ฅ ์ ์ถ ์ PUT /api/letters/{id}/reply ํธ์ถ
- ๋ต์ฅ์ด ์์ผ๋ฉด ๋ ํฐ ์๋์ ํ์
- ๋ค๋ก๊ฐ๊ธฐ ๋ฒํผ (๋ชฉ๋ก์ผ๋ก ๋์๊ฐ๊ธฐ)
3. ๋ชฉ๋ก๊ณผ ์์ธ ๋ณด๊ธฐ๋ฅผ ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ผ๋ก ์ ํ (useState๋ก ์ ํ๋ ๋ ํฐ ID ๊ด๋ฆฌ)
4. Tailwind๋ก ์นด๋ ๋์์ธ:
- ํธ๋ฒ ์ ์ด์ง ๋ ์ค๋ฅด๋ ํจ๊ณผ
- ์ฝ์/์์ฝ์ ์ํ์ ๋ฐ๋ผ ๋ฐฐ์ง ์์ ๋ณ๊ฒฝ
- ์ด๋ชจ์ง ๋ฐ์ ๋ฒํผ ์ ๋๋ฉ์ด์
๋ ํฐ ๋ชฉ๋ก์ด ํ์๋๊ณ , ์นด๋ ํด๋ฆญ ์ ์์ธ ๋ณด๊ธฐ๋ก ์ ํ๋๋ฉฐ, ์ด๋ชจ์ง ๋ฐ์๊ณผ ๋ต์ฅ ์์ฑ์ด ๊ฐ๋ฅํ์ง ํ์ธํ์ธ์.
๊ธฐ๋ ๊ฒฐ๊ณผ: ๋ ํฐ ๋ชฉ๋ก์ด ์นด๋ ํํ๋ก ํ์๋๊ณ , ์นด๋๋ฅผ ํด๋ฆญํ๋ฉด ์์ธ ๋ณด๊ธฐ ํ๋ฉด์ผ๋ก ์ ํ๋ฉ๋๋ค. ์์ธ ๋ณด๊ธฐ์์ ์ด๋ชจ์ง ๋ฐ์ ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ฐฑ์๋์ PATCH ์์ฒญ์ด ์ ์ก๋๊ณ , ๋ต์ฅ์ ์์ฑํ์ฌ ์ ์ถํ๋ฉด PUT ์์ฒญ์ด ์ ์ก๋ฉ๋๋ค. ๋ต์ฅ์ด ์๋ ๋ ํฐ๋ ๋ต์ฅ ๋ด์ฉ์ด ํจ๊ป ํ์๋ฉ๋๋ค.
์ ์ถ๋ ์ํ (0)
๋ก๊ทธ์ธ ํ ์ ์ถ์์ง ์ ์ถ๋ ์ํ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋์ ์๊ฐ ๋์ด๋ณด์ธ์!