← 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...');
});