Files
dss/team-portal/server.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

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}`);
});