204 lines
8.2 KiB
HTML
204 lines
8.2 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}Audit Dashboard - {{ APP_VERSION }}{% endblock %}
|
|
{% block content %}
|
|
<style>
|
|
.audit-panel,
|
|
.audit-stat-card,
|
|
.audit-table-panel {
|
|
border: 1px solid var(--ui-border);
|
|
border-radius: 10px;
|
|
background: var(--ui-surface);
|
|
color: var(--ui-text);
|
|
}
|
|
|
|
.audit-panel p,
|
|
.audit-stat-label,
|
|
.audit-table-panel th {
|
|
color: var(--ui-text-muted);
|
|
}
|
|
|
|
.audit-table-panel {
|
|
padding: 12px;
|
|
}
|
|
|
|
.audit-table-scroll {
|
|
max-height: 560px;
|
|
overflow: auto;
|
|
}
|
|
|
|
.audit-table-panel table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
.audit-table-panel th,
|
|
.audit-table-panel td {
|
|
border-bottom: 1px solid var(--ui-border) !important;
|
|
}
|
|
|
|
.audit-table-panel tbody tr:hover td {
|
|
background: var(--ui-bg-accent) !important;
|
|
}
|
|
|
|
.audit-mismatch-panel {
|
|
border-color: #f87171;
|
|
background: #fff7f7;
|
|
}
|
|
|
|
:root[data-theme="dark"] .audit-info-panel {
|
|
background: #082f49 !important;
|
|
border-left-color: #38bdf8 !important;
|
|
}
|
|
|
|
:root[data-theme="dark"] .audit-info-panel p {
|
|
color: #bae6fd !important;
|
|
}
|
|
|
|
:root[data-theme="dark"] .audit-panel,
|
|
:root[data-theme="dark"] .audit-stat-card,
|
|
:root[data-theme="dark"] .audit-table-panel {
|
|
background: var(--ui-surface) !important;
|
|
color: var(--ui-text) !important;
|
|
border-color: var(--ui-border) !important;
|
|
}
|
|
|
|
:root[data-theme="dark"] .audit-mismatch-panel {
|
|
background: #451a1a !important;
|
|
border-color: #f87171 !important;
|
|
}
|
|
|
|
:root[data-theme="dark"] .audit-mismatch-panel h3 {
|
|
color: #fecaca !important;
|
|
}
|
|
|
|
:root[data-theme="dark"] .audit-table-panel th,
|
|
:root[data-theme="dark"] .audit-table-panel td,
|
|
:root[data-theme="dark"] .audit-table-panel pre {
|
|
color: var(--ui-text) !important;
|
|
border-color: var(--ui-border) !important;
|
|
}
|
|
|
|
@media (max-width: 700px) {
|
|
.audit-table-panel {
|
|
padding: 8px;
|
|
}
|
|
|
|
.audit-table-scroll {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.audit-table-panel table {
|
|
min-width: 720px;
|
|
}
|
|
}
|
|
</style>
|
|
<div class="container" style="max-width:1400px; margin:0 auto; padding:18px;">
|
|
<h1>Audit Dashboard</h1>
|
|
<p>Integritätsstatus der Audit-Chain und letzte Audit-Ereignisse (max. 200 Einträge).</p>
|
|
|
|
<!-- Information Box for DIN 5008 Compliance -->
|
|
<div class="audit-panel audit-info-panel" style="background:#e8f4f8; border-left:4px solid #0284c7; padding:12px; margin:0 0 16px 0; border-radius:4px;">
|
|
<p style="margin:0; font-size:0.95rem; color:#1e40af;">
|
|
<strong>✓ Professionelle PDF-Exporte:</strong> Die neuen DIN 5008 konformen Berichte sind speziell für Schulträger,
|
|
Rechnungsprüfungsämter und Behörden optimiert. Sie enthalten Revisionssicherheit, Barrierefreiheit (BFSG) und
|
|
PDF/A-Format für Langzeitarchivierung in deutschen Behörden.
|
|
</p>
|
|
</div>
|
|
|
|
<div style="display:grid; grid-template-columns:1fr 1fr; gap:12px; margin:10px 0 18px;">
|
|
<!-- PDF Export Section -->
|
|
<div class="audit-panel" style="padding:14px; border:1px solid #e2e8f0; border-radius:10px; background: var(--ui-surface);">
|
|
<h4 style="margin:0 0 10px 0; color:#1a1a1a;">📄 PDF-Export (DIN 5008 konform)</h4>
|
|
<p style="margin:0 0 10px 0; font-size:0.9rem; color:#666;">Professionelle Berichte für Schulträger und Behörden</p>
|
|
<div style="display:flex; gap:8px; flex-wrap:wrap;">
|
|
<a class="btn btn-primary" href="{{ url_for('admin_audit_export_pdf_official') }}" style="flex:1; text-align:center;">
|
|
📋 Amtlicher Bericht (DIN 5008)
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div style="display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:12px; margin:16px 0 20px;">
|
|
<div class="audit-stat-card" style="padding:14px; border:1px solid #e2e8f0; border-radius:10px; background: var(--ui-surface);">
|
|
<div style="font-size:0.85rem; color:#64748b;">Chain Status</div>
|
|
{% if verify_result.ok %}
|
|
<div style="font-size:1.35rem; font-weight:700; color:#166534;">OK</div>
|
|
{% else %}
|
|
<div style="font-size:1.35rem; font-weight:700; color:#991b1b;">FEHLER</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="audit-stat-card" style="padding:14px; border:1px solid #e2e8f0; border-radius:10px; background: var(--ui-surface);">
|
|
<div style="font-size:0.85rem; color:#64748b;">Einträge</div>
|
|
<div style="font-size:1.35rem; font-weight:700;">{{ verify_result.count }}</div>
|
|
</div>
|
|
<div class="audit-stat-card" style="padding:14px; border:1px solid #e2e8f0; border-radius:10px; background: var(--ui-surface);">
|
|
<div style="font-size:0.85rem; color:#64748b;">Letzter Index</div>
|
|
<div style="font-size:1.35rem; font-weight:700;">{{ verify_result.last_chain_index }}</div>
|
|
</div>
|
|
<div style="padding:14px; border:1px solid #e2e8f0; border-radius:10px; background: var(--ui-surface);">
|
|
<div style="font-size:0.85rem; color:#64748b;">Mismatch Count</div>
|
|
<div style="font-size:1.35rem; font-weight:700;">{{ verify_result.mismatches|length }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if verify_result.mismatches %}
|
|
<div class="audit-table-panel audit-mismatch-panel" style="margin-bottom:20px; border:1px solid #fecaca; background:#fff7f7; border-radius:10px; padding:12px;">
|
|
<h3 style="margin-top:0; color:#991b1b;">Integritätsabweichungen</h3>
|
|
<div style="max-height:280px; overflow:auto;">
|
|
<table class="table" style="width:100%; border-collapse:collapse;">
|
|
<thead>
|
|
<tr>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Index</th>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Typ</th>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Expected</th>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Found</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for m in verify_result.mismatches %}
|
|
<tr>
|
|
<td style="padding:8px; border-bottom:1px solid #eee;">{{ m.chain_index }}</td>
|
|
<td style="padding:8px; border-bottom:1px solid #eee;">{{ m.error }}</td>
|
|
<td style="padding:8px; border-bottom:1px solid #eee; font-family:monospace;">{{ m.expected }}</td>
|
|
<td style="padding:8px; border-bottom:1px solid #eee; font-family:monospace;">{{ m.found }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="audit-table-panel" style="border:1px solid #e2e8f0; border-radius:10px; background: var(--ui-surface); padding:12px;">
|
|
<h3 style="margin-top:0;">Letzte Audit-Ereignisse</h3>
|
|
<div class="audit-table-scroll" style="max-height:560px; overflow:auto;">
|
|
<table class="table" style="width:100%; border-collapse:collapse;">
|
|
<thead>
|
|
<tr>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Index</th>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Zeit</th>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Event</th>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Actor</th>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Hash</th>
|
|
<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Payload</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for row in audit_rows %}
|
|
<tr>
|
|
<td style="padding:8px; border-bottom:1px solid #eee;">{{ row.chain_index }}</td>
|
|
<td style="padding:8px; border-bottom:1px solid #eee;">{{ row.timestamp or row.created_at }}</td>
|
|
<td style="padding:8px; border-bottom:1px solid #eee;">{{ row.event_type }}</td>
|
|
<td style="padding:8px; border-bottom:1px solid #eee;">{{ row.actor }}</td>
|
|
<td style="padding:8px; border-bottom:1px solid #eee; font-family:monospace; font-size:0.8rem;">{{ row.entry_hash }}</td>
|
|
<td style="padding:8px; border-bottom:1px solid #eee;"><pre style="margin:0; white-space:pre-wrap; font-size:0.8rem;">{{ row.payload }}</pre></td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|