diff --git a/scripts/git-hooks/pre-commit b/scripts/git-hooks/pre-commit
new file mode 100755
index 0000000..2486532
--- /dev/null
+++ b/scripts/git-hooks/pre-commit
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+# AegisSight-Verwaltung Pre-Commit-Hook.
+#
+# Ueberprueft bei jeder Aenderung in src/shared/ den Drift-Stand gegen das
+# Monitor-Repo. Gibt eine Warnung aus, BLOCKIERT den Commit aber NICHT -
+# der User entscheidet selbst, ob er zurueck will.
+#
+# Installation: scripts/install-hooks.sh
+
+REPO_ROOT="$(git rev-parse --show-toplevel)"
+cd "$REPO_ROOT" || exit 0
+
+# Nur prüfen wenn shared/ geändert wird
+if ! git diff --cached --name-only | grep -q '^src/shared/'; then
+ exit 0
+fi
+
+# venv-Python finden
+PY=""
+for cand in "venv/bin/python3" "venv/bin/python" "/home/claude-dev/.venvs/verwaltung/bin/python3"; do
+ if [ -x "$cand" ]; then PY="$cand"; break; fi
+done
+if [ -z "$PY" ] || [ ! -f "scripts/sync_shared.py" ]; then
+ # Tool nicht verfuegbar - silent durchlassen
+ exit 0
+fi
+
+if ! out=$("$PY" scripts/sync_shared.py --check 2>&1); then
+ # --check Exit 1 = auto-syncbarer Drift vorhanden
+ echo ""
+ echo "================================================================"
+ echo " WARNUNG: src/shared/ Drift gegen Monitor-Repo erkannt"
+ echo "================================================================"
+ echo "$out" | head -30
+ echo ""
+ echo " Mehr Details: ./venv/bin/python scripts/sync_shared.py --check"
+ echo " Aufloesen: ./venv/bin/python scripts/sync_shared.py --apply"
+ echo " (oder bewusst forken: LOCKED_FILES in scripts/sync_shared.py)"
+ echo ""
+ echo " Commit laeuft trotzdem durch - du entscheidest."
+ echo "================================================================"
+fi
+
+exit 0
diff --git a/scripts/install-hooks.sh b/scripts/install-hooks.sh
new file mode 100755
index 0000000..7813464
--- /dev/null
+++ b/scripts/install-hooks.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+# Installiert die Git-Hooks aus scripts/git-hooks/ in die lokale Repo-Konfig.
+#
+# Nutzung: ./scripts/install-hooks.sh
+#
+# Idempotent: Bereits installierte Hooks werden nur ueberschrieben wenn
+# sie aus scripts/git-hooks/ kommen (Marker-Check), nicht user-eigene.
+set -euo pipefail
+
+REPO_ROOT="$(git rev-parse --show-toplevel)"
+SRC_DIR="$REPO_ROOT/scripts/git-hooks"
+DST_DIR="$REPO_ROOT/.git/hooks"
+
+if [ ! -d "$SRC_DIR" ]; then
+ echo "FEHLER: $SRC_DIR nicht gefunden" >&2
+ exit 1
+fi
+
+mkdir -p "$DST_DIR"
+
+count=0
+for hook in "$SRC_DIR"/*; do
+ [ -f "$hook" ] || continue
+ name="$(basename "$hook")"
+ target="$DST_DIR/$name"
+
+ # Wenn Ziel existiert und kein AegisSight-Marker drin: ueberspringen
+ if [ -f "$target" ] && ! grep -q "AegisSight-Verwaltung Pre-Commit-Hook\|AegisSight-Verwaltung Hook" "$target" 2>/dev/null; then
+ echo " ! $name uebersprungen (existiert, kein AegisSight-Marker)"
+ continue
+ fi
+
+ cp "$hook" "$target"
+ chmod +x "$target"
+ echo " + $name installiert"
+ count=$((count + 1))
+done
+
+echo ""
+echo "$count Hook(s) installiert nach $DST_DIR"
diff --git a/src/static/dashboard.html b/src/static/dashboard.html
index b13790f..6878bc5 100644
--- a/src/static/dashboard.html
+++ b/src/static/dashboard.html
@@ -393,6 +393,7 @@
+
diff --git a/src/static/js/audit.js b/src/static/js/audit.js
index 9d04580..46e445e 100644
--- a/src/static/js/audit.js
+++ b/src/static/js/audit.js
@@ -38,7 +38,7 @@ document.addEventListener("DOMContentLoaded", () => {
});
// Filter-Inputs verdrahten
- ["auditFilterAction", "auditFilterResource", "auditFilterAdmin",
+ ["auditFilterAction", "auditFilterResource", "auditFilterResourceId", "auditFilterAdmin",
"auditFilterFrom", "auditFilterTo"].forEach((id) => {
const el = document.getElementById(id);
if (el) el.addEventListener("change", () => { auditCache.offset = 0; loadAudit(); });
@@ -112,12 +112,14 @@ async function loadAudit() {
const params = new URLSearchParams();
const action = document.getElementById("auditFilterAction")?.value;
const resource = document.getElementById("auditFilterResource")?.value;
+ const resourceId = document.getElementById("auditFilterResourceId")?.value;
const adminId = document.getElementById("auditFilterAdmin")?.value;
const from = document.getElementById("auditFilterFrom")?.value;
const to = document.getElementById("auditFilterTo")?.value;
if (action) params.append("action", action);
if (resource) params.append("resource_type", resource);
+ if (resourceId) params.append("resource_id", resourceId);
if (adminId) params.append("admin_id", adminId);
if (from) params.append("from_ts", from);
if (to) params.append("to_ts", to);