Overdue badges on the task board

Go · Go · beginner · modification

Adds an `overdue` flag to every task in the project task list, so the board can put a red badge on tasks that are past their due date. The rule lives in a small `isOverdue` function with its own table test: a task is overdue when it is not done and was due before now, so a task due exactly now, a finished task and a task with no due date stay unflagged. The list handler applies it to each task before encoding the response, reading the time from a clock injected into `Handler` (`time.Now` in `main`). The flag is computed per response, nothing new is stored.

Go 1.22 service, standard library only (`net/http` method-pattern `ServeMux`, `log/slog`, `database/sql`). `auth.RequireMember` (existing, unchanged) answers 401 or 403 itself unless the signed-in user is a member of the project in the path. `store.NewTaskStore(db).ListByProject` (existing, unchanged) reads the project's tasks in board order, at most 500 per project; it returns a non-nil, possibly empty slice (an empty project encodes as `[]`), and each `DueAt` is either nil or a `timestamptz` value. `config.Load`, `store.Open` and `httpserver.Serve` are unchanged; `httpserver.Serve(ctx, addr, h)` sets the server timeouts and drains in-flight requests on shutdown. The board's badge (web app) ships separately and reads `overdue` from this endpoint; until this PR, the field is absent and the board shows no badges.

Requirements

Files touched

--- cmd/api/main.go
 	"os/signal"
 	"syscall"
+	"time"
 
 	"example.com/taskboard/internal/auth"
 	defer db.Close()
 
-	th := &tasks.Handler{Store: store.NewTaskStore(db), Log: log}
+	th := &tasks.Handler{Store: store.NewTaskStore(db), Log: log, Now: time.Now}
 
 	mux := http.NewServeMux()
--- internal/tasks/tasks.go
 // Task is one row of a project's task list, as the board renders it.
 type Task struct {
-	ID    int64      `json:"id"`
-	Title string     `json:"title"`
-	Done  bool       `json:"done"`
-	DueAt *time.Time `json:"due_at"`
+	ID      int64      `json:"id"`
+	Title   string     `json:"title"`
+	Done    bool       `json:"done"`
+	DueAt   *time.Time `json:"due_at"`
+	Overdue bool       `json:"overdue"`
 }
 
 	Store Store
 	Log   *slog.Logger
+	Now   func() time.Time
 }

Review this PR

Go practice