You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

8.4 KiB

TASKS

Use this board to coordinate handoff between planner, implementer, and reviewer.

Status values:

  • in_planning
  • ready_for_implement
  • in_implementation
  • ready_for_review
  • in_review
  • ready_to_commit
  • changes_requested
  • done

Command expectations:

  • planner moves tasks into in_planning and ready_for_implement
  • implementer moves tasks into in_implementation, ready_for_review, and done, and resumes work from changes_requested and ready_to_commit
  • reviewer moves tasks into in_review, ready_to_commit, or changes_requested
  • status_cycle should report deterministic task status, current owner role, and next recommended action based on this board
Task ID Scope Status Acceptance Criteria Evidence Next Role
T-001 Project scaffolding: Go module layout, root-config loading (file/env listing container paths + display names), Dockerfile skeleton, docker-compose example, README.md overview/setup skeleton done go build ./... succeeds; app boots and logs the configured roots from a sample config without panicking; README.md documents the config file/env format for declaring roots and the volume-mount + restart-to-add-root constraint PASS: config source/precedence/validation tests; go fmt ./..., go vet ./..., go test ./..., and go build -buildvcs=false ./... in golang:1.24; Docker image build + sample-config startup-log smoke test none
T-002 Data & auth foundation: SQLite schema/migrations for users + sessions, bcrypt password hashing, seed admin boss@zecevic-ninja.com / Start1234! with must_change_password=true on first startup, server-side session-cookie middleware (HTTP-only/Secure/SameSite, sliding expiry), login/logout routes, forced password-change gate that blocks every other route until the password is changed done Unauthenticated request to any non-login route (incl. file listing, download, stream, admin) returns redirect/401, never content; login with seed credentials succeeds and is immediately forced to the change-password screen and cannot reach any other page until changed; new password must differ from the temporary one; sessions persist across process restart via SQLite; unit tests cover auth middleware, forced-change gate, and password hashing PASS: auth storage/bcrypt/persistence/sliding-session and HTTP login/logout/forced-change/protected-route tests; go fmt ./..., go vet ./..., go test ./... in golang:1.24; Docker image build and named-volume startup smoke test none
T-003 Folder browsing UI: server-rendered root listing page, directory navigation with breadcrumbs, strict path confinement inside each configured root (block .. traversal and symlink escapes), light/dark theme toggle, minimal vanilla JS/CSS (no SPA framework) done Authenticated user sees configured roots, can enter/exit subfolders via breadcrumbs; any crafted path that would resolve outside a root's filesystem boundary is rejected (test with ../ and a symlink pointing outside the root); theme toggle switches light/dark and persists per session/browser; README.md documents the browsing UI behavior PASS: confined directory listing, traversal/symlink-escape rejection, authenticated root/folder/breadcrumb rendering, theme-local-storage markup; go fmt ./..., go vet ./..., go test ./... in golang:1.24 none
T-004 Download & video streaming: raw-byte download endpoint with correct Content-Type/Content-Disposition, full HTTP Range support for video files (seek/partial content/resume) with zero transcoding anywhere in the request path done Downloading any file returns identical bytes to the source file (checksum match); a Range request against a video file returns 206 Partial Content with the correct byte range and headers; no encoding/thumbnailing/transcoding code path exists; README.md documents the reverse-proxy Range-header-passthrough requirement PASS: root-confined regular-file opens; authenticated byte-identical attachment download; video 206 Range response; unauthenticated delivery gate; go fmt ./..., go vet ./..., go test ./... in golang:1.24 none
T-005 Admin user management: admin-only screens to list users, create a user (temporary password, must_change_password=true), reset a user's password, disable/delete a user; role-based route protection (403 for authenticated non-admins, not a redirect that leaks page existence) done Non-admin authenticated user gets 403 on all admin routes; admin can create a user who is then forced through the change-password gate on first login; admin can reset/disable a user; README.md documents the admin user-management flow PASS: admin lifecycle/session-invalidation and HTTP role-protection/temporary-password tests; go fmt ./..., go vet ./..., go test ./... in golang:1.24; E2E not configured none
T-006 Docker packaging & deployment docs: finalize multi-stage Dockerfile (small image, no build tools in final image), finalize docker-compose example with volume mounts + root config, complete README.md (build/run, root config format, first-login/admin credential flow, forced password change, reverse-proxy TLS + Range passthrough requirement) done docker build produces a working image; docker run with a sample volume mount and root config serves the login page only until authenticated, per Priority 1; README.md is complete enough for a new operator to deploy without reading source code PASS: Compose configuration validation; production image build/run, non-root runtime, and unauthenticated login boundary smoke test; go fmt ./..., go vet ./..., go test ./... in golang:1.24 none
T-007 Local-testing insecure-cookie opt-in: add an off-by-default env var (e.g. WEB_FILE_BROWSER_INSECURE_COOKIES) that, when explicitly enabled, omits the Secure attribute from the session cookie so login works over plain http:// (non-TLS, non-localhost-only origins) for local development; default behavior unchanged; no other session/auth behavior (HttpOnly, SameSite, expiry, forced password change) may be weakened; README.md gets a new "Local development over HTTP" section that explicitly warns this must never be enabled on a real/production/exposed deployment done With the var unset, session cookie still has Secure set and behavior is unchanged from T-002/T-005; with the var explicitly enabled, login over plain http:// succeeds (no redirect loop back to /login), the cookie has Secure unset, and all other cookie/session attributes and the forced-password-change gate are unchanged; README.md documents local-only Docker Compose and Docker Run setup with an explicit warning PASS: default-secure and plain-HTTP cookie-jar login/forced-change tests; Compose default/opt-in configuration validation; go fmt ./..., go vet ./..., go test ./... in golang:1.24; deployment E2E passed none
T-008 Bug fix (regression against shipped T-004): isVideoFile and the delivered Content-Type currently rely on mime.TypeByExtension, which resolves to nothing for .mp4/.mkv/etc. inside the actual Alpine-based production image (no OS MIME database present, no video entries in Go's built-in fallback table) — verified by inspecting alpine:3.21 directly. Replace with an app-internal extension → MIME-type table (.mp4, .m4v, .mov, .webm, .mkv, .avi, .mpg/.mpeg, .wmv, .flv at minimum) used consistently by both the "stream" link visibility check and the file-delivery Content-Type header, independent of any OS/container MIME database. README.md documents the supported video extensions and the .mkv-in-browser playback caveat (download always works; native in-browser streaming of the MKV container is browser-dependent, not guaranteed, and no transcoding is performed per the project's no-encoding requirement) ready_for_implement Inside the actual production Docker image (not the Go build image): requesting an .mp4 returns Content-Type: video/mp4 and the folder listing shows a "stream" link for it; requesting an .mkv returns the correct Matroska Content-Type and a "stream" link; a Range request against the .mp4 still returns 206 Partial Content with correct byte range; unit tests cover the new extension table directly (no dependency on host/OS MIME data) so the bug can't silently regress; README.md lists supported video extensions and the .mkv browser-support caveat n/a implement