Files
project-tracker/backend/server.js

104 lines
3.6 KiB
JavaScript

const express = require('express');
const sqlite3 = require('better-sqlite3');
const cors = require('cors');
const fs = require('fs');
const path = require('path');
const app = express();
const PORT = 3000;
const DB_PATH = '/opt/project-tracker/data/projects.db';
const DATA_DIR = '/opt/project-tracker/data';
// Ensure data directory exists
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR, { recursive: true });
}
// Initialize database
const db = new sqlite3(DB_PATH);
// Create table
db.exec(`
CREATE TABLE IF NOT EXISTS projects (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
priority TEXT NOT NULL,
url TEXT DEFAULT '',
notes TEXT DEFAULT '',
status TEXT DEFAULT 'Backlog',
owner TEXT DEFAULT 'Ada',
tags TEXT DEFAULT '',
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
)
`);
// Middleware
app.use(cors());
app.use(express.json());
// GET all projects
app.get('/api/projects', (req, res) => {
const { status } = req.query;
let stmt = status
? db.prepare('SELECT * FROM projects WHERE status = ? ORDER BY CASE priority WHEN \'High\' THEN 1 WHEN \'Med-High\' THEN 2 WHEN \'Medium\' THEN 3 WHEN \'Low\' THEN 4 ELSE 5 END, created_at DESC')
: db.prepare('SELECT * FROM projects ORDER BY CASE priority WHEN \'High\' THEN 1 WHEN \'Med-High\' THEN 2 WHEN \'Medium\' THEN 3 WHEN \'Low\' THEN 4 ELSE 5 END, created_at DESC');
const rows = status ? stmt.all(status) : stmt.all();
res.json(rows);
});
// GET single project
app.get('/api/projects/:id', (req, res) => {
const stmt = db.prepare('SELECT * FROM projects WHERE id = ?');
const row = stmt.get(req.params.id);
if (row) res.json(row);
else res.status(404).json({ error: 'Not found' });
});
// POST create project
app.post('/api/projects', (req, res) => {
const { name, priority, url, notes, status, owner, tags } = req.body;
if (!name || !priority) {
return res.status(400).json({ error: 'name and priority are required' });
}
const stmt = db.prepare(`
INSERT INTO projects (name, priority, url, notes, status, owner, tags)
VALUES (?, ?, ?, ?, ?, ?, ?)
`);
const result = stmt.run(name, priority, url || '', notes || '', status || 'Backlog', owner || 'Ada', tags || '');
res.json({ id: result.lastInsertRowid, message: 'Created' });
});
// PUT update project
app.put('/api/projects/:id', (req, res) => {
const { name, priority, url, notes, status, owner, tags } = req.body;
const fields = [];
const values = [];
if (name !== undefined) { fields.push('name = ?'); values.push(name); }
if (priority !== undefined) { fields.push('priority = ?'); values.push(priority); }
if (url !== undefined) { fields.push('url = ?'); values.push(url); }
if (notes !== undefined) { fields.push('notes = ?'); values.push(notes); }
if (status !== undefined) { fields.push('status = ?'); values.push(status); }
if (owner !== undefined) { fields.push('owner = ?'); values.push(owner); }
if (tags !== undefined) { fields.push('tags = ?'); values.push(tags); }
fields.push('updated_at = datetime(\'now\')');
values.push(req.params.id);
if (fields.length === 1) {
return res.status(400).json({ error: 'No fields to update' });
}
const stmt = db.prepare(`UPDATE projects SET ${fields.join(', ')} WHERE id = ?`);
stmt.run(...values);
res.json({ message: 'Updated' });
});
// DELETE project
app.delete('/api/projects/:id', (req, res) => {
const stmt = db.prepare('DELETE FROM projects WHERE id = ?');
stmt.run(req.params.id);
res.json({ message: 'Deleted' });
});
app.listen(PORT, '0.0.0.0', () => {
console.log(`Project Tracker API running on port ${PORT}`);
});