Initial commit — Electron + React frontend, Express/Docker backend, members & project management
This commit is contained in:
2
backend/.dockerignore
Normal file
2
backend/.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
12
backend/Dockerfile
Normal file
12
backend/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install --omit=dev
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 4000
|
||||
|
||||
CMD ["node", "index.js"]
|
||||
106
backend/index.js
Normal file
106
backend/index.js
Normal file
@@ -0,0 +1,106 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import { Low } from 'lowdb';
|
||||
import { JSONFile } from 'lowdb/node';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const dataDir = join(__dirname, 'data');
|
||||
import { mkdirSync } from 'fs';
|
||||
mkdirSync(dataDir, { recursive: true });
|
||||
const dbFile = join(dataDir, 'db.json');
|
||||
const adapter = new JSONFile(dbFile);
|
||||
const defaultData = { members: [], projects: [], tasks: [] };
|
||||
const db = new Low(adapter, defaultData);
|
||||
|
||||
await db.read();
|
||||
await db.write();
|
||||
|
||||
const app = express();
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Member CRUD
|
||||
app.get('/api/members', (req, res) => {
|
||||
res.json(db.data.members);
|
||||
});
|
||||
|
||||
app.post('/api/members', (req, res) => {
|
||||
const member = { id: Date.now().toString(), ...req.body };
|
||||
db.data.members.push(member);
|
||||
db.write();
|
||||
res.status(201).json(member);
|
||||
});
|
||||
|
||||
app.delete('/api/members/:id', (req, res) => {
|
||||
db.data.members = db.data.members.filter(m => m.id !== req.params.id);
|
||||
db.write();
|
||||
res.status(204).end();
|
||||
});
|
||||
|
||||
app.put('/api/members/:id', async (req, res) => {
|
||||
const idx = db.data.members.findIndex(m => m.id === req.params.id);
|
||||
if (idx === -1) return res.status(404).json({ error: 'Member not found' });
|
||||
db.data.members[idx] = { ...db.data.members[idx], ...req.body, id: req.params.id };
|
||||
await db.write();
|
||||
res.json(db.data.members[idx]);
|
||||
});
|
||||
|
||||
// Project CRUD
|
||||
app.get('/api/projects', (req, res) => {
|
||||
res.json(db.data.projects);
|
||||
});
|
||||
|
||||
app.post('/api/projects', (req, res) => {
|
||||
const project = { id: Date.now().toString(), members: [], ...req.body };
|
||||
db.data.projects.push(project);
|
||||
db.write();
|
||||
res.status(201).json(project);
|
||||
});
|
||||
|
||||
app.put('/api/projects/:id', async (req, res) => {
|
||||
const idx = db.data.projects.findIndex(p => p.id === req.params.id);
|
||||
const updated = { ...req.body, id: req.params.id };
|
||||
if (idx === -1) db.data.projects.push(updated);
|
||||
else db.data.projects[idx] = updated;
|
||||
await db.write();
|
||||
res.json(updated);
|
||||
});
|
||||
|
||||
app.delete('/api/projects/:id', (req, res) => {
|
||||
db.data.projects = db.data.projects.filter(p => p.id !== req.params.id);
|
||||
db.write();
|
||||
res.status(204).end();
|
||||
});
|
||||
|
||||
// Assign member to project
|
||||
app.post('/api/projects/:projectId/members/:memberId', (req, res) => {
|
||||
const project = db.data.projects.find(p => p.id === req.params.projectId);
|
||||
if (!project) return res.status(404).json({ error: 'Project not found' });
|
||||
if (!project.members.includes(req.params.memberId)) {
|
||||
project.members.push(req.params.memberId);
|
||||
db.write();
|
||||
}
|
||||
res.json(project);
|
||||
});
|
||||
|
||||
// Tasks (assign to member in project)
|
||||
app.post('/api/projects/:projectId/tasks', (req, res) => {
|
||||
const { title, description, memberId } = req.body;
|
||||
const project = db.data.projects.find(p => p.id === req.params.projectId);
|
||||
if (!project) return res.status(404).json({ error: 'Project not found' });
|
||||
if (!project.members.includes(memberId)) return res.status(400).json({ error: 'Member not assigned to project' });
|
||||
const task = { id: Date.now().toString(), projectId: project.id, memberId, title, description, status: 'todo' };
|
||||
db.data.tasks.push(task);
|
||||
db.write();
|
||||
res.status(201).json(task);
|
||||
});
|
||||
|
||||
app.get('/api/projects/:projectId/tasks', (req, res) => {
|
||||
const tasks = db.data.tasks.filter(t => t.projectId === req.params.projectId);
|
||||
res.json(tasks);
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 4000;
|
||||
app.listen(PORT, () => console.log(`Backend running on port ${PORT}`));
|
||||
1259
backend/package-lock.json
generated
Normal file
1259
backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
backend/package.json
Normal file
18
backend/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "project-manager-backend",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"dev": "nodemon index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"lowdb": "^6.0.1",
|
||||
"cors": "^2.8.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.0.1"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user