# Gantt Board Task and sprint board built with Next.js + Zustand and Supabase-backed API persistence. ## Current Product Behavior ### Feb 20, 2026 updates - Added task attachments with Supabase persistence. - Added URL-based task detail pages (`/tasks/{taskId}`) so tasks can be opened/shared by link. - Replaced flat notes/comments with threaded comments. - Added unlimited nested replies (reply to comment, reply to reply, no depth limit). - Updated UI wording from "notes" to "comments". - Improved attachment opening/rendering by coercing MIME types (including `.md` as text) and using blob URLs for reliable in-browser viewing. - Added lightweight collaborator identity tracking for task/comment authorship. ### Feb 21, 2026 updates - Stabilized auth and settings flows with Supabase Auth credentials. - Login/password validation now uses Supabase Auth credentials. - Reset password flow no longer depends on `public.users.password_hash`. - Settings API response handling was hardened to avoid client script errors. - Avatar preset key collision warning in settings was fixed. ### Feb 22, 2026 updates - Fixed sprint date timezone drift (for example `2026-02-22` rendering as `2/21` in US time zones). - Standardized sprint date parsing across Kanban, Backlog, Sprint Board, Archive, and task detail sprint pickers. - `POST /api/sprints` and `PATCH /api/sprints` now normalize `startDate`/`endDate` to `YYYY-MM-DD` before writing to Supabase. ### Feb 23, 2026 updates - Removed non-live fallback data paths from the task store; board data now comes from Supabase-backed APIs only. - Removed legacy schema expectations from API code and docs (`legacy_id`, `meta` dependency, non-existent task columns). - Task detail now includes explicit Project + Sprint selection; sprint selection no longer rewrites task `projectId`. - API validation now accepts UUID-shaped IDs used by existing data and returns clearer error payloads for failed writes. ### Feb 24, 2026 updates - Standardized CLI tools to API passthrough mode only (no direct DB logic in scripts). - Consolidated shared CLI transport into `scripts/lib/api_client.sh`. - Added refactor safety tests: - sprint selection unit tests - mocked CLI API-contract tests across task/project/sprint/auth/debug command paths ### Feb 25, 2026 updates - Added a dedicated `/sprints` page (previously missing, caused route 404). - Added sprint management UI on `/sprints` to view all sprints and perform create/edit/delete actions. - Added a dedicated `/tasks` list page with URL-based filtering and scope controls. - Removed sprint-to-project coupling across app/API/CLI. Tasks remain project-scoped; sprints are now global. - Added DB migration script to drop `sprints.project_id`: `supabase/remove_sprint_project_id.sql`. ### Sprint date semantics (important) - Sprint dates are treated as local calendar-day boundaries: - `startDate` means local `12:00:00 AM` of that date. - `endDate` means local `11:59:59.999 PM` of that date. - Supabase stores sprint dates as SQL `DATE` (`YYYY-MM-DD`) in `sprints.start_date` and `sprints.end_date`. - API contract for `/api/sprints`: - Accepts date strings with a `YYYY-MM-DD` prefix (`YYYY-MM-DD` or ISO timestamp). - Normalizes and persists only the date part (`YYYY-MM-DD`). - `PATCH` returns `400` for invalid `startDate`/`endDate` format. - Example request payloads: - `POST /api/sprints` - `{ "name": "Sprint 1", "startDate": "2026-02-16", "endDate": "2026-02-22", "status": "active" }` - `PATCH /api/sprints` - `{ "id": "", "startDate": "2026-02-16T00:00:00.000Z", "endDate": "2026-02-22T23:59:59.999Z" }` - persisted as `start_date = '2026-02-16'`, `end_date = '2026-02-22'` - Do not use `new Date("YYYY-MM-DD")` for sprint display logic. Use shared helpers: - `parseSprintStart(...)` - `parseSprintEnd(...)` - `toLocalDateInputValue(...)` ### Data model and status rules - Tasks use labels (`tags: string[]`) and can have multiple labels. - Tasks support attachments (`attachments: TaskAttachment[]`). - Tasks persist identity references via `createdById`, `updatedById`, and `assigneeId`. - Display fields (`createdByName`, `updatedByName`, `assigneeName`, avatar/email) are resolved from `users` data in API/UI, not stored as separate task table columns. - There is no active `backlog` status in workflow logic. - A task is considered in Backlog when `sprintId` is empty. - Current status values: - `open` - `todo` - `blocked` - `in-progress` - `review` - `validate` - `archived` - `canceled` - `done` - New tasks default to `status: open`. ### Authentication and sessions - Added account-based authentication with: - `POST /api/auth/register` - `POST /api/auth/login` - `POST /api/auth/logout` - `GET /api/auth/session` - Added a dedicated login/register screen at `/login`. - Added account settings at `/settings` for authenticated users. - Main board (`/`) and task detail pages (`/tasks/{taskId}`) require an authenticated session. - Main board and task detail headers include quick access to Settings and Logout. - API routes now enforce auth on task read/write/delete (`/api/tasks` returns `401` when unauthenticated). - Added `PATCH /api/auth/account` to update profile and password for the current user. - Session cookie: `gantt_session` (HTTP-only, same-site lax, secure in production). - Optional machine-to-machine auth for API routes: - Set `GANTT_MACHINE_TOKEN` in server env. - Send either `Authorization: Bearer ` or `x-gantt-machine-token: `. - Optional identity fields: `GANTT_MACHINE_USER_ID`, `GANTT_MACHINE_USER_NAME`, `GANTT_MACHINE_USER_EMAIL`. - Added `Remember me` in auth forms: - Checked: persistent 30-day cookie/session. - Unchecked: browser-session cookie (clears on browser close), with server-side short-session expiry. - Forgot-password currently uses a dev reset-link flow unless an external email provider is integrated. - Task/comment authorship now uses authenticated user identity. - Added `GET /api/auth/users` so task forms can load assignable users. - User records now include optional `avatarUrl` profile photos. ### Task assignment - You can assign or unassign tasks in: - New Task modal - Task detail popup on board - URL task detail page (`/tasks/{taskId}`) - New tasks default to the current signed-in user as assignee. - Kanban and Backlog cards show a visible assignee avatar/initial pill. - When someone else updates status (for example closes a task), updater fields still track who made that change. ### Profile photos and account settings - Account Settings (`/settings`) has separate save actions: - `Save Profile` for name/email/photo - `Update Password` for password-only changes - Profile photos can be uploaded/removed in settings. - Users without uploaded photos get a generated default avatar (unique by user seed). - Settings also provides multiple preset avatar choices. - Profile photos appear in: - Board/task header identity chips - Assignee pills on Kanban and Backlog - Threaded comment author avatars - Creator/updater identity rows on task detail views - Avatar updates persist in Supabase profile tables and propagate through session/user APIs. ### Labels - Labels are independent of project/sprint selection. - You can add/remove labels inline in: - New Task modal - Task Detail page - Label entry supports: - Enter/comma to add - Existing-label suggestions - Quick-add chips - Case-insensitive de-duplication ### Task detail pages - Clicking a task from Kanban or Backlog opens a dedicated route: - `/tasks/{taskId}` - Task detail is no longer popup-only behavior. - Each task now has a shareable deep link. - Task detail includes explicit Project and Sprint dropdowns. ### Task list route - Added a dedicated task list route at `/tasks`. - Supported query params: - `scope=active-sprint|all` (default: `all`) - `status=` (for example `in-progress,review`) - `priority=` (for example `urgent,high`) - Unknown status/priority tokens are ignored. - Filtering is client-side against the synced task dataset. - Results are sorted by `updatedAt` descending. ### Attachments - Task detail page supports adding multiple attachments per task. - Attachments are stored with each task in Supabase and survive refresh/restart. - Attachment UI supports: - Upload multiple files - Open/view file - Markdown (`.md`) preview rendering in browser tab - Text/code preview for common file types including iOS project/code files (`.swift`, `.plist`, `.pbxproj`, `.storyboard`, `.xib`, `.xcconfig`, `.entitlements`) - Syntax-highlighted source rendering (highlight.js) with copy-source action - CSV table preview and sandboxed HTML preview with source view - Download file - Remove attachment ### Threaded comments - Comments are now threaded, not flat. - You can: - Add top-level comments - Reply to any comment - Reply to replies recursively (unlimited depth) - Delete any comment or reply from the thread - Thread data is persisted in Supabase through the existing `/api/tasks` sync flow. Current persisted comment shape: ```json { "id": "string", "text": "string", "createdAt": "2026-02-23T19:00:00.000Z", "commentAuthorId": "user-uuid-or-assistant", "replies": [] } ``` - `commentAuthorId` is required. - Legacy `author` objects are not supported by the UI parser. ### Backlog drag and drop Backlog view supports moving tasks between: - Current sprint - Other sprint sections - Backlog Status behavior on drop: - Drop into any sprint section: `status -> open` - Drop into backlog section: `status -> open` - `sprintId` is set/cleared based on destination Changes persist through store sync to Supabase. ### Kanban drag and drop Kanban supports drag by visible left handle on each task card. Columns: - `To Do` contains statuses: `open`, `todo` - `In Progress` contains statuses: `blocked`, `in-progress`, `review`, `validate` - `Done` contains statuses: `archived`, `canceled`, `done` Drop behavior: - Drop on column body: applies that column's default status - `To Do` -> `open` - `In Progress` -> `in-progress` - `Done` -> `done` - Drop on status chip target: applies exact status - Drop on a task: adopts that task's exact status During drag, the active target column shows expanded status drop zones for clarity. ### Layout - Left sidebar cards (Current Sprint and Labels quick view) were removed. - Main board now uses full width for Kanban/Backlog views. ## Persistence - Client state is managed with Zustand. - Persistence is handled through Supabase-backed API routes: - `/api/tasks` - `/api/projects` - `/api/sprints` - No local task/project/sprint fallback dataset is used. - API reads/writes Supabase tables only. ## Run locally ```bash npm install npm run dev ``` Open `http://localhost:3000`. Task URLs follow `http://localhost:3000/tasks/{taskId}`. ## Scripts ```bash npm run dev npm run build npm run start npm run lint ``` ## CLI Tools for AI Access Located in `scripts/` directory. These allow programmatic access without browser automation. ```bash # Full wrapper ./scripts/gantt.sh task list open ./scripts/gantt.sh task create "Fix login issue" todo high p1 ./scripts/gantt.sh sprint close ./scripts/gantt.sh auth session # Focused helpers ./scripts/task.sh list --json ./scripts/project.sh list --json ./scripts/sprint.sh list --active --json ./scripts/attach-file.sh ./scripts/view-attachment.sh [index] ``` **Architecture:** CLI is API passthrough only. Business logic lives in API/server code. **Docs:** - `scripts/README.md` (command details and env vars) - `docs/API_CLI_PASSTHROUGH_PATTERN.md` (refactor/architecture standard) **Refactor test suite:** ```bash npm run test:refactor ``` ## Notes - You may see a Next.js warning about multiple lockfiles and inferred workspace root. This is non-blocking for local dev.