- Express backend with PostgreSQL (JWT auth, full CRUD) - React + Vite + TailwindCSS frontend in Hebrew (RTL) - Features: Digital Booking System, Guest Management, Smart Budget Management - Docker Compose with postgres healthcheck - Auto-runs migrations on startup Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
75 lines
2.4 KiB
JavaScript
75 lines
2.4 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const pool = require('../db');
|
|
const bcrypt = require('bcryptjs');
|
|
const jwt = require('jsonwebtoken');
|
|
|
|
const JWT_SECRET = process.env.JWT_SECRET || 'airewit-secret-key-2026';
|
|
|
|
// Register
|
|
router.post('/register', async (req, res) => {
|
|
const { email, name, password } = req.body;
|
|
if (!email || !name || !password) {
|
|
return res.status(400).json({ error: 'Missing required fields' });
|
|
}
|
|
try {
|
|
const hashed = await bcrypt.hash(password, 10);
|
|
const result = await pool.query(
|
|
'INSERT INTO users (email, name, password) VALUES ($1, $2, $3) RETURNING id, email, name, created_at',
|
|
[email, name, hashed]
|
|
);
|
|
const user = result.rows[0];
|
|
const token = jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '7d' });
|
|
res.status(201).json({ token, user });
|
|
} catch (err) {
|
|
if (err.code === '23505') {
|
|
return res.status(409).json({ error: 'Email already registered' });
|
|
}
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Server error' });
|
|
}
|
|
});
|
|
|
|
// Login
|
|
router.post('/login', async (req, res) => {
|
|
const { email, password } = req.body;
|
|
if (!email || !password) {
|
|
return res.status(400).json({ error: 'Missing email or password' });
|
|
}
|
|
try {
|
|
const result = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
|
|
if (result.rows.length === 0) {
|
|
return res.status(401).json({ error: 'Invalid credentials' });
|
|
}
|
|
const user = result.rows[0];
|
|
const valid = await bcrypt.compare(password, user.password);
|
|
if (!valid) {
|
|
return res.status(401).json({ error: 'Invalid credentials' });
|
|
}
|
|
const token = jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '7d' });
|
|
res.json({ token, user: { id: user.id, email: user.email, name: user.name } });
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Server error' });
|
|
}
|
|
});
|
|
|
|
// Middleware
|
|
function authMiddleware(req, res, next) {
|
|
const auth = req.headers.authorization;
|
|
if (!auth || !auth.startsWith('Bearer ')) {
|
|
return res.status(401).json({ error: 'Unauthorized' });
|
|
}
|
|
try {
|
|
const token = auth.split(' ')[1];
|
|
const payload = jwt.verify(token, JWT_SECRET);
|
|
req.userId = payload.userId;
|
|
next();
|
|
} catch {
|
|
res.status(401).json({ error: 'Invalid token' });
|
|
}
|
|
}
|
|
|
|
module.exports = router;
|
|
module.exports.authMiddleware = authMiddleware;
|