당신의 승리를 축하하기: 한 주를 잊을 수 없게 만든 이유
Source: Dev.to
개발자들은 종종 깨진 부분, 다음에 할 일, 아직 배포하지 않은 것에 집중합니다. 하지만 성장은 실제로 잘 된 일을 멈춰서 되돌아볼 때 일어납니다 — 고친 작은 버그, 배포한 기능, 혹은 마침내 이해한 새로운 개념 말이죠.
이번 튜토리얼에서는 Node.js와 Express를 사용해 **“주간 성과 트래커”**를 간단히 만들어 보겠습니다. 데이터는 JSON 파일에 저장됩니다. 초보자도 쉽게 따라 할 수 있는 코드 중심 예제로, 한 주씩 여러분의 진행 상황을 축하할 수 있게 설계되었습니다.
튜토리얼을 마치면 다음과 같은 기능을 갖춘 웹 앱을 얻게 됩니다:
- 주간 성과를 추가하기
- 모든 성과 보기
- 이모지 콘페티 🎉 로 진행 상황을 축하하기
시작해 볼까요?
1단계: 프로젝트 설정
새 디렉터리를 만들고 Node.js 프로젝트를 초기화합니다:
mkdir weekly-wins-tracker
cd weekly-wins-tracker
npm init -y
Express 설치:
npm install express
nodemon을 설치하여 개발 중 자동 재시작을 가능하게 합니다 (선택 사항이지만 권장됩니다):
npm install --save-dev nodemon
package.json 스크립트를 업데이트합니다:
{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
}
}
Step 2: 서버 만들기
server.js 생성:
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const PORT = 3000;
// Middleware to parse JSON and serve static files
app.use(express.json());
app.use(express.static('public'));
우리는 다음을 사용합니다:
express.json()은 들어오는 JSON을 파싱합니다express.static('public')은 HTML, CSS, 그리고 JS 파일을 제공합니다
Step 3: 데이터 저장소 설정
우리는 승리를 wins.json이라는 JSON 파일에 저장합니다.
프로젝트 루트에 wins.json을 생성하세요:
[]
승리를 읽고 쓰는 헬퍼 함수를 추가합니다:
const WINS_FILE = path.join(__dirname, 'wins.json');
// Read wins from file
function readWins() {
const data = fs.readFileSync(WINS_FILE);
return JSON.parse(data);
}
// Write wins to file
function writeWins(wins) {
fs.writeFileSync(WINS_FILE, JSON.stringify(wins, null, 2));
}
4단계: API 엔드포인트 구축
우리는 세 개의 라우트를 만들 것입니다:
GET /wins– 모든 승리 항목 가져오기POST /wins– 새로운 승리 항목 추가하기GET /– 프론트엔드 제공하기
라우트를 추가합니다:
// Get all wins
app.get('/wins', (req, res) => {
try {
const wins = readWins();
res.json(wins);
} catch (err) {
res.status(500).json({ error: 'Failed to read wins' });
}
});
// Add a new win
app.post('/wins', (req, res) => {
const { text } = req.body;
if (!text || text.trim() === '') {
return res.status(400).json({ error: 'Win text is required' });
}
const newWin = {
id: Date.now().toString(),
text: text.trim(),
date: new Date().toISOString().split('T')[0]
};
const wins = readWins();
wins.push(newWin);
writeWins(wins);
res.status(201).json(newWin);
});
server.js 파일의 마지막에 서버를 시작하는 것을 잊지 마세요:
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
5단계: 프론트엔드 만들기
public 폴더를 만들고 index.html을 추가하세요:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Weekly Wins Tracker</title>
<style>
body {
font-family: 'Segoe UI', sans-serif;
max-width: 600px;
margin: 40px auto;
padding: 20px;
background: #f9f9ff;
color: #333;
}
h1 { color: #4a4a98; text-align: center; }
input, button {
padding: 10px;
margin: 10px 0;
width: 100%;
box-sizing: border-box;
}
button {
background: #4a4a98;
color: white;
border: none;
cursor: pointer;
}
ul {
list-style: none;
padding: 0;
}
li {
background: white;
margin: 8px 0;
padding: 12px;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.confetti {
font-size: 1.5em;
margin-right: 8px;
}
</style>
</head>
<body>
<h1>🎉 Celebrate Your Wins</h1>
<input type="text" id="winInput" placeholder="What did you achieve this week?" />
<button onclick="addWin()">Add Win</button>
<ul id="winsList"></ul>
<script>
// Load wins on page load
window.onload = loadWins;
async function loadWins() {
const res = await fetch('/wins');
const wins = await res.json();
const list = document.getElementById('winsList');
list.innerHTML = '';
wins.forEach(win => {
const li = document.createElement('li');
li.innerHTML = `🎊${win.text} (${win.date})`;
list.appendChild(li);
});
}
async function addWin() {
const input = document.getElementById('winInput');
const text = input.value.trim();
if (!text) return;
const res = await fetch('/wins', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text })
});
if (res.ok) {
input.value = '';
loadWins();
} else {
const err = await res.json();
alert(err.error);
}
}
</script>
</body>
</html>
이제 앱을 실행하세요:
npm run dev # or npm start
브라우저에서 http://localhost:3000을 열고, 몇 개의 승리를 추가하면, 축하 효과와 함께 리스트가 늘어나는 것을 볼 수 있습니다! 🎉