import express from 'express'; import Database from 'better-sqlite3'; import { v4 as uuidv4 } from 'uuid'; import puppeteer from 'puppeteer'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const app = express(); const PORT = process.env.PORT || 3000; const API_KEY = process.env.API_KEY || 'crystal-secret-key'; // Initialize database const dbPath = process.env.DB_PATH || '/data/crystal.db'; const db = new Database(dbPath); // Create tables db.exec(` CREATE TABLE IF NOT EXISTS reports ( id TEXT PRIMARY KEY, title TEXT NOT NULL, report_type TEXT NOT NULL, html_content TEXT NOT NULL, summary TEXT, created_at TEXT DEFAULT (datetime('now')), period_start TEXT, period_end TEXT ) `); app.use(express.json({ limit: '10mb' })); app.use(express.static(path.join(__dirname, '../public'))); // Helper: Wrap content in layout function renderPage(title, content, extra = '') { return ` ${title} - Phil Dashboard ${extra}

📋 Phil Dashboard

${content}
`; } // Dashboard - List all reports app.get('/', (req, res) => { const reports = db.prepare(` SELECT id, title, report_type, summary, created_at, period_start, period_end FROM reports ORDER BY created_at DESC `).all(); const reportsList = reports.length === 0 ? '

No reports yet. Ask Phil to generate one!

' : reports.map(r => `
${r.report_type} ${new Date(r.created_at).toLocaleDateString()}

${r.title}

${r.summary ? `

${r.summary}

` : ''} ${r.period_start ? `

${r.period_start} to ${r.period_end || 'Present'}

` : ''}
View PDF
`).join(''); const content = `

Regulatory Reports

${reportsList}
`; res.send(renderPage('Dashboard', content)); }); // View single report app.get('/reports/:id', (req, res) => { const report = db.prepare('SELECT * FROM reports WHERE id = ?').get(req.params.id); if (!report) return res.status(404).send(renderPage('Not Found', '

Report not found

')); const content = `
${report.report_type} Generated: ${new Date(report.created_at).toLocaleString()} ${report.period_start ? `Period: ${report.period_start} to ${report.period_end || 'Present'}` : ''}
← Back Download PDF
${report.html_content}
`; res.send(renderPage(report.title, content)); }); // Generate PDF app.get('/reports/:id/pdf', async (req, res) => { const report = db.prepare('SELECT * FROM reports WHERE id = ?').get(req.params.id); if (!report) return res.status(404).send('Report not found'); try { const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); const html = ` ${report.title}

${report.title}

Generated: ${new Date(report.created_at).toLocaleString()} ${report.period_start ? ` • Period: ${report.period_start} to ${report.period_end || 'Present'}` : ''}
${report.html_content} `; await page.setContent(html, { waitUntil: 'networkidle0' }); const pdf = await page.pdf({ format: 'A4', printBackground: true, margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' } }); await browser.close(); const filename = `${report.title.replace(/[^a-z0-9]/gi, '-').toLowerCase()}.pdf`; res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); res.send(pdf); } catch (err) { console.error('PDF generation error:', err); res.status(500).send('Failed to generate PDF'); } }); // Delete report app.delete('/reports/:id', (req, res) => { const result = db.prepare('DELETE FROM reports WHERE id = ?').run(req.params.id); if (result.changes === 0) return res.status(404).json({ error: 'Not found' }); res.json({ success: true }); }); // API: Create report (for Phil) app.post('/api/reports', (req, res) => { const authHeader = req.headers.authorization; if (authHeader !== `Bearer ${API_KEY}`) { return res.status(401).json({ error: 'Unauthorized' }); } const { title, report_type, html_content, summary, period_start, period_end } = req.body; if (!title || !report_type || !html_content) { return res.status(400).json({ error: 'Missing required fields: title, report_type, html_content' }); } const id = uuidv4(); db.prepare(` INSERT INTO reports (id, title, report_type, html_content, summary, period_start, period_end) VALUES (?, ?, ?, ?, ?, ?, ?) `).run(id, title, report_type, html_content, summary || null, period_start || null, period_end || null); const url = `${req.protocol}://${req.get('host')}/reports/${id}`; res.json({ success: true, id, url }); }); // API: List reports (for Phil) app.get('/api/reports', (req, res) => { const reports = db.prepare(` SELECT id, title, report_type, summary, created_at, period_start, period_end FROM reports ORDER BY created_at DESC LIMIT 50 `).all(); res.json(reports); }); app.listen(PORT, () => { console.log(`Phil Dashboard running on port ${PORT}`); });