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
This commit is contained in:
245
server/src/routes/projects.js
Normal file
245
server/src/routes/projects.js
Normal file
@@ -0,0 +1,245 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user