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:
108
team-portal/server.js
Normal file
108
team-portal/server.js
Normal file
@@ -0,0 +1,108 @@
|
||||
// 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}`);
|
||||
});
|
||||
Reference in New Issue
Block a user