6.8 KiB
Reorder-Validierung Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: PlaylistStore.Reorder soll mit ErrReorderMismatch abbrechen, wenn die übergebene ID-Liste nicht vollständig oder nicht korrekt ist; beide Handler geben dann 400 zurück.
Architecture: Sentinel-Fehler im store-Package; Vollständigkeitsprüfung per COUNT + RowsAffected-Check im Store; beide HTTP-Handler unterscheiden Validierungsfehler von DB-Fehlern via errors.Is.
Tech Stack: Go, pgx/v5, net/http
Task 1: Sentinel-Fehler + Validierung in store.go
Files:
-
Modify:
server/backend/internal/store/store.go:4-10(imports) -
Modify:
server/backend/internal/store/store.go:533-550(Reorder) -
Schritt 1:
errorszu den Imports hinzufügenDatei:
server/backend/internal/store/store.go, Zeilen 4–10.Vorher:
import ( "context" "fmt" "time" "github.com/jackc/pgx/v5/pgxpool" )Nachher:
import ( "context" "errors" "fmt" "time" "github.com/jackc/pgx/v5/pgxpool" ) -
Schritt 2: Sentinel-Variable nach den Imports einfügen
Direkt nach dem Import-Block (vor der ersten Typdefinition) einfügen:
// ErrReorderMismatch wird von Reorder zurückgegeben, wenn die übergebene // ID-Liste nicht mit den tatsächlichen Items der Playlist übereinstimmt. var ErrReorderMismatch = errors.New("reorder: item list does not match playlist") -
Schritt 3:
Reorder-Funktion ersetzenDatei:
server/backend/internal/store/store.go, die gesamteReorder-Funktion (aktuell Zeilen 533–550) ersetzen durch:// Reorder sets order_index for each item ID in the given slice order. // Returns ErrReorderMismatch if the number of provided IDs does not match // the number of items in the playlist, or if any ID does not belong to it. func (s *PlaylistStore) Reorder(ctx context.Context, playlistID string, itemIDs []string) error { tx, err := s.pool.Begin(ctx) if err != nil { return err } defer tx.Rollback(ctx) //nolint:errcheck var count int if err := tx.QueryRow(ctx, `select count(*) from playlist_items where playlist_id=$1`, playlistID, ).Scan(&count); err != nil { return err } if count != len(itemIDs) { return fmt.Errorf("%w: got %d ids, playlist has %d items", ErrReorderMismatch, len(itemIDs), count) } for i, id := range itemIDs { tag, err := tx.Exec(ctx, `update playlist_items set order_index=$1 where id=$2 and playlist_id=$3`, i, id, playlistID, ) if err != nil { return err } if tag.RowsAffected() != 1 { return fmt.Errorf("%w: id %s not found in playlist %s", ErrReorderMismatch, id, playlistID) } } return tx.Commit(ctx) } -
Schritt 4: Kompilieren
cd server/backend && go build ./...Erwartet: keine Ausgabe, Exit 0.
-
Schritt 5: Committen
git add server/backend/internal/store/store.go git commit -m "fix(store): Reorder validiert Vollständigkeit und RowsAffected"
Task 2: HandleReorderUI gibt 400 bei Mismatch zurück
Files:
-
Modify:
server/backend/internal/httpapi/manage/ui.go:1-20(imports) -
Modify:
server/backend/internal/httpapi/manage/ui.go:743-746(Fehlerbehandlung) -
Schritt 1:
errorszu den Imports hinzufügenDatei:
server/backend/internal/httpapi/manage/ui.go. Im import-Block"errors"ergänzen (alphabetisch vor"encoding/json"):import ( "bytes" "encoding/json" "errors" "html/template" "log/slog" "net/http" "os" "path/filepath" "strconv" "strings" "time" "git.az-it.net/az/morz-infoboard/server/backend/internal/config" "git.az-it.net/az/morz-infoboard/server/backend/internal/fileutil" "git.az-it.net/az/morz-infoboard/server/backend/internal/mqttnotifier" "git.az-it.net/az/morz-infoboard/server/backend/internal/reqcontext" "git.az-it.net/az/morz-infoboard/server/backend/internal/store" ) -
Schritt 2: Fehlerbehandlung in
HandleReorderUIersetzenDatei:
server/backend/internal/httpapi/manage/ui.go, Zeilen 743–746. Den Block:if err := playlists.Reorder(r.Context(), playlist.ID, ids); err != nil { http.Error(w, "db error", http.StatusInternalServerError) return }ersetzen durch:
if err := playlists.Reorder(r.Context(), playlist.ID, ids); err != nil { if errors.Is(err, store.ErrReorderMismatch) { http.Error(w, "item list mismatch", http.StatusBadRequest) } else { http.Error(w, "db error", http.StatusInternalServerError) } return } -
Schritt 3: Kompilieren
cd server/backend && go build ./...Erwartet: keine Ausgabe, Exit 0.
-
Schritt 4: Committen
git add server/backend/internal/httpapi/manage/ui.go git commit -m "fix(manage): HandleReorderUI gibt 400 bei Mismatch zurück"
Task 3: HandleReorder gibt 400 bei Mismatch zurück
Files:
-
Modify:
server/backend/internal/httpapi/manage/playlist.go:1-14(imports) -
Modify:
server/backend/internal/httpapi/manage/playlist.go:244-247(Fehlerbehandlung) -
Schritt 1:
errorszu den Imports hinzufügenDatei:
server/backend/internal/httpapi/manage/playlist.go. Im import-Block"errors"ergänzen:import ( "encoding/json" "errors" "fmt" "net/http" "strconv" "strings" "time" "git.az-it.net/az/morz-infoboard/server/backend/internal/mqttnotifier" "git.az-it.net/az/morz-infoboard/server/backend/internal/reqcontext" "git.az-it.net/az/morz-infoboard/server/backend/internal/store" ) -
Schritt 2: Fehlerbehandlung in
HandleReorderersetzenDatei:
server/backend/internal/httpapi/manage/playlist.go, Zeilen 244–247. Den Block:if err := playlists.Reorder(r.Context(), playlistID, ids); err != nil { http.Error(w, "db error", http.StatusInternalServerError) return }ersetzen durch:
if err := playlists.Reorder(r.Context(), playlistID, ids); err != nil { if errors.Is(err, store.ErrReorderMismatch) { http.Error(w, "item list mismatch", http.StatusBadRequest) } else { http.Error(w, "db error", http.StatusInternalServerError) } return } -
Schritt 3: Kompilieren und Tests ausführen
cd server/backend && go build ./... && go test ./...Erwartet: keine Ausgabe bei build, alle Tests grün.
-
Schritt 4: Committen
git add server/backend/internal/httpapi/manage/playlist.go git commit -m "fix(manage): HandleReorder gibt 400 bei Mismatch zurück"