Implement car reservation schedule management system
Co-authored-by: pdf114514 <57948770+pdf114514@users.noreply.github.com> Agent-Logs-Url: https://github.com/pdf114514/CarReservation/sessions/1d8c6b05-0e8d-4484-a2d8-8d427dfad9cb
This commit is contained in:
1314
backend/package-lock.json
generated
Normal file
1314
backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
backend/package.json
Normal file
21
backend/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"dev": "node server.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"better-sqlite3": "^12.8.0",
|
||||
"cors": "^2.8.6",
|
||||
"express": "^5.2.1",
|
||||
"express-rate-limit": "^8.3.1"
|
||||
}
|
||||
}
|
||||
140
backend/server.js
Normal file
140
backend/server.js
Normal file
@@ -0,0 +1,140 @@
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const rateLimit = require('express-rate-limit');
|
||||
const Database = require('better-sqlite3');
|
||||
const path = require('path');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3001;
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Apply rate limiting to all API routes
|
||||
const apiLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||
max: 300, // limit each IP to 300 requests per windowMs
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
message: { error: 'リクエストが多すぎます。しばらくしてから再試行してください。' },
|
||||
});
|
||||
app.use('/api', apiLimiter);
|
||||
|
||||
const dbPath = path.join(__dirname, 'data.db');
|
||||
const db = new Database(dbPath);
|
||||
|
||||
// Initialize database schema
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS cars (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT DEFAULT ''
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS reservations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
car_id INTEGER NOT NULL,
|
||||
start_date TEXT NOT NULL,
|
||||
end_date TEXT NOT NULL,
|
||||
customer_name TEXT DEFAULT '',
|
||||
notes TEXT DEFAULT '',
|
||||
FOREIGN KEY (car_id) REFERENCES cars(id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
|
||||
// Seed some initial cars if none exist
|
||||
const carCount = db.prepare('SELECT COUNT(*) as cnt FROM cars').get();
|
||||
if (carCount.cnt === 0) {
|
||||
const insertCar = db.prepare('INSERT INTO cars (name, description) VALUES (?, ?)');
|
||||
insertCar.run('代車 A', '');
|
||||
insertCar.run('代車 B', '');
|
||||
insertCar.run('代車 C', '');
|
||||
}
|
||||
|
||||
// --- Cars API ---
|
||||
app.get('/api/cars', (req, res) => {
|
||||
const cars = db.prepare('SELECT * FROM cars ORDER BY id').all();
|
||||
res.json(cars);
|
||||
});
|
||||
|
||||
app.post('/api/cars', (req, res) => {
|
||||
const { name, description = '' } = req.body;
|
||||
if (!name || !name.trim()) {
|
||||
return res.status(400).json({ error: '車名は必須です' });
|
||||
}
|
||||
const result = db.prepare('INSERT INTO cars (name, description) VALUES (?, ?)').run(name.trim(), description);
|
||||
const car = db.prepare('SELECT * FROM cars WHERE id = ?').get(result.lastInsertRowid);
|
||||
res.status(201).json(car);
|
||||
});
|
||||
|
||||
app.put('/api/cars/:id', (req, res) => {
|
||||
const { name, description } = req.body;
|
||||
if (!name || !name.trim()) {
|
||||
return res.status(400).json({ error: '車名は必須です' });
|
||||
}
|
||||
const result = db.prepare('UPDATE cars SET name = ?, description = ? WHERE id = ?').run(name.trim(), description ?? '', req.params.id);
|
||||
if (result.changes === 0) {
|
||||
return res.status(404).json({ error: '車が見つかりません' });
|
||||
}
|
||||
const car = db.prepare('SELECT * FROM cars WHERE id = ?').get(req.params.id);
|
||||
res.json(car);
|
||||
});
|
||||
|
||||
app.delete('/api/cars/:id', (req, res) => {
|
||||
const result = db.prepare('DELETE FROM cars WHERE id = ?').run(req.params.id);
|
||||
if (result.changes === 0) {
|
||||
return res.status(404).json({ error: '車が見つかりません' });
|
||||
}
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
// --- Reservations API ---
|
||||
app.get('/api/reservations', (req, res) => {
|
||||
const reservations = db.prepare('SELECT * FROM reservations ORDER BY start_date').all();
|
||||
res.json(reservations);
|
||||
});
|
||||
|
||||
app.post('/api/reservations', (req, res) => {
|
||||
const { car_id, start_date, end_date, customer_name = '', notes = '' } = req.body;
|
||||
if (!car_id || !start_date || !end_date) {
|
||||
return res.status(400).json({ error: 'car_id, start_date, end_date は必須です' });
|
||||
}
|
||||
if (start_date > end_date) {
|
||||
return res.status(400).json({ error: '開始日は終了日以前である必要があります' });
|
||||
}
|
||||
const result = db.prepare(
|
||||
'INSERT INTO reservations (car_id, start_date, end_date, customer_name, notes) VALUES (?, ?, ?, ?, ?)'
|
||||
).run(car_id, start_date, end_date, customer_name, notes);
|
||||
const reservation = db.prepare('SELECT * FROM reservations WHERE id = ?').get(result.lastInsertRowid);
|
||||
res.status(201).json(reservation);
|
||||
});
|
||||
|
||||
app.put('/api/reservations/:id', (req, res) => {
|
||||
const { car_id, start_date, end_date, customer_name, notes } = req.body;
|
||||
if (!car_id || !start_date || !end_date) {
|
||||
return res.status(400).json({ error: 'car_id, start_date, end_date は必須です' });
|
||||
}
|
||||
if (start_date > end_date) {
|
||||
return res.status(400).json({ error: '開始日は終了日以前である必要があります' });
|
||||
}
|
||||
const result = db.prepare(
|
||||
'UPDATE reservations SET car_id = ?, start_date = ?, end_date = ?, customer_name = ?, notes = ? WHERE id = ?'
|
||||
).run(car_id, start_date, end_date, customer_name ?? '', notes ?? '', req.params.id);
|
||||
if (result.changes === 0) {
|
||||
return res.status(404).json({ error: '予約が見つかりません' });
|
||||
}
|
||||
const reservation = db.prepare('SELECT * FROM reservations WHERE id = ?').get(req.params.id);
|
||||
res.json(reservation);
|
||||
});
|
||||
|
||||
app.delete('/api/reservations/:id', (req, res) => {
|
||||
const result = db.prepare('DELETE FROM reservations WHERE id = ?').run(req.params.id);
|
||||
if (result.changes === 0) {
|
||||
return res.status(404).json({ error: '予約が見つかりません' });
|
||||
}
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on http://localhost:${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user