` sitzt.
-Noch nicht übertragen: Betreiber-Accounts, Betreiber-Audit-Log,
-Wiedervorlage, "Meine Anträge" — nächste Kandidaten, falls das Muster
-fortgesetzt werden soll (Audit-Log wird langfristig am ehesten groß
-genug für Paginierung).
+**Ebenfalls ausgerollt (2026-08-31, zweite Runde):** Betreiber-Accounts
+(`.page-header` + Filter über Firmenname + Paginierung), Betreiber-
+Audit-Log (`.page-header` + Filter über Aktion/Zieltyp/Details +
+Paginierung), "Meine Anträge" (`.page-header` + Filter über Titel/
+Status/Häufigkeit + Paginierung), Wiedervorlage (nur `.page-header`,
+bewusst ohne Paginierung — natürlich begrenzt auf "braucht gerade
+Aufmerksamkeit").
+
+**Bekannte Einschränkung beim Audit-Log:** `ListAuditLog` holt weiterhin
+nur die neuesten `auditLogFetchLimit` (1000) Einträge aus der DB, dann
+wird in Go gefiltert/paginiert (`auditLogFetchLimit`-Konstante in
+`betreiber_handlers.go`) — keine echte DB-seitige Offset-Paginierung.
+Für ein potenziell sehr groß werdendes, append-only Audit-Log ist das
+mittelfristig nicht die saubere Lösung (Einträge jenseits der 1000
+neuesten sind über die Such-/Paginierungs-UI nicht erreichbar), aber
+proportional zum aktuellen Datenvolumen und konsistent mit dem
+In-Memory-Paginierungsmuster der übrigen Listen. Bei echtem Bedarf:
+`store.ListAuditLog` um `offset`/echtes SQL-`LIMIT`/`OFFSET` erweitern.
**Verifikationsmethode für CSS-Änderungen:** Live-Cookie-Auth per
Chromium-Headless/CDP ist im Sandbox-Environment nicht möglich (kein
diff --git a/internal/web/antrag_handlers.go b/internal/web/antrag_handlers.go
index e1d85c1..e201b61 100644
--- a/internal/web/antrag_handlers.go
+++ b/internal/web/antrag_handlers.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"net/http"
+ "strings"
"github.com/netcell-it/deklarix/internal/rules"
"github.com/netcell-it/deklarix/internal/store"
@@ -334,9 +335,11 @@ type antragListItem struct {
}
type antragListData struct {
- Title string
- Nav navData
- Antraege []antragListItem
+ Title string
+ Nav navData
+ Antraege []antragListItem
+ Suche string
+ Pagination pagination
}
// handleAntragList zeigt die eigenen Anträge (Ebene 2 — "Eigene
@@ -351,8 +354,16 @@ func (s *Server) handleAntragList(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Anträge konnten nicht geladen werden: "+err.Error(), http.StatusInternalServerError)
return
}
- data := antragListData{Title: "Meine Anträge", Nav: navFor(r)}
+ q := strings.TrimSpace(r.URL.Query().Get("q"))
+ var gefiltert []store.Antrag
for _, a := range list {
+ if matchesQuery(q, a.Titel, a.Status, a.Haeufigkeit) {
+ gefiltert = append(gefiltert, a)
+ }
+ }
+ pag := paginationFromRequest(r, len(gefiltert))
+ data := antragListData{Title: "Meine Anträge", Nav: navFor(r), Suche: q, Pagination: pag}
+ for _, a := range paginate(gefiltert, pag) {
data.Antraege = append(data.Antraege, antragListItem{
ID: a.ID, Titel: a.Titel, Status: a.Status, Haeufigkeit: a.Haeufigkeit,
CreatedAt: a.CreatedAt.Format("02.01.2006 15:04"),
diff --git a/internal/web/betreiber_handlers.go b/internal/web/betreiber_handlers.go
index bad1881..08490c7 100644
--- a/internal/web/betreiber_handlers.go
+++ b/internal/web/betreiber_handlers.go
@@ -2,9 +2,11 @@ package web
import (
"net/http"
+ "strings"
"time"
"github.com/netcell-it/deklarix/internal/auth"
+ "github.com/netcell-it/deklarix/internal/store"
)
type betreiberDashboardData struct {
@@ -52,9 +54,11 @@ type betreiberAccountListItem struct {
}
type betreiberAccountListData struct {
- Title string
- Nav navData
- Accounts []betreiberAccountListItem
+ Title string
+ Nav navData
+ Accounts []betreiberAccountListItem
+ Suche string
+ Pagination pagination
}
// handleBetreiberAccountList listet alle Mandanten der Plattform.
@@ -64,8 +68,16 @@ func (s *Server) handleBetreiberAccountList(w http.ResponseWriter, r *http.Reque
http.Error(w, "Accounts konnten nicht geladen werden: "+err.Error(), http.StatusInternalServerError)
return
}
- data := betreiberAccountListData{Title: "Accounts", Nav: navFor(r)}
+ q := strings.TrimSpace(r.URL.Query().Get("q"))
+ var gefiltert []store.Account
for _, a := range accounts {
+ if matchesQuery(q, a.Name) {
+ gefiltert = append(gefiltert, a)
+ }
+ }
+ pag := paginationFromRequest(r, len(gefiltert))
+ data := betreiberAccountListData{Title: "Accounts", Nav: navFor(r), Suche: q, Pagination: pag}
+ for _, a := range paginate(gefiltert, pag) {
data.Accounts = append(data.Accounts, betreiberAccountListItem{
ID: a.ID, Name: a.Name, CreatedAt: a.CreatedAt.Format("02.01.2006 15:04"),
})
@@ -218,20 +230,37 @@ type betreiberAuditEntryView struct {
}
type betreiberAuditLogData struct {
- Title string
- Nav navData
- Entries []betreiberAuditEntryView
+ Title string
+ Nav navData
+ Entries []betreiberAuditEntryView
+ Suche string
+ Pagination pagination
}
+// auditLogFetchLimit begrenzt, wie viele der neuesten Einträge aus der
+// DB geholt werden, bevor im Go-Code gefiltert/paginiert wird — echte
+// DB-seitige Offset-Paginierung wäre für ein potenziell sehr groß
+// werdendes Audit-Log der sauberere Ansatz, ist hier aber (noch) nicht
+// umgesetzt (siehe CLAUDE.md, Offene Punkte).
+const auditLogFetchLimit = 1000
+
// handleBetreiberAuditLog zeigt das plattformweite Audit-Log.
func (s *Server) handleBetreiberAuditLog(w http.ResponseWriter, r *http.Request) {
- entries, err := s.store.ListAuditLog(r.Context(), 200)
+ entries, err := s.store.ListAuditLog(r.Context(), auditLogFetchLimit)
if err != nil {
http.Error(w, "Audit-Log konnte nicht geladen werden: "+err.Error(), http.StatusInternalServerError)
return
}
- data := betreiberAuditLogData{Title: "Audit-Log", Nav: navFor(r)}
+ q := strings.TrimSpace(r.URL.Query().Get("q"))
+ var gefiltert []store.AuditEntry
for _, e := range entries {
+ if matchesQuery(q, e.Action, e.TargetType, e.Details) {
+ gefiltert = append(gefiltert, e)
+ }
+ }
+ pag := paginationFromRequest(r, len(gefiltert))
+ data := betreiberAuditLogData{Title: "Audit-Log", Nav: navFor(r), Suche: q, Pagination: pag}
+ for _, e := range paginate(gefiltert, pag) {
data.Entries = append(data.Entries, betreiberAuditEntryView{
CreatedAt: e.CreatedAt.Format("02.01.2006 15:04:05"), Action: e.Action,
TargetType: e.TargetType, TargetID: e.TargetID, Details: e.Details,
diff --git a/internal/web/templates/antraege_liste.html b/internal/web/templates/antraege_liste.html
index 3d067c3..3e99afd 100644
--- a/internal/web/templates/antraege_liste.html
+++ b/internal/web/templates/antraege_liste.html
@@ -4,22 +4,42 @@
{{template "nav" .Nav}}
-
Meine Anträge
-{{if not .Antraege}}
-
Noch keine Anträge gestellt.
-{{else}}
-