Files
dss/server/src/routes/projects.js
Digital Production Factory 276ed71f31 Initial commit: Clean DSS implementation
Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm

Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)

Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability

Migration completed: $(date)
🤖 Clean migration with full functionality preserved
2025-12-09 18:45:48 -03:00

246 lines
5.8 KiB
JavaScript

import express from 'express';
import { authenticateToken } from '../middleware/auth.js';
import Project from '../models/Project.js';
import User from '../models/User.js';
const router = express.Router();
// Get all projects for user
router.get('/', authenticateToken, async (req, res, next) => {
try {
const projects = await Project.findAll({
where: { userId: req.user.id },
attributes: { exclude: ['settings'] }
});
res.status(200).json({
status: 'success',
code: 'PROJECTS_RETRIEVED',
message: 'Projects retrieved successfully',
data: { projects }
});
} catch (error) {
next(error);
}
});
// Get single project
router.get('/:id', authenticateToken, async (req, res, next) => {
try {
const project = await Project.findOne({
where: { id: req.params.id, userId: req.user.id }
});
if (!project) {
return res.status(404).json({
status: 'error',
code: 'PROJECT_NOT_FOUND',
message: 'Project not found',
data: null
});
}
res.status(200).json({
status: 'success',
code: 'PROJECT_RETRIEVED',
message: 'Project retrieved successfully',
data: { project }
});
} catch (error) {
next(error);
}
});
// Create project
router.post('/', authenticateToken, async (req, res, next) => {
try {
const { name, description, key, figmaFileKey, jiraProjectKey, storybookUrl } = req.body;
if (!name || !key) {
return res.status(400).json({
status: 'error',
code: 'VALIDATION_ERROR',
message: 'Name and key are required',
data: null
});
}
const project = await Project.create({
name,
description,
key,
userId: req.user.id,
figmaFileKey,
jiraProjectKey,
storybookUrl
});
res.status(201).json({
status: 'success',
code: 'PROJECT_CREATED',
message: 'Project created successfully',
data: { project }
});
} catch (error) {
if (error.name === 'SequelizeUniqueConstraintError') {
return res.status(409).json({
status: 'error',
code: 'DUPLICATE_KEY',
message: 'Project key already exists',
data: null
});
}
next(error);
}
});
// Update project
router.put('/:id', authenticateToken, async (req, res, next) => {
try {
const project = await Project.findOne({
where: { id: req.params.id, userId: req.user.id }
});
if (!project) {
return res.status(404).json({
status: 'error',
code: 'PROJECT_NOT_FOUND',
message: 'Project not found',
data: null
});
}
const { name, description, figmaFileKey, jiraProjectKey, storybookUrl, status, settings } = req.body;
await project.update({
name: name || project.name,
description: description !== undefined ? description : project.description,
figmaFileKey: figmaFileKey !== undefined ? figmaFileKey : project.figmaFileKey,
jiraProjectKey: jiraProjectKey !== undefined ? jiraProjectKey : project.jiraProjectKey,
storybookUrl: storybookUrl !== undefined ? storybookUrl : project.storybookUrl,
status: status || project.status,
settings: settings || project.settings
});
res.status(200).json({
status: 'success',
code: 'PROJECT_UPDATED',
message: 'Project updated successfully',
data: { project }
});
} catch (error) {
next(error);
}
});
// Delete project
router.delete('/:id', authenticateToken, async (req, res, next) => {
try {
const project = await Project.findOne({
where: { id: req.params.id, userId: req.user.id }
});
if (!project) {
return res.status(404).json({
status: 'error',
code: 'PROJECT_NOT_FOUND',
message: 'Project not found',
data: null
});
}
await project.destroy();
res.status(200).json({
status: 'success',
code: 'PROJECT_DELETED',
message: 'Project deleted successfully',
data: null
});
} catch (error) {
next(error);
}
});
// Save ESRE (style requirements) for project
router.post('/:id/esre', authenticateToken, async (req, res, next) => {
try {
const project = await Project.findOne({
where: { id: req.params.id, userId: req.user.id }
});
if (!project) {
return res.status(404).json({
status: 'error',
code: 'PROJECT_NOT_FOUND',
message: 'Project not found',
data: null
});
}
const { content } = req.body;
if (!content) {
return res.status(400).json({
status: 'error',
code: 'VALIDATION_ERROR',
message: 'ESRE content is required',
data: null
});
}
// Update project settings with ESRE content
await project.update({
settings: {
...project.settings,
esre: content
}
});
res.status(200).json({
status: 'success',
code: 'ESRE_SAVED',
message: 'ESRE saved successfully',
data: {
success: true,
savedAt: new Date().toISOString()
}
});
} catch (error) {
next(error);
}
});
// Get ESRE (style requirements) for project
router.get('/:id/esre', authenticateToken, async (req, res, next) => {
try {
const project = await Project.findOne({
where: { id: req.params.id, userId: req.user.id }
});
if (!project) {
return res.status(404).json({
status: 'error',
code: 'PROJECT_NOT_FOUND',
message: 'Project not found',
data: null
});
}
const esreContent = project.settings?.esre || '';
res.status(200).json({
status: 'success',
code: 'ESRE_RETRIEVED',
message: 'ESRE retrieved successfully',
data: {
content: esreContent
}
});
} catch (error) {
next(error);
}
});
export default router;