This commit introduces a complete transparency infrastructure including: Core Transparency Modules: - AuditLog: Immutable, cryptographically-linked audit trail for all actions - EventStream: Real-time SSE streaming and webhook support - TransparencyDashboard: Aggregated metrics and system health monitoring - DigitalSignatures: Cryptographic verification for handoffs and certificates API Endpoints: - /api/transparency/dashboard - Full platform metrics - /api/transparency/audit - Query and log audit entries - /api/transparency/events - SSE stream and event history - /api/transparency/webhooks - Webhook management - /api/transparency/signatures - Digital signature operations - /api/transparency/certificate/[plantId] - Plant authenticity certificates - /api/transparency/export - Multi-format data export - /api/transparency/report - Compliance reporting - /api/transparency/health - System health checks Features: - Immutable audit logging with chain integrity verification - Real-time event streaming via Server-Sent Events - Webhook support with HMAC signature verification - Digital signatures for transport handoffs and ownership transfers - Certificate of Authenticity generation for plants - Multi-format data export (JSON, CSV, summary) - Public transparency portal at /transparency - System health monitoring for all components Documentation: - Comprehensive TRANSPARENCY.md guide with API examples
140 lines
3.9 KiB
TypeScript
140 lines
3.9 KiB
TypeScript
/**
|
|
* Transparency Report API
|
|
* GET /api/transparency/report - Generate transparency report
|
|
*
|
|
* Generates comprehensive reports for stakeholders and compliance.
|
|
*/
|
|
|
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
import { getTransparencyDashboard, getAuditLog } from '../../../lib/transparency';
|
|
|
|
export default async function handler(
|
|
req: NextApiRequest,
|
|
res: NextApiResponse
|
|
) {
|
|
if (req.method !== 'GET') {
|
|
return res.status(405).json({ error: 'Method not allowed' });
|
|
}
|
|
|
|
try {
|
|
const {
|
|
startDate,
|
|
endDate,
|
|
format = 'json',
|
|
type = 'full'
|
|
} = req.query;
|
|
|
|
const now = new Date();
|
|
const defaultEndDate = now.toISOString();
|
|
const defaultStartDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
|
|
|
const start = (startDate as string) || defaultStartDate;
|
|
const end = (endDate as string) || defaultEndDate;
|
|
|
|
const dashboard = getTransparencyDashboard();
|
|
const auditLog = getAuditLog();
|
|
|
|
if (type === 'audit') {
|
|
// Audit-specific report
|
|
const auditReport = auditLog.generateReport(start, end);
|
|
|
|
if (format === 'summary') {
|
|
res.setHeader('Content-Type', 'text/plain');
|
|
return res.status(200).send(`
|
|
LOCALGREENCHAIN AUDIT REPORT
|
|
============================
|
|
Period: ${start} to ${end}
|
|
Generated: ${auditReport.generatedAt}
|
|
|
|
COMPLIANCE STATUS
|
|
-----------------
|
|
Data Integrity: ${auditReport.complianceStatus.dataIntegrity ? 'PASS' : 'FAIL'}
|
|
Chain Valid: ${auditReport.complianceStatus.chainValid ? 'PASS' : 'FAIL'}
|
|
No Tampering: ${auditReport.complianceStatus.noTampering ? 'PASS' : 'FAIL'}
|
|
|
|
STATISTICS
|
|
----------
|
|
Total Entries: ${auditReport.stats.totalEntries}
|
|
Last 24h: ${auditReport.stats.entriesLast24h}
|
|
Last 7d: ${auditReport.stats.entriesLast7d}
|
|
Last 30d: ${auditReport.stats.entriesLast30d}
|
|
Error Rate (24h): ${(auditReport.stats.errorRate24h * 100).toFixed(2)}%
|
|
|
|
HIGHLIGHTS
|
|
----------
|
|
${auditReport.highlights.map(h => `- ${h}`).join('\n')}
|
|
|
|
ANOMALIES (${auditReport.anomalies.length})
|
|
-------------------------------------------
|
|
${auditReport.anomalies.slice(0, 10).map(a =>
|
|
`[${a.severity}] ${a.timestamp}: ${a.description}`
|
|
).join('\n')}
|
|
`.trim());
|
|
}
|
|
|
|
return res.status(200).json({
|
|
success: true,
|
|
data: auditReport
|
|
});
|
|
}
|
|
|
|
// Full transparency report
|
|
const report = await dashboard.generateReport(start, end);
|
|
|
|
if (format === 'summary') {
|
|
res.setHeader('Content-Type', 'text/plain');
|
|
let content = `
|
|
${report.title}
|
|
${'='.repeat(report.title.length)}
|
|
Period: ${report.period.start} to ${report.period.end}
|
|
Generated: ${report.generatedAt}
|
|
|
|
EXECUTIVE SUMMARY
|
|
-----------------
|
|
Total Plants Registered: ${report.summary.totalPlants}
|
|
Total Transport Events: ${report.summary.totalTransportEvents}
|
|
Carbon Saved: ${report.summary.carbonSavedKg} kg
|
|
System Health: ${report.summary.systemHealth}
|
|
Compliance Status: ${report.summary.complianceStatus}
|
|
|
|
`;
|
|
|
|
for (const section of report.sections) {
|
|
content += `
|
|
${section.title}
|
|
${'-'.repeat(section.title.length)}
|
|
${section.content}
|
|
|
|
Metrics:
|
|
${section.metrics.map(m => ` ${m.label}: ${m.value}`).join('\n')}
|
|
`;
|
|
}
|
|
|
|
return res.status(200).send(content.trim());
|
|
}
|
|
|
|
// JSON format with optional filtering
|
|
if (format === 'csv') {
|
|
const rows = [
|
|
['Section', 'Metric', 'Value'],
|
|
...report.sections.flatMap(s =>
|
|
s.metrics.map(m => [s.title, m.label, String(m.value)])
|
|
)
|
|
];
|
|
res.setHeader('Content-Type', 'text/csv');
|
|
res.setHeader('Content-Disposition', `attachment; filename=transparency-report-${start.split('T')[0]}.csv`);
|
|
return res.status(200).send(rows.map(r => r.join(',')).join('\n'));
|
|
}
|
|
|
|
return res.status(200).json({
|
|
success: true,
|
|
data: report
|
|
});
|
|
} catch (error) {
|
|
console.error('[API] Report generation error:', error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to generate report'
|
|
});
|
|
}
|
|
}
|