Address production-readiness review: clearer errors, safer votes, and ops hardening.

Distinguish auth/lookup failures, make votes idempotent on visible questions, bound shutdown, page admin users, LRU throttle, trusted-proxy CIDRs, avatar cleanup, versioned migrations, and session cleanup logging.
This commit is contained in:
2026-08-22 12:16:59 -07:00
parent 5bdaa8977f
commit 29b0536215
26 changed files with 612 additions and 146 deletions
+45 -21
View File
@@ -3,38 +3,62 @@ package store
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jackc/pgx/v5/pgconn"
"plumber/internal/store/sqlc"
)
// Vote toggles or sets a user's vote on a question (value must be 1 or -1).
func Vote(ctx context.Context, db *sql.DB, userID, questionID string, value int) error {
if value != 1 && value != -1 {
// ErrDuplicateUsername is returned when inserting a username that already exists.
var ErrDuplicateUsername = errors.New("username taken")
// ErrHiddenOrMissing is returned when voting on a hidden or unknown question.
var ErrHiddenOrMissing = errors.New("question not votable")
// SetVote sets the user's vote to value (1, -1, or 0 to clear) on a visible question.
func SetVote(ctx context.Context, db *sql.DB, userID, questionID string, value int) error {
if value != 1 && value != -1 && value != 0 {
return fmt.Errorf("invalid vote")
}
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback()
q := sqlc.New(tx)
current, err := q.GetVote(ctx, sqlc.GetVoteParams{UserID: userID, QuestionID: questionID})
if err != nil && err != sql.ErrNoRows {
return err
}
if err == nil && int(current) == value {
err = q.DeleteVote(ctx, sqlc.DeleteVoteParams{UserID: userID, QuestionID: questionID})
} else {
err = q.UpsertVote(ctx, sqlc.UpsertVoteParams{
q := sqlc.New(db)
if value == 0 {
visible, err := q.QuestionIsVisible(ctx, questionID)
if err != nil {
return err
}
if !visible {
return ErrHiddenOrMissing
}
return q.DeleteVote(ctx, sqlc.DeleteVoteParams{
UserID: userID,
QuestionID: questionID,
Value: int32(value),
})
}
n, err := q.UpsertVoteOnVisible(ctx, sqlc.UpsertVoteOnVisibleParams{
UserID: userID,
QuestionID: questionID,
Value: int32(value),
})
if err != nil {
return err
return mapUniqueViolation(err)
}
return tx.Commit()
if n == 0 {
return ErrHiddenOrMissing
}
return nil
}
// Vote is kept as an alias for SetVote for callers that still use the old name.
func Vote(ctx context.Context, db *sql.DB, userID, questionID string, value int) error {
return SetVote(ctx, db, userID, questionID, value)
}
func mapUniqueViolation(err error) error {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
return ErrDuplicateUsername
}
return err
}