antragstracker/frontend/src/routes/anleitung/+page.svelte

382 lines
16 KiB
Svelte
Raw Normal View History

<script lang="ts">
import { onMount } from 'svelte';
import Ampel from '$lib/components/Ampel.svelte';
import { fetchAmpelDefinition, type AmpelDefinition } from '$lib/api';
let definition = $state<AmpelDefinition | null>(null);
let error = $state<string | null>(null);
// Mock-Ampeldaten pro Strang für die Beispiele
const MOCK_AMPELN: Record<string, {
schritte: { id: string; label: string; aktiv: boolean; erreicht: boolean; farbe: string }[];
abzweigung: { id: string; label: string; farbe: string } | null;
kontrollfrage: string | null;
beschreibung: string;
ablauf: string;
}> = {
antrag: {
schritte: [
{ id: 'eingereicht', label: 'Eingereicht', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beraten', label: 'Beraten', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beschlossen', label: 'Beschlossen', aktiv: true, erreicht: true, farbe: 'gelb' },
{ id: 'umgesetzt', label: 'Umgesetzt', aktiv: false, erreicht: false, farbe: 'grau' },
],
abzweigung: null,
kontrollfrage: 'Hat die Verwaltung umgesetzt, was beschlossen wurde?',
beschreibung: 'Politik will etwas verändern — die Verwaltung soll es umsetzen.',
ablauf: 'Antrag wird eingereicht → in Ausschüssen beraten → vom Rat beschlossen → von der Verwaltung umgesetzt (oder auch nicht).',
},
anfrage: {
schritte: [
{ id: 'gestellt', label: 'Gestellt', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beantwortet', label: 'Beantwortet', aktiv: true, erreicht: true, farbe: 'gruen' },
],
abzweigung: null,
kontrollfrage: 'Wurde die Anfrage befriedigend beantwortet?',
beschreibung: 'Politik fragt — die Verwaltung antwortet.',
ablauf: 'Anfrage wird gestellt → Verwaltung antwortet schriftlich → KI bewertet, ob die Antwort die Frage tatsächlich beantwortet.',
},
beschlussvorlage: {
schritte: [
{ id: 'eingebracht', label: 'Eingebracht', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beraten', label: 'Beraten', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beschlossen', label: 'Beschlossen', aktiv: true, erreicht: true, farbe: 'gelb' },
{ id: 'umgesetzt', label: 'Umgesetzt', aktiv: false, erreicht: false, farbe: 'grau' },
],
abzweigung: null,
kontrollfrage: 'Wurde so umgesetzt wie beschlossen?',
beschreibung: 'Die Verwaltung legt einen Vorschlag vor — der Rat stimmt zu.',
ablauf: 'Verwaltung bringt Vorlage ein → Beratung in Ausschüssen → Ratsbeschluss → Umsetzung durch die Verwaltung.',
},
mitteilung: {
schritte: [
{ id: 'vorgelegt', label: 'Vorgelegt', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'kenntnisnahme', label: 'Kenntnisnahme', aktiv: true, erreicht: true, farbe: 'gruen' },
],
abzweigung: null,
kontrollfrage: null,
beschreibung: 'Die Verwaltung informiert den Rat — keine Abstimmung, nur Kenntnisnahme.',
ablauf: 'Verwaltung legt Mitteilung vor → Rat nimmt zur Kenntnis.',
},
};
// Beispiel-Ampel mit Abzweigung (versandet)
const MOCK_ABZWEIGUNG = {
strang: 'antrag',
strang_label: 'Antrag (versandet)',
kontrollfrage: 'Hat die Verwaltung umgesetzt?',
schritte: [
{ id: 'eingereicht', label: 'Eingereicht', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beraten', label: 'Beraten', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beschlossen', label: 'Beschlossen', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'umgesetzt', label: 'Umgesetzt', aktiv: false, erreicht: false, farbe: 'grau' },
],
abzweigung: { id: 'versandet', label: 'Versandet', farbe: 'rot' },
};
const MOCK_ABGELEHNT = {
strang: 'antrag',
strang_label: 'Antrag (abgelehnt)',
kontrollfrage: null,
schritte: [
{ id: 'eingereicht', label: 'Eingereicht', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beraten', label: 'Beraten', aktiv: false, erreicht: true, farbe: 'gruen' },
{ id: 'beschlossen', label: 'Beschlossen', aktiv: false, erreicht: false, farbe: 'grau' },
{ id: 'umgesetzt', label: 'Umgesetzt', aktiv: false, erreicht: false, farbe: 'grau' },
],
abzweigung: { id: 'abgelehnt', label: 'Abgelehnt', farbe: 'rot' },
};
const STRANG_FARBEN: Record<string, { bg: string; border: string; text: string }> = {
antrag: { bg: 'bg-green-50', border: 'border-green-200', text: 'text-green-800' },
anfrage: { bg: 'bg-blue-50', border: 'border-blue-200', text: 'text-blue-800' },
beschlussvorlage: { bg: 'bg-amber-50', border: 'border-amber-200', text: 'text-amber-800' },
mitteilung: { bg: 'bg-gray-50', border: 'border-gray-200', text: 'text-gray-700' },
};
const STRANG_ORDER = ['antrag', 'anfrage', 'beschlussvorlage', 'mitteilung'];
const TOC = [
{ id: 'was-ist', label: 'Was ist der Antragstracker?' },
{ id: 'straenge', label: 'Die vier Verfahrensstränge' },
{ id: 'ampel', label: 'Die Ampel verstehen' },
{ id: 'ki-bewertung', label: 'Die KI-Bewertung' },
{ id: 'szenarien', label: 'Konkrete Szenarien' },
{ id: 'fristen', label: 'Fristen-Tracking' },
];
onMount(async () => {
try {
definition = await fetchAmpelDefinition();
} catch (e) {
error = 'Strang-Definitionen konnten nicht geladen werden.';
console.error(e);
}
});
function strangLabel(key: string): string {
if (definition?.straenge[key]) return definition.straenge[key].label;
const fallback: Record<string, string> = {
antrag: 'Anträge',
anfrage: 'Anfragen',
beschlussvorlage: 'Beschlussvorlagen',
mitteilung: 'Mitteilungen',
};
return fallback[key] || key;
}
function buildMockAmpel(key: string) {
const mock = MOCK_AMPELN[key];
if (!mock) return null;
return {
strang: key,
strang_label: strangLabel(key),
kontrollfrage: mock.kontrollfrage,
schritte: mock.schritte,
abzweigung: mock.abzweigung,
};
}
</script>
<svelte:head>
<title>Anleitung — Antragstracker Hagen</title>
</svelte:head>
<div class="max-w-3xl mx-auto">
<h1 class="text-3xl font-bold text-gray-900 mb-2">Anleitung</h1>
<p class="text-gray-500 mb-8">Wie der Antragstracker funktioniert — und wie du ihn nutzt.</p>
<!-- Inhaltsverzeichnis -->
<nav class="bg-white rounded-lg border border-gray-200 p-4 mb-10">
<p class="text-xs font-semibold text-gray-400 uppercase tracking-wide mb-2">Inhalt</p>
<ol class="space-y-1">
{#each TOC as item}
<li>
<a href="#{item.id}" class="text-sm text-green-700 hover:text-green-900 hover:underline">
{item.label}
</a>
</li>
{/each}
</ol>
</nav>
<!-- 1. Was ist der Antragstracker? -->
<section id="was-ist" class="mb-12 scroll-mt-24">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Was ist der Antragstracker?</h2>
<div class="prose prose-gray max-w-none">
<p>
Der Antragstracker ist ein kommunalpolitisches Kontroll-Instrument für den Rat der Stadt Hagen.
Er verfolgt den Weg von Anträgen, Anfragen und Beschlüssen durch die Gremien — und macht sichtbar,
was beschlossen wurde und was davon tatsächlich umgesetzt wird.
</p>
<p>
Daten werden aus dem Ratsinformationssystem (Allris) importiert. Eine KI analysiert den aktuellen
Stand jedes Vorgangs und bewertet, ob beschlossene Maßnahmen umgesetzt wurden.
</p>
</div>
</section>
<!-- 2. Die vier Verfahrensstränge -->
<section id="straenge" class="mb-12 scroll-mt-24">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Die vier Verfahrensstränge</h2>
<p class="text-gray-600 mb-6">
Jeder Vorgang im Rat folgt einem von vier Verfahrenssträngen. Jeder Strang hat eigene Schritte,
eine eigene Ampel — und eine eigene Kontrollfrage.
</p>
{#if error}
<div class="bg-red-50 border border-red-200 rounded-lg p-3 text-sm text-red-700 mb-4">{error}</div>
{/if}
<div class="space-y-6">
{#each STRANG_ORDER as key}
{@const farben = STRANG_FARBEN[key]}
{@const mock = MOCK_AMPELN[key]}
{@const ampelData = buildMockAmpel(key)}
<div class="{farben.bg} border {farben.border} rounded-lg p-5">
<h3 class="text-lg font-semibold {farben.text} mb-1">{strangLabel(key)}</h3>
<p class="text-sm text-gray-700 mb-3">{mock.beschreibung}</p>
{#if ampelData}
<div class="bg-white/60 rounded-md p-3 mb-3">
<Ampel ampel={ampelData} />
</div>
{/if}
{#if mock.kontrollfrage}
<p class="text-sm font-medium text-gray-800 mb-1">
Kontrollfrage: <span class="italic">{mock.kontrollfrage}</span>
</p>
{/if}
<p class="text-sm text-gray-600">
<span class="font-medium">Ablauf:</span> {mock.ablauf}
</p>
</div>
{/each}
</div>
</section>
<!-- 3. Die Ampel verstehen -->
<section id="ampel" class="mb-12 scroll-mt-24">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Die Ampel verstehen</h2>
<div class="prose prose-gray max-w-none mb-6">
<p>
Jeder Vorgang hat eine Ampel, die seinen Fortschritt zeigt. Die Schritte werden
von links nach rechts durchlaufen.
</p>
</div>
<div class="space-y-4 mb-6">
<div class="flex items-start gap-3">
<div class="w-5 h-5 rounded-full border-2 border-gray-300 bg-white shrink-0 mt-0.5"></div>
<div>
<p class="text-sm font-medium text-gray-900">Offen (weißer Kreis)</p>
<p class="text-sm text-gray-600">Dieser Schritt wurde noch nicht erreicht.</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="w-5 h-5 rounded-full bg-gray-300 shrink-0 mt-0.5"></div>
<div>
<p class="text-sm font-medium text-gray-900">Durchlaufen (grau)</p>
<p class="text-sm text-gray-600">Dieser Schritt liegt in der Vergangenheit — er wurde bereits passiert.</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="w-5 h-5 rounded-full bg-yellow-500 shrink-0 mt-0.5" style="box-shadow: 0 0 0 3px rgba(234, 179, 8, 0.19)"></div>
<div>
<p class="text-sm font-medium text-gray-900">Aktuell — wartet (gelb)</p>
<p class="text-sm text-gray-600">Der Vorgang befindet sich gerade in diesem Schritt. Es passiert etwas — oder es wird darauf gewartet.</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="w-5 h-5 rounded-full bg-green-500 shrink-0 mt-0.5" style="box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.19)"></div>
<div>
<p class="text-sm font-medium text-gray-900">Erledigt (grün)</p>
<p class="text-sm text-gray-600">Dieser Schritt ist abgeschlossen — der aktive Schritt leuchtet grün, wenn er positiv abgeschlossen ist.</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="w-5 h-5 rounded-full bg-red-500 shrink-0 mt-0.5" style="box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.19)"></div>
<div>
<p class="text-sm font-medium text-gray-900">Gescheitert (rot)</p>
<p class="text-sm text-gray-600">Hier ist etwas schiefgegangen — abgelehnt, gescheitert oder nicht umgesetzt.</p>
</div>
</div>
</div>
<h3 class="text-lg font-semibold text-gray-900 mb-3">Abzweigungen</h3>
<p class="text-sm text-gray-600 mb-4">
Manchmal nimmt ein Vorgang nicht den normalen Weg. In diesen Fällen zeigt die Ampel eine Abzweigung:
</p>
<div class="space-y-4">
<div class="bg-white border border-gray-200 rounded-lg p-4">
<p class="text-sm font-medium text-red-700 mb-2">Versandet</p>
<p class="text-sm text-gray-600 mb-3">
Ein Antrag wurde beschlossen, aber nie umgesetzt. Die Verwaltung hat ihn schlicht nicht weiterverfolgt.
</p>
<Ampel ampel={MOCK_ABZWEIGUNG} />
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<p class="text-sm font-medium text-red-700 mb-2">Abgelehnt</p>
<p class="text-sm text-gray-600 mb-3">
Der Vorgang wurde in der Beratung oder Abstimmung abgelehnt und nicht weiterverfolgt.
</p>
<Ampel ampel={MOCK_ABGELEHNT} />
</div>
</div>
</section>
<!-- 4. Die KI-Bewertung -->
<section id="ki-bewertung" class="mb-12 scroll-mt-24">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Die KI-Bewertung</h2>
<div class="prose prose-gray max-w-none">
<p>
Jeder Vorgang wird von einer KI analysiert. Sie liest die zugehörigen Dokumente aus dem
Ratsinformationssystem und erstellt:
</p>
<ul>
<li><strong>Eine Zusammenfassung</strong> — worum geht es, was wurde beschlossen?</li>
<li><strong>Einen Umsetzungs-Score</strong> — wie weit ist die Umsetzung fortgeschritten (0100%)?</li>
</ul>
<h3>Was bedeutet der Prozentwert?</h3>
<ul>
<li><strong>0%</strong> — Keine erkennbare Umsetzung</li>
<li><strong>149%</strong> — Teilweise umgesetzt, wesentliche Teile fehlen</li>
<li><strong>5079%</strong> — Überwiegend umgesetzt, aber nicht vollständig</li>
<li><strong>80100%</strong> — Weitgehend bis vollständig umgesetzt</li>
</ul>
<h3>Neubewertung</h3>
<p>
Bewertungen können neu angefordert werden — etwa wenn neue Informationen vorliegen oder eine
Einschätzung fragwürdig erscheint. Dabei kann eine Anmerkung mitgegeben werden, die der KI
als zusätzlichen Kontext dient.
</p>
<h3>Versionierung</h3>
<p>
Jede Bewertung wird versioniert. Alte Bewertungen bleiben erhalten und sind nachvollziehbar.
So lässt sich verfolgen, wie sich die Einschätzung über die Zeit verändert hat.
</p>
</div>
</section>
<!-- 5. Konkrete Szenarien -->
<section id="szenarien" class="mb-12 scroll-mt-24">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Konkrete Szenarien</h2>
<div class="space-y-3">
<div class="bg-white border border-gray-200 rounded-lg p-4">
<p class="text-sm font-semibold text-gray-900 mb-1">„Welche beschlossenen Anträge wurden nie umgesetzt?"</p>
<p class="text-sm text-gray-600">
<a href="/explorer" class="text-green-700 hover:underline">Explorer</a> öffnen, nach Status „versandet" filtern.
Zeigt alle Vorgänge, bei denen die Verwaltung beschlossene Maßnahmen nicht weiterverfolgt hat.
</p>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<p class="text-sm font-semibold text-gray-900 mb-1">„Hat die Verwaltung meine Anfrage wirklich beantwortet?"</p>
<p class="text-sm text-gray-600">
→ Anfrage im Explorer suchen, KI-Bewertung lesen. Falls unbefriedigend: Neubewertung mit
eigener Anmerkung anfordern.
</p>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<p class="text-sm font-semibold text-gray-900 mb-1">„Welche Fristen laufen demnächst ab?"</p>
<p class="text-sm text-gray-600">
<a href="/fristen" class="text-green-700 hover:underline">Fristen</a> öffnen.
Zeigt alle anstehenden und überfälligen Termine aus Beschlusstexten.
</p>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<p class="text-sm font-semibold text-gray-900 mb-1">„Wie stimmt meine Fraktion im Vergleich zu anderen ab?"</p>
<p class="text-sm text-gray-600">
<a href="/abstimmungen" class="text-green-700 hover:underline">Abstimmungen</a> öffnen.
Vergleicht das Abstimmungsverhalten aller Fraktionen.
</p>
</div>
</div>
</section>
<!-- 6. Fristen-Tracking -->
<section id="fristen" class="mb-12 scroll-mt-24">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Fristen-Tracking</h2>
<div class="prose prose-gray max-w-none">
<p>
In vielen Beschlüssen stecken konkrete Termine: „bis Ende Q2 umsetzen", „Bericht bis März vorlegen".
Der Antragstracker erkennt solche Fristen automatisch per KI und macht sie sichtbar.
</p>
<ul>
<li><strong>Automatische Erkennung</strong> — Die KI extrahiert Termine aus Beschlusstexten</li>
<li><strong>Manuelle Ergänzung</strong> — Fristen können auch von Hand hinzugefügt werden</li>
<li><strong>Farbkodierung</strong> — Überfällige Fristen werden rot markiert, anstehende gelb</li>
</ul>
<p>
Alle Fristen sind unter <a href="/fristen">/fristen</a> einsehbar, gefiltert nach Status und Zeitraum.
</p>
</div>
</section>
</div>