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
109 lines
3.3 KiB
JavaScript
109 lines
3.3 KiB
JavaScript
// Production server for DSS Team Portal
|
|
import { createServer } from 'http';
|
|
import { readFile, stat } from 'fs/promises';
|
|
import { join, extname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
const DIST_DIR = join(__dirname, 'dist');
|
|
const PORT = process.env.PORT || 3457;
|
|
const API_PROXY = process.env.API_PROXY || 'http://localhost:3456';
|
|
|
|
const MIME_TYPES = {
|
|
'.html': 'text/html',
|
|
'.css': 'text/css',
|
|
'.js': 'application/javascript',
|
|
'.json': 'application/json',
|
|
'.svg': 'image/svg+xml',
|
|
'.png': 'image/png',
|
|
'.jpg': 'image/jpeg',
|
|
'.ico': 'image/x-icon',
|
|
'.woff': 'font/woff',
|
|
'.woff2': 'font/woff2'
|
|
};
|
|
|
|
async function serveFile(res, filePath) {
|
|
try {
|
|
const content = await readFile(filePath);
|
|
const ext = extname(filePath);
|
|
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
|
|
|
|
res.writeHead(200, {
|
|
'Content-Type': contentType,
|
|
'Cache-Control': ext === '.html' ? 'no-cache' : 'public, max-age=31536000'
|
|
});
|
|
res.end(content);
|
|
} catch (err) {
|
|
// File not found, serve index.html for SPA routing
|
|
const indexPath = join(DIST_DIR, 'index.html');
|
|
const content = await readFile(indexPath);
|
|
res.writeHead(200, { 'Content-Type': 'text/html', 'Cache-Control': 'no-cache' });
|
|
res.end(content);
|
|
}
|
|
}
|
|
|
|
async function proxyRequest(req, res) {
|
|
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
const proxyUrl = `${API_PROXY}${url.pathname}${url.search}`;
|
|
|
|
try {
|
|
const proxyRes = await fetch(proxyUrl, {
|
|
method: req.method,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...Object.fromEntries(
|
|
Object.entries(req.headers).filter(([k]) => !['host', 'connection'].includes(k))
|
|
)
|
|
},
|
|
body: ['POST', 'PUT', 'PATCH'].includes(req.method)
|
|
? await getRequestBody(req)
|
|
: undefined
|
|
});
|
|
|
|
const data = await proxyRes.text();
|
|
res.writeHead(proxyRes.status, { 'Content-Type': 'application/json' });
|
|
res.end(data);
|
|
} catch (err) {
|
|
console.error('[Proxy Error]', err.message);
|
|
res.writeHead(502, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify({ error: 'Proxy error', message: err.message }));
|
|
}
|
|
}
|
|
|
|
function getRequestBody(req) {
|
|
return new Promise((resolve, reject) => {
|
|
let body = '';
|
|
req.on('data', chunk => body += chunk);
|
|
req.on('end', () => resolve(body));
|
|
req.on('error', reject);
|
|
});
|
|
}
|
|
|
|
const server = createServer(async (req, res) => {
|
|
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
|
|
// Health check
|
|
if (url.pathname === '/health') {
|
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify({ status: 'ok', service: 'dss-team-portal' }));
|
|
return;
|
|
}
|
|
|
|
// Proxy API requests to DSS MCP server
|
|
if (url.pathname.startsWith('/api/')) {
|
|
url.pathname = url.pathname.replace('/api', '');
|
|
req.url = url.pathname + url.search;
|
|
await proxyRequest(req, res);
|
|
return;
|
|
}
|
|
|
|
// Serve static files
|
|
const filePath = join(DIST_DIR, url.pathname === '/' ? 'index.html' : url.pathname);
|
|
await serveFile(res, filePath);
|
|
});
|
|
|
|
server.listen(PORT, () => {
|
|
console.log(`[DSS Team Portal] Running on http://localhost:${PORT}`);
|
|
console.log(`[DSS Team Portal] API Proxy: ${API_PROXY}`);
|
|
});
|