morz-infoboard/docs/superpowers/plans/2026-03-26-reorder-validation.md
Jesko Anschütz b463aeeae1 docs: Implementierungsplan für Reorder-Validierung
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 22:20:15 +01:00

6.8 KiB
Raw Blame History

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: errors zu den Imports hinzufügen

    Datei: server/backend/internal/store/store.go, Zeilen 410.

    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 ersetzen

    Datei: server/backend/internal/store/store.go, die gesamte Reorder-Funktion (aktuell Zeilen 533550) 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: errors zu den Imports hinzufügen

    Datei: 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 HandleReorderUI ersetzen

    Datei: server/backend/internal/httpapi/manage/ui.go, Zeilen 743746. 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: errors zu den Imports hinzufügen

    Datei: 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 HandleReorder ersetzen

    Datei: server/backend/internal/httpapi/manage/playlist.go, Zeilen 244247. 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"