Initial commit: Yakıt Takip Modülü - Akaryakıt İstasyonu Yönetim Sistemi
🚀 Features Implemented: - Full-stack SvelteKit application with Express backend - Role-based authentication (Admin, Fuel Manager, Goods Manager) - Real-time notifications with Socket.IO - SQLite database with auto-initialization in /db directory - Comprehensive user management and fuel slip tracking - Responsive design with Turkish language support 🏗️ Architecture: - Frontend: Svelte + SvelteKit + Vite - Backend: Node.js + Express + Socket.IO - Database: SQLite3 with automatic schema creation - Security: bcrypt password hashing + session management - Real-time: Socket.IO for instant notifications 📁 Project Structure: - Organized documentation in /docs directory - Database files in /db directory with auto-setup - Clean separation of API routes and UI components - Comprehensive documentation including processes, architecture, and user guides 📚 Documentation: - PROJECT_PROCESSES.md: Comprehensive project documentation - KNOWLEDGE_BASE.md: Quick reference and user guide - TEST_GUIDE.md: Testing and quality assurance guide - README_ADMIN_FEATURES.md: Admin functionality guide - Full API documentation and system architecture 🔒 Security Features: - Role-based authorization system - Encrypted password storage with bcrypt - Session-based authentication - SQL injection protection with parameterized queries - CORS configuration and input validation 🎯 Key Features: - Fuel slip creation and approval workflow - Real-time notifications between users - PDF generation for fuel slips - User and vehicle management - Comprehensive audit logging 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
231
src/server.js
Normal file
231
src/server.js
Normal file
@@ -0,0 +1,231 @@
|
||||
import express from 'express';
|
||||
import session from 'express-session';
|
||||
import { createServer } from 'http';
|
||||
import { Server } from 'socket.io';
|
||||
import sqlite3 from 'sqlite3';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { promises as fs } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
|
||||
const app = express();
|
||||
const server = createServer(app);
|
||||
const io = new Server(server, {
|
||||
cors: {
|
||||
origin: "http://localhost:5173",
|
||||
methods: ["GET", "POST"]
|
||||
}
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
// ES Module equivalent of __dirname
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Database path setup - ensure /db directory exists and use it
|
||||
const projectRoot = dirname(__dirname); // Go up from src/ to project root
|
||||
const dbDir = join(projectRoot, 'db');
|
||||
const dbPath = join(dbDir, 'yakit_takip.db');
|
||||
|
||||
// Middleware
|
||||
app.use(express.json());
|
||||
app.use(express.static('build'));
|
||||
|
||||
// Session middleware
|
||||
app.use(session({
|
||||
secret: 'yakit-takip-modulu-secret-key-2023',
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: {
|
||||
secure: false, // development için false
|
||||
maxAge: 24 * 60 * 60 * 1000 // 24 saat
|
||||
}
|
||||
}));
|
||||
|
||||
// Ensure /db directory exists
|
||||
async function ensureDbDirectory() {
|
||||
try {
|
||||
await fs.mkdir(dbDir, { recursive: true });
|
||||
console.log(`📁 Database directory ensured: ${dbDir}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Error creating database directory:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Veritabanı bağlantısı
|
||||
const db = new sqlite3.Database(dbPath);
|
||||
|
||||
// Veritabanı tablolarını oluştur
|
||||
async function initializeDatabase() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.serialize(() => {
|
||||
// Kullanıcılar tablosu
|
||||
db.run(`CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
role TEXT NOT NULL,
|
||||
full_name TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
is_active BOOLEAN DEFAULT 1
|
||||
)`, (err) => {
|
||||
if (err) reject(err);
|
||||
});
|
||||
|
||||
// Örnek kullanıcıları ekle
|
||||
const users = [
|
||||
{ username: 'admin', password: 'admin123', role: 'admin', full_name: 'Sistem Yöneticisi' },
|
||||
{ username: 'fuel', password: 'fuel123', role: 'fuel_manager', full_name: 'Yakıt Sorumlusu' },
|
||||
{ username: 'goods', password: 'goods123', role: 'goods_manager', full_name: 'Mal Sorumlusu' }
|
||||
];
|
||||
|
||||
// Her kullanıcıyı kontrol et ve yoksa ekle
|
||||
users.forEach(async (user) => {
|
||||
const hashedPassword = await bcrypt.hash(user.password, 10);
|
||||
|
||||
db.get('SELECT id FROM users WHERE username = ?', [user.username], (err, row) => {
|
||||
if (!row) {
|
||||
db.run('INSERT INTO users (username, password, role, full_name) VALUES (?, ?, ?, ?)',
|
||||
[user.username, hashedPassword, user.role, user.full_name]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// API Routes
|
||||
|
||||
// Login endpoint
|
||||
app.post('/api/login', async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ message: 'Kullanıcı adı ve şifre gerekli.' });
|
||||
}
|
||||
|
||||
try {
|
||||
db.get('SELECT * FROM users WHERE username = ? AND is_active = 1', [username], async (err, user) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: 'Veritabanı hatası.' });
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return res.status(401).json({ message: 'Kullanıcı bulunamadı.' });
|
||||
}
|
||||
|
||||
const passwordMatch = await bcrypt.compare(password, user.password);
|
||||
if (!passwordMatch) {
|
||||
return res.status(401).json({ message: 'Şifre hatalı.' });
|
||||
}
|
||||
|
||||
// Session oluştur
|
||||
req.session.user = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
full_name: user.full_name
|
||||
};
|
||||
|
||||
res.json({
|
||||
message: 'Giriş başarılı.',
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
full_name: user.full_name
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'Sunucu hatası.' });
|
||||
}
|
||||
});
|
||||
|
||||
// Logout endpoint
|
||||
app.post('/api/logout', (req, res) => {
|
||||
req.session.destroy((err) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: 'Çıkış yapılamadı.' });
|
||||
}
|
||||
res.json({ message: 'Çıkış başarılı.' });
|
||||
});
|
||||
});
|
||||
|
||||
// Mevcut kullanıcı bilgisi
|
||||
app.get('/api/user', (req, res) => {
|
||||
if (!req.session.user) {
|
||||
return res.status(401).json({ message: 'Oturum bulunamadı.' });
|
||||
}
|
||||
|
||||
res.json({ user: req.session.user });
|
||||
});
|
||||
|
||||
// Socket.IO bildirim endpoint'i
|
||||
app.post('/api/socket-notify', (req, res) => {
|
||||
const { event, data } = req.body;
|
||||
|
||||
if (!event || !data) {
|
||||
return res.status(400).json({ message: 'Event ve data zorunludur.' });
|
||||
}
|
||||
|
||||
// Socket.IO ile olay yayınla
|
||||
io.emit(event, data);
|
||||
|
||||
res.json({ message: 'Bildirim gönderildi.' });
|
||||
});
|
||||
|
||||
// Tüm kullanıcıları getir (sadece admin)
|
||||
app.get('/api/users', (req, res) => {
|
||||
if (!req.session.user || req.session.user.role !== 'admin') {
|
||||
return res.status(403).json({ message: 'Yetkisiz erişim.' });
|
||||
}
|
||||
|
||||
db.all('SELECT id, username, role, full_name, created_at, is_active FROM users', (err, users) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: 'Veritabanı hatası.' });
|
||||
}
|
||||
res.json({ users });
|
||||
});
|
||||
});
|
||||
|
||||
// Socket.IO bağlantıları
|
||||
io.on('connection', (socket) => {
|
||||
console.log('Bir kullanıcı bağlandı:', socket.id);
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log('Bir kullanıcı ayrıldı:', socket.id);
|
||||
});
|
||||
});
|
||||
|
||||
// SvelteKit için tüm route'ları handle et
|
||||
app.use('*', (req, res) => {
|
||||
res.sendFile('build/index.html', { root: '.' });
|
||||
});
|
||||
|
||||
// Sunucuyu başlat
|
||||
async function startServer() {
|
||||
try {
|
||||
// Ensure database directory exists first
|
||||
await ensureDbDirectory();
|
||||
console.log(`📄 Database file path: ${dbPath}`);
|
||||
|
||||
// Initialize database and tables
|
||||
await initializeDatabase();
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`🚀 Sunucu http://localhost:${PORT} adresinde çalışıyor`);
|
||||
console.log(`📱 Socket.IO sunucusu aktif`);
|
||||
console.log(`💾 Veritabanı: ${dbPath}`);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('❌ Sunucu başlatılamadı:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
startServer();
|
||||
Reference in New Issue
Block a user