From ce32a1f6a6520c377f6bdc27863b561c4b0a5251 Mon Sep 17 00:00:00 2001 From: gitea_admin Date: Fri, 6 Feb 2026 16:58:52 +0000 Subject: [PATCH] Upload files to "src" --- src/init.sql | 17 +++++++ src/server.js | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 src/init.sql create mode 100644 src/server.js diff --git a/src/init.sql b/src/init.sql new file mode 100644 index 0000000..fd7b261 --- /dev/null +++ b/src/init.sql @@ -0,0 +1,17 @@ +-- Database initialization script for inventory management +-- Simple schema with only 4 fields (focus on DevOps, not data modeling) + +CREATE TABLE IF NOT EXISTS items ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + quantity INT NOT NULL DEFAULT 0, + price DECIMAL(10, 2) NOT NULL, + INDEX idx_name (name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Insert sample data +INSERT INTO items (name, quantity, price) VALUES +('Laptop', 10, 999.99), +('Mouse', 50, 29.99), +('Keyboard', 30, 79.99) +ON DUPLICATE KEY UPDATE quantity=quantity; diff --git a/src/server.js b/src/server.js new file mode 100644 index 0000000..59e2cbc --- /dev/null +++ b/src/server.js @@ -0,0 +1,121 @@ +// Minimal Express server for inventory management +// All routes inline (no separate controllers) - focus on DevOps, not architecture +require('dotenv').config(); +const express = require('express'); +const cors = require('cors'); +const helmet = require('helmet'); +const { body, validationResult } = require('express-validator'); +const { pool, initDatabase, testConnection } = require('./db'); + +const app = express(); +const PORT = process.env.PORT || 3000; + +// Middleware +app.use(helmet()); +app.use(cors()); +app.use(express.json()); + +// Request logging middleware +app.use((req, res, next) => { + console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`); + next(); +}); + +// Health check endpoint (liveness probe) +app.get('/health', (req, res) => { + res.status(200).json({ status: 'ok' }); +}); + +// Readiness check endpoint (checks DB connection) +app.get('/ready', async (req, res) => { + const isConnected = await testConnection(); + if (isConnected) { + res.status(200).json({ status: 'ready', database: 'connected' }); + } else { + res.status(503).json({ status: 'not ready', database: 'disconnected' }); + } +}); + +// GET /api/items - List all items (no pagination for simplicity) +app.get('/api/items', async (req, res) => { + try { + const [rows] = await pool.query('SELECT * FROM items ORDER BY id DESC'); + res.json(rows); + } catch (error) { + console.error('Error fetching items:', error); + res.status(500).json({ error: 'Failed to fetch items' }); + } +}); + +// POST /api/items - Create new item +app.post('/api/items', + [ + body('name').trim().notEmpty().withMessage('Name is required'), + body('quantity').isInt({ min: 0 }).withMessage('Quantity must be a non-negative integer'), + body('price').isFloat({ min: 0 }).withMessage('Price must be a non-negative number') + ], + async (req, res) => { + // Validate input + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + + const { name, quantity, price } = req.body; + + try { + const [result] = await pool.query( + 'INSERT INTO items (name, quantity, price) VALUES (?, ?, ?)', + [name, quantity, price] + ); + + res.status(201).json({ + id: result.insertId, + name, + quantity, + price, + message: 'Item created successfully' + }); + } catch (error) { + console.error('Error creating item:', error); + res.status(500).json({ error: 'Failed to create item' }); + } + } +); + +// Error handling middleware +app.use((err, req, res, next) => { + console.error('Unhandled error:', err); + res.status(500).json({ error: 'Internal server error' }); +}); + +// 404 handler +app.use((req, res) => { + res.status(404).json({ error: 'Route not found' }); +}); + +// Start server +async function startServer() { + try { + // Initialize database schema + await initDatabase(); + + // Start listening + app.listen(PORT, () => { + console.log(`Backend service running on port ${PORT}`); + console.log(`Health check: http://localhost:${PORT}/health`); + console.log(`Ready check: http://localhost:${PORT}/ready`); + console.log(`API endpoint: http://localhost:${PORT}/api/items`); + }); + } catch (error) { + console.error('Failed to start server:', error); + process.exit(1); + } +} + +// Only start server if not in test mode +if (require.main === module) { + startServer(); +} + +module.exports = app;