2025. 5. 15. 12:46ㆍSvelte
목표
- Svelte로 할 일 목록 추가/삭제/완료 체크
- PHP API로 MySQL CRUD 연결
- 초간단 풀스택 SPA 만들기
✅ 심플한 "To-Do 리스트" with Svelte + PHP + MySQL
- 기능: 할 일을 추가/삭제/완료 체크 (SPA)
- 구성:
- Svelte로 프론트엔드 구현
- PHP로 CRUD API
- MySQL에 할 일 저장
- 목표: Svelte의 상태관리 & PHP API + DB 연동 연습
To-Do 리스트 |
Svelte + PHP CRUD |
🛠️ 개발 순서 백엔드 -> 프론트엔드
백엔드 만들기 시작
1️⃣ MySQL 테이블 만들기 (attendance.sql)
CREATE DATABASE todo_app;
USE todo_app;
CREATE TABLE todos (
id INT AUTO_INCREMENT PRIMARY KEY,
task TEXT NOT NULL,
completed BOOLEAN DEFAULT FALSE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
2️⃣ PHP 서버 API 만들기
config.php (DB연결)
<?php
$host = "localhost";
$user = "root";
$pass = "1234"; // 비밀번호 수정
$db = "todo_app";
$conn = new mysqli($host, $user, $pass, $db);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
?>
getTodos.php
<?php
include("../db/config.php");
$result = $conn->query("SELECT * FROM todos ORDER BY created_at DESC");
$todos = [];
while($row = $result->fetch_assoc()) {
$todos[] = $row;
}
echo json_encode($todos);
?>
addTodo.php
<?php
include("../db/config.php");
$task = $_POST['task'] ?? '';
if ($task) {
$stmt = $conn->prepare("INSERT INTO todos (task) VALUES (?)");
$stmt->bind_param("s", $task);
$stmt->execute();
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "no task"]);
}
?>
deleteTodo.php
<?php
include("../db/config.php");
$id = $_POST['id'] ?? '';
if ($id) {
$stmt = $conn->prepare("DELETE FROM todos WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "no id"]);
}
?>
toggleTodo.php
<?php
include("../db/config.php");
$id = $_POST['id'] ?? '';
if ($id) {
$stmt = $conn->prepare("UPDATE todos SET completed = NOT completed WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "no id"]);
}
?>
3️⃣ Svelte 프론트엔드 만들기
기본 프로젝트 생성
npx degit sveltejs/template frontend
cd frontend
npm install
npm run dev
Todo.svelte 예시 (코드블럭 선택에서 svelte가 없어서 javascript 선택함)
<script>
import { onMount } from 'svelte';
let todos = [];
let newTask = '';
async function loadTodos() {
const res = await fetch('http://your-server-ip/backend/api/getTodos.php');
todos = await res.json();
}
async function addTodo() {
await fetch('http://your-server-ip/backend/api/addTodo.php', {
method: 'POST',
body: new URLSearchParams({ task: newTask })
});
newTask = '';
loadTodos();
}
async function deleteTodo(id) {
await fetch('http://your-server-ip/backend/api/deleteTodo.php', {
method: 'POST',
body: new URLSearchParams({ id })
});
loadTodos();
}
async function toggleTodo(id) {
await fetch('http://your-server-ip/backend/api/toggleTodo.php', {
method: 'POST',
body: new URLSearchParams({ id })
});
loadTodos();
}
onMount(loadTodos);
</script>
<h1>📝 To-Do List</h1>
<input bind:value={newTask} placeholder="할 일 입력" />
<button on:click={addTodo}>추가</button>
<ul>
{#each todos as todo}
<li>
<input type="checkbox" checked={todo.completed == 1} on:change={() => toggleTodo(todo.id)} />
{todo.task}
<button on:click={() => deleteTodo(todo.id)}>삭제</button>
</li>
{/each}
</ul>
✅ 결과물 정리
구성 요소완료 목표
🖥️ Svelte To-Do SPA | 상태관리, 이벤트 처리 |
🌐 PHP API | CRUD 기능 구현 |
🗄️ MySQL | todos 테이블 구축 |
🛠️ Svelte ↔ PHP API 연결 | fetch 통한 동기화 |
✅ 끝나면 이런 느낌
- Svelte로 CRUD SPA 직접 만들어보기
- PHP API & DB 연동 경험
- 실제 서비스 흐름 체험 (SPA → API → DB)
👍 구현 과정 스크린샷
1️⃣ 준비물 설치
✅ MySQL + PHP 환경 준비
- 로컬에서 XAMPP 설치 (MySQL + Apache 통합 환경)
- 다운로드: https://www.apachefriends.org/index.html
- XAMPP 실행 → Apache + MySQL Start 버튼 클릭
- MySQL 접속 (phpMyAdmin 또는 DBeaver)
- 여기도 접속되면 DB까지 준비 완료
- 실행되면 http://localhost:5173 에서 확인 가능
✅ XAMPP가 뭐하는 놈이냐?
👉 "내 컴퓨터를 웹서버처럼 만들어주는 패키지"
🔽 구체적으로 말하면:
Apache | 웹 서버 | 내 PC를 작은 인터넷 사이트처럼 동작시킴 |
MySQL | 데이터베이스 | 데이터 저장소 (회원정보, 게시판 글 등) |
PHP | 서버 스크립트 언어 | DB와 연결해서 웹페이지를 동적으로 만듦 |
phpMyAdmin | DB 관리 툴 | MySQL을 웹 브라우저에서 쉽게 조작 |
🟡 XAMPP는 위 4개를 "한 번에 설치하고 바로 쓸 수 있게" 묶은 패키지입니다.
- 원래는 다 따로 설치하고 설정해야 하는데 귀찮죠?
- XAMPP는 그냥 1번 설치로 내 PC를 서버처럼 만들어줌.
✅ 정리: 내 로컬에서 이런 걸 하고 싶을 때 씁니다
- PHP + MySQL 웹 개발 테스트 (ex: To-Do 리스트 만들기)
- 서버 없이도 "http://localhost"로 내 웹사이트 돌려보기
- 실제 서버 배포 전에 로컬에서 연습/테스트
✅ 외우기 쉽게
"XAMPP = 내 컴퓨터를 미니 웹서버로 만들어주는 간편 설치세트"
- 👇아래 : 설치 시 경고 메세지 (정확하게는 설치하려고 하는 데 에러 메세지 뜸)
🟡 경고 메시지 해석
"UAC(사용자 계정 컨트롤) 때문에 XAMPP가 제대로 동작하지 않을 수 있다. 특히 C:\Program Files 폴더에 설치하면 권한 문제로 쓰기 제한이 걸릴 수 있으니 다른 경로에 설치해라. 아니면 UAC를 꺼라."
✅ 해결 방법 (추천)
- C:\xampp 또는 D:\xampp 처럼
→ Program Files 폴더가 아닌 곳에 설치하면 문제 없음.- 경로 예: C:\xampp ✅
- 경로 예: C:\Program Files\xampp ❌ (하지 말라는 것)
- UAC(사용자 계정 컨트롤)는 굳이 건드리지 않아도 됩니다.
- 그냥 경로만 조심하면 됩니다.
- 설치 컴포넌트 선택
- 그냥 기본 설정 그대로 두고 "Next"
- Apache (웹서버) ✅
- MySQL ✅
- PHP ✅
- phpMyAdmin ✅
- 기타는 굳이 건드리지 않아도 OK
4. 설치 진행 → Finish- "Do you want to start the Control Panel now?" 체크된 상태로 Finish 클릭
- 그냥 기본 설정 그대로 두고 "Next"
5. XAMPP Control Panel 실행
- Apache → Start ✅
- MySQL → Start ✅
- 두 개가 초록불로 바뀌면 성공!
6. 정상 작동 확인
- 브라우저에 http://localhost 입력 → XAMPP Welcome 페이지 나오면 OK
- phpMyAdmin 확인: http://localhost/phpmyadmin
☑️ PHP API 만들기
✅ 폴더 구조 (XAMPP htdocs 기준)
C:\xampp\htdocs\todo-backend\
├── db\config.php
├── api\getTodos.php
├── api\addTodo.php
├── api\deleteTodo.php
└── api\toggleTodo.php
(코드블럭에 arduino 없어서 javascript 선택함)
☑️ Postman 사용 (정석 방법)
Postman은 API 테스트하는 무료 프로그램입니다.
- Postman 설치 (https://www.postman.com/downloads/)
- 새 요청 만들기
- Method: POST
- URL: http://localhost/todo-backend/api/addTodo.php
- Body → form-data 선택
Key: task, Value: 공부하기 - Send 버튼
- 결과가나오면 성공
-
json복사편집{"status":"success"}
✅ 간단 정리
주소창 GET 테스트 | 👍 매우 쉬움 | 테스트용 임시 |
Postman 테스트 | 실무처럼 정확 | 추천 |
나는 메모장에 하나하나씩 붙여넣고 확장자를 PHP 파일로 변환해서 만듦
✅ [메모장에 만든 예시 하나만] toggleTodo.php 만들기 (완료 여부 토글 API)
➡️ 위치: C:\xampp\htdocs\todo-backend\api\toggleTodo.php
➡️ 파일 내용:
<?php
include("../db/config.php");
$id = $_POST['id'] ?? '';
if ($id) {
$stmt = $conn->prepare("UPDATE todos SET completed = NOT completed WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "no id"]);
}
?>
🔹 설명
- 할 일 ID를 받아서, completed 필드를 0 → 1 또는 1 → 0 으로 반전시킴 (체크 토글)
- 성공 시 {"status":"success"} 반환
✅ 테스트 방법 (Postman)
- 새 요청 → Method: POST
- URL: http://localhost/todo-backend/api/toggleTodo.php
- Body → form-data →
Key: id, Value: (토글할 할 일 id 값, ex: 1) - Send 버튼 클릭
- 결과 → {"status":"success"} 나오면 성공
→ 다시 getTodos.php로 조회하면 completed 값이 0 → 1 로 바뀐 걸 확인할 수 있습니다.
>> 이런 식으로 따라했음!
☑️ Svelte 프론트엔드 만들기
👉 원래는 +page.svelte에서 작성하고 page를 import해서 가져다가 보여주는 방법을 쓰려고 했으나, GPT-4o가 App에서 작성해서 띄우라고 하길래 그렇게 계획을 변경했다.
코드 - 나는 VsCode 사용함
- API 4개 사용 - CRUD
<script>
import { onMount } from 'svelte';
let todos = [];
let newTask = '';
async function loadTodos() {
const res = await fetch('http://localhost/todo-backend/api/getTodos.php');
todos = await res.json();
}
async function addTodo() {
if (!newTask) return;
await fetch('http://localhost/todo-backend/api/addTodo.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ task: newTask })
});
newTask = '';
loadTodos();
}
async function deleteTodo(id) {
await fetch('http://localhost/todo-backend/api/deleteTodo.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ id })
});
loadTodos();
}
async function toggleTodo(id) {
await fetch('http://localhost/todo-backend/api/toggleTodo.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ id })
});
loadTodos();
}
onMount(loadTodos);
</script>
<main>
<h1>📝 To-Do List</h1>
<div class="input-area">
<input bind:value={newTask} placeholder="할 일 입력" />
<button on:click={addTodo}>추가</button>
</div>
<ul>
{#each todos as todo}
<li class:completed={todo.completed == 1}>
<input type="checkbox" checked={todo.completed == 1} on:change={() => toggleTodo(todo.id)} />
{todo.task}
<button on:click={() => deleteTodo(todo.id)}>삭제</button>
</li>
{/each}
</ul>
<h2>🔎 디버그용 개별 확인</h2>
{#if todos[0]}
<p>첫 번째 항목: {todos[0].task} (완료: {todos[0].completed == 1 ? 'O' : 'X'})</p>
{/if}
{#if todos[1]}
<p>두 번째 항목: {todos[1].task} (완료: {todos[1].completed == 1 ? 'O' : 'X'})</p>
{/if}
</main>
<style>
main {
text-align: center;
padding: 2rem;
max-width: 600px;
margin: 0 auto;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 3rem;
margin-bottom: 2rem;
}
.input-area {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
}
input[type="text"] {
width: 60%;
padding: 0.5rem;
font-size: 1rem;
}
button {
padding: 0.5rem 1rem;
background: #ff3e00;
color: white;
border: none;
cursor: pointer;
border-radius: 5px;
}
ul {
list-style: none;
padding: 0;
}
li {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.5rem;
border-bottom: 1px solid #ddd;
}
li.completed {
text-decoration: line-through;
color: #999;
}
li button {
background: #ccc;
color: #333;
border: none;
padding: 0.3rem 0.7rem;
border-radius: 3px;
cursor: pointer;
}
</style>
{#each todos as todo} >> 이 부분이 for 문임
todo.completed 라고만 되어있어서 할일 생성하면 모두 다 완료 표시가 된 채로 생성됬음.
todo.completed 에 ==1 추가해서 수정
웃긴 건, 기본 값이 1이 안한 거고 0이 한 걸로 되어있었음....
보통 0이 안한거고 1이 한건데... ㅋㅋㅋㅋㅋ
GPT-4o도 100% 믿으면 안된다는 것을 실감했다.
✅ 실행 결과
- Svelte 화면에서 할 일 추가
- 체크박스 클릭하면 완료 여부 변경
- 삭제 버튼으로 할 일 삭제
- 모두 MySQL 연동 (실시간 CRUD)
✅ 마무리 체크리스트
✅ | MySQL todos 테이블 생성 |
✅ | PHP API 4종 구현 (조회, 추가, 삭제, 토글) |
✅ | Svelte SPA 기본 셋업 |
✅ | Svelte ↔ PHP API 연동 |
✅ | 리스트 추가/삭제/완료 체크 UI 완성 |
귀여운 todo web app 을 만들어서 기뻤다 ㅋㅋ 아주 귀엽다 ㅋㅋ
💻소감😊
svelte 라는 언어를 사용해서 처음으로 만들어본 웹앱. 전부터 개인프로젝트 해보고 싶었는데 어제 처음 시작을 해봐서 기분이 좋다 ㅎㅎ 오늘은 날씨 앱을 만들어 볼 건데 출근하기 전까지 매일 하루에 하나씩 만드는 게 목표다. 담주 월요일이 첫 출근 ^^ 대표님은 신기술을 가장 먼저 사용해보고 싶어하시는 분이고 직원들도 그런 태도를 가졌으면 좋겠다고 하셨다. 나도 새로운 것을 아주 잘 받아들이는 사람이니까 성향은 비슷하다고 느껴졌다. 스벨트 사용해보니 리액트보다도 코드가 훨씬 간결하고 마치 Streamlit으로 웹앱을 만드는 느낌이 났다~! 물론 그 땐 리액트로 만들었지만 사용하는 언어가 달라진다는 게 아주 재밌는 것 같다. 여러 나라의 언어를 짧은 시간안에 사용하는 것은 어렵지만 로직안에서 문법이 조금씩 변하는 컴퓨터 언어는 오히려 쉽게 다가오는 것 같다. 내가 언어쪽으로는 받아들이는 게 빠른 사람이라서 그런지 컴퓨터 언어도 결국 언어라서 나랑 쉽게 친해지는 것 같다~ 즐겁게 배우자! 마음은 가볍게 가볍게~ 매일 조금씩 나아지고 발전하고 있다는 느낌을 가지고^^ 내가 지금은 실력이 부족해도 기회만 주어진다면 얼마든지 노력해서 발전하고 성장할 수 있다! 라는 자신감을 가진다면 무엇이든 해낼 수 있다는 긍정마인드를 가지자! 아자아자~~!