← back to Designer Wallcoverings
DW-Agents/dw-agents/agent-executive-cfo/cfo-dashboard-agent.ts.backup-oauth-20251112
378 lines
import cookieParser from "cookie-parser";
/**
* DW-Agents: CFO Executive Dashboard
*
* Financial oversight and analysis:
* - P&L, cash flow, and financial health
* - Budget vs actuals tracking
* - Expense management and cost optimization
* - Financial forecasting and modeling
* - Access to accounting, purchasing, and reporting agents
*
* Port: 7122
* Access: Financial agents and reports
*/
import Anthropic from '@anthropic-ai/sdk';
import express, { Request, Response } from 'express';
import session from 'express-session';
import dotenv from 'dotenv';
import path from 'path';
import { chatMiddleware } from '../shared-chat-integration';
// Load environment variables from parent directory
dotenv.config({ path: path.join(__dirname, '..', '.env') });
const app = express();
// Global Authentication
const PORT = 7122;
// Global Authentication - MUST come before any other middleware
app.use(cookieParser());
// Add inter-agent chat widget (after auth)
app.use(chatMiddleware({
agentId: 'agent-executive-cfo',
agentName: 'Executive Cfo',
port: 7122,
category: 'agent'
}));
const AUTH_USERNAME = 'admin';
const AUTH_PASSWORD = '*exec2025*';
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY || '',
});
// CFO has access to financial agents
const CFO_AGENT_ACCESS = [
{ name: 'Accounting Agent', port: 9882, url: 'http://45.61.58.125:9882/' },
{ name: 'Purchasing Office', port: 9880, url: 'http://45.61.58.125:9880/' },
{ name: 'Shopify Store (Revenue)', port: 7238, url: 'http://45.61.58.125:7238/' },
{ name: 'Trend Research', port: 9883, url: 'http://45.61.58.125:9883/' },
{ name: 'Skills Manager', port: 9894, url: 'http://45.61.58.125:9894/' },
{ name: 'CEO Dashboard', port: 7121, url: 'http://45.61.58.125:7121/' }
];
const CFO_SKILLS = [
{ name: '📈 Spreadsheets', description: 'Financial modeling and analysis' },
{ name: '📄 Documents', description: 'Financial reports and documentation' },
{ name: '✉️ Email', description: 'Financial correspondence' },
{ name: '📋 EOD Reports', description: 'Daily financial summaries' }
];
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
declare module 'express-session' {
interface SessionData {
authenticated: boolean;
chatHistory: Array<{ role: 'user' | 'assistant', content: string }>;
}
}
app.use(session({
secret: 'dw-cfo-dashboard-2025-finance',
resave: false,
saveUninitialized: true,
rolling: true,
cookie: { secure: false, httpOnly: true, maxAge: 7 * 24 * 60 * 60 * 1000 }
}));
const requireAuth = (req: Request, res: Response, next: any) => {
if (req.session.authenticated) return next();
res.redirect('/login');
};
app.get('/login', (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>CFO Dashboard - Login</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'DejaVu Sans, Segoe UI', sans-serif;
background: linear-gradient(135deg, #16a085 0%, #27ae60 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.login-container {
background: white;
padding: 50px;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
max-width: 450px;
width: 100%;
}
.logo { text-align: center; font-size: 3em; margin-bottom: 10px; }
h1 { color: #16a085; text-align: center; margin-bottom: 10px; font-size: 1.8em; }
.subtitle { text-align: center; color: #666; margin-bottom: 30px; font-size: 1.1em; }
input {
width: 100%;
padding: 15px;
margin: 10px 0;
border: 2px solid #e0e0e0;
border-radius: 10px;
font-size: 1em;
}
input:focus { border-color: #16a085; outline: none; }
button {
width: 100%;
background: linear-gradient(135deg, #16a085 0%, #27ae60 100%);
color: white;
border: none;
padding: 15px;
border-radius: 10px;
cursor: pointer;
font-weight: 600;
font-size: 1.1em;
margin-top: 10px;
}
.error { color: #dc3545; text-align: center; margin-bottom: 15px; font-weight: 600; }
</style>
</head>
<body>
<div class="login-container">
<div class="logo">💰</div>
<h1>CFO Dashboard</h1>
<div class="subtitle">Financial Control Center</div>
${req.query.error ? '<div class="error">Invalid credentials</div>' : ''}
<form method="POST">
<input type="text" name="username" placeholder="Username" required autofocus>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Access Dashboard</button>
</form>
</div>
</body>
</html>
`);
});
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username === AUTH_USERNAME && password === AUTH_PASSWORD) {
req.session.authenticated = true;
req.session.chatHistory = [];
res.redirect('/');
} else {
res.redirect('/login?error=1');
}
});
app.get('/logout', (req, res) => {
req.session.destroy(() => res.redirect('/login'));
});
app.get('/', requireAuth, (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>CFO Dashboard - Designer Wallcoverings</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
:root {
--primary: #36454f;
--primary-light: #708090;
--accent: #f39c12;
--success: #27ae60;
--danger: #e74c3c;
--bg: #ffffff;
--card-bg: #f8f9fa;
--text: #36454f;
--text-light: #708090;
}
body {
font-family: 'DejaVu Sans, Segoe UI', sans-serif;
background: var(--bg);
padding: 0;
min-height: 100vh;
font-size: 18px;
line-height: 1.8;
}
.header {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
color: white;
padding: 25px 40px;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 { font-size: 2.2em; display: flex; align-items: center; gap: 15px; }
.header-actions { display: flex; gap: 15px; align-items: center; }
.header-actions a {
color: white;
text-decoration: none;
padding: 10px 20px;
border-radius: 8px;
background: rgba(255,255,255,0.2);
}
.container { max-width: 1800px; margin: 0 auto; padding: 30px; }
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 25px;
margin-bottom: 30px;
}
.kpi-card {
background: var(--card-bg);
padding: 25px;
border-radius: 15px;
box-shadow: 0 5px 20px rgba(0,0,0,0.08);
border-left: 5px solid var(--primary);
}
.kpi-label { color: var(--text-light); font-size: 1.1em; text-transform: uppercase; font-weight: 600; margin-bottom: 10px; }
.kpi-value { font-size: 3em; font-weight: bold; color: var(--text); margin-bottom: 10px; }
.kpi-change { font-size: 0.9em; font-weight: 600; }
.kpi-change.positive { color: var(--success); }
.kpi-change.negative { color: var(--danger); }
.section {
background: var(--card-bg);
padding: 30px;
border-radius: 15px;
box-shadow: 0 5px 20px rgba(0,0,0,0.08);
margin-bottom: 25px;
}
.section h2 {
color: var(--primary);
margin-bottom: 20px;
font-size: 1.8em;
border-bottom: 3px solid var(--primary);
padding-bottom: 10px;
}
.agents-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
.agent-link {
background: var(--bg);
padding: 20px;
border-radius: 12px;
text-decoration: none;
color: var(--text);
border: 2px solid transparent;
transition: all 0.3s;
display: block;
}
.agent-link:hover {
border-color: var(--primary);
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(22, 160, 133, 0.2);
}
.agent-name { font-weight: 700; font-size: 1.3em; margin-bottom: 8px; color: var(--primary); }
.agent-port { color: var(--text-light); font-size: 1em; font-family: monospace; }
</style>
</head>
<body>
<div class="header">
<h1><span>💰</span><span>CFO Dashboard</span></h1>
<div class="header-actions">
<span>Welcome, CFO</span>
<a href="/logout">Logout</a>
</div>
</div>
<div class="container">
<div class="dashboard-grid">
<div class="kpi-card">
<div class="kpi-label">Revenue (MTD)</div>
<div class="kpi-value">$2.4M</div>
<div class="kpi-change positive">↑ 12.5% vs last month</div>
</div>
<div class="kpi-card">
<div class="kpi-label">Gross Profit</div>
<div class="kpi-value">$960K</div>
<div class="kpi-change positive">40% margin</div>
</div>
<div class="kpi-card">
<div class="kpi-label">Operating Expenses</div>
<div class="kpi-value">$480K</div>
<div class="kpi-change positive">↓ 2.1% cost reduction</div>
</div>
<div class="kpi-card">
<div class="kpi-label">Cash Flow</div>
<div class="kpi-value">$1.2M</div>
<div class="kpi-change positive">↑ Healthy position</div>
</div>
<div class="kpi-card">
<div class="kpi-label">A/R Outstanding</div>
<div class="kpi-value">$340K</div>
<div class="kpi-change">28 days average</div>
</div>
<div class="kpi-card">
<div class="kpi-label">Inventory Value</div>
<div class="kpi-value">$890K</div>
<div class="kpi-change">45 days turnover</div>
</div>
</div>
<div class="section">
<h2>💼 Financial Systems Access</h2>
<div class="agents-grid">
${CFO_AGENT_ACCESS.map(agent => `
<a href="${agent.url}" target="_blank" class="agent-link">
<div class="agent-name">${agent.name}</div>
<div class="agent-port">Port ${agent.port}</div>
</a>
`).join('')}
</div>
</div>
<!-- Executive Skills -->
<div class="section">
<h2>🛠️ Financial Skills & Tools</h2>
<div class="agents-grid">
${CFO_SKILLS.map(skill => `
<div class="agent-link" style="cursor: default; background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);">
<div class="agent-name">${skill.name}</div>
<div class="agent-port" style="color: var(--text-light); font-size: 0.95em; margin-top: 8px;">
${skill.description}
</div>
</div>
`).join('')}
</div>
</div>
</div>
</body>
</html>
`);
});
// Metrics endpoint for daily reporting
app.get("/api/metrics", (req: Request, res: Response) => {
res.json({
status: "online",
uptime: process.uptime(),
responseTime: 0,
tasksCompleted: 0,
errorsToday: 0,
lastActivity: new Date().toISOString(),
qnaReadiness: 100
});
});
app.listen(PORT, '0.0.0.0', () => {
console.log('');
console.log('💰 CFO Executive Dashboard');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('🌍 External: http://45.61.58.125:' + PORT);
console.log('🏠 Local: http://localhost:' + PORT);
console.log('');
console.log('🔐 Username: ' + AUTH_USERNAME);
console.log('🔐 Password: ' + AUTH_PASSWORD);
console.log('');
console.log('✅ CFO Dashboard ready...');
});