Changelog
What shipped in Foreman, in reverse chronological order.
2026-05-10
Phase 9 — Polish
- Custom
not-found.tsxand rooterror.tsxboundary (no more Next.js stack-trace pages in production). loading.tsxskeletons on the project board, task detail, and notifications inbox so cold loads have a frame instead of a flash of blank.- Signed-in users hitting
/now redirect straight to/projects. Logged-out home is a small "invite-only" lead-in.
Phase 8 — Notifications
notificationstable. RLS: users read/update/delete only their own; only the server (service role) inserts.notifyUser/notifyManyhelpers insrc/lib/notifications.tsinsert the in-app row and send a Resend email in parallel. Email failure doesn't break the action.createCommentnotifies the assignee + all prior commenters (excluding self).updateTasknotifies the new assignee wheneverassignee_idchanges (excluding self-assignment).- New
<NotificationBell />in the project layout,<UserRealtime />listens to inserts onnotificationsfor live unread-count updates. - New
/notificationspage: full inbox, mark read / mark all read / dismiss. - Email templates inline (text-only for now). React Email templates and
@mention-driven mentions land in a follow-up alongside TipTap.
Phase 7 — Attachments
- Supabase Storage bucket
task-attachments. Path convention:{project_id}/{task_id}/{uuid}-{filename}. - Storage RLS parses
project_idfrom the path and gates by project membership for read, by editor/admin role for upload/delete. - Metadata table
attachmentsmirrors object info; same RLS shape. - Task detail page shows the attachment list with image thumbnails for image MIME types and a generic file pill for everything else. Server-side signed URLs (1-hour TTL).
- Upload via a hidden
<input type="file">in<AttachmentList />. Direct browser-to-Storage upload, then metadata insert. If the metadata insert fails the storage object is rolled back.
Phase 6 — Subtasks
- One-level subtask UI on the task detail page: list with checkbox toggle, quick-add input, link to each subtask's own detail page.
createSubtaskserver action inherits parent's project + the project's first non-done status.toggleTaskDoneflips between the first non-done and first done status (per project).- Schema already supported subtasks via
parent_task_id; depth still capped at one via the existing trigger.
Phase 5 — Realtime
- Added
tasks,comments,activity,statuses,labels,task_labels,project_members,invitationsto thesupabase_realtimepublication. <ProjectRealtime />(mounted in the project layout) subscribes to project-scoped Postgres changes and triggersrouter.refresh(). RLS ensures contractors only receive events for projects they're in.<TaskRealtime />does the same for comments + activity scoped to a single task on the detail page.- Refreshes are debounced to one per 150ms so a burst of changes (e.g. drag-drop) doesn't stampede the server.
Phase 4 — Comments + activity log
- Schema:
commentsandactivitytables. - Activity is auto-logged via a Postgres trigger on
tasks(created, title_changed, status_changed, assignee_changed, priority_changed, due_date_changed). Clients can read but cannot insert directly — only the trigger writes. createComment,updateComment,deleteCommentserver actions.- New combined timeline on the task detail page: comments and activity events, ordered by time. Comment composer at the bottom, ⌘+Enter submits.
Phase 3b — Board drag-and-drop + inline task edit
- Board now drag-and-drop via
@dnd-kit/core+@dnd-kit/sortable. Drag a card within a column to reorder, drag across columns to change status. Optimistic UI viauseOptimistic; server reconciles on the next render. - Position math: fractional indexing — drop between two cards averages their positions, drop at top/bottom shifts by ±1024. No full-column re-shuffle on every move.
moveTask,updateTask,deleteTaskserver actions added.- Task detail page is now editable: Edit / Save / Cancel / Delete. Form covers title, description, status, assignee, priority, due date.
Phase 3 — Tasks core (read + create slice)
- Schema:
statuses,labels,tasks(with one-level subtask depth enforced),task_labels. - Default statuses (To-do / Doing / Review / Done) auto-seeded on every project create.
- Helper:
project_role(uuid)returns the caller's role in a project (admin / editor / viewer / null). - RLS policies — viewers read-only on tasks/task_labels, editors and admins can create/update/delete.
- Project shell:
layout.tsxprovides project name + tab nav (Board / List / Settings — Settings admin-only). Active tab highlighting viausePathname. - Board view (kanban, static — drag-and-drop ships in 3b). List view (sortable table). Task detail page.
- Server action:
createTaskwith fractional-position calculation (end-of-column on insert). - Invite/cancel/remove member flows now live inside the project shell rather than as standalone pages.
Phase 2 — Projects + invitations + RLS
- Schema:
projects,project_members,invitationswith RLS on each. - Helper:
is_project_member(uuid)— used everywhere RLS gates project access. accept_invitation(token)SQL function (SECURITY DEFINER) does the email-match check and inserts the membership atomically.- Admin can create projects, invite users by email, cancel pending invitations, and remove members.
- Pages:
/projects,/projects/new,/projects/[id],/projects/[id]/settings,/invite/[token]. - Resend wired for invitation emails (
foreman@hrefcreative.com, reply-tosupport@hrefcreative.com). Falls back to a manually-shareable URL if the email send fails. - Home page detects auth state and shows "Open Foreman" / "Account" when signed in.
Permanent local ports + Google OAuth wired
- Foreman dev server permanently on
3030(was using fallback3003because HQ holds3000). - Supabase moved off the CLI defaults onto a Foreman-specific block: API
54400, DB54402, Studio54403, Inbucket54404, Pooler54409, Analytics54407. Done insupabase/config.tomlso it's permanent acrosssupabase starts. - Google OAuth provider enabled in
supabase/config.tomlviaenv()substitutions. Credentials live in a gitignored.envat the project root.
Phase 1 — Auth + profiles
profilestable with auto-create trigger onauth.usersinsert (admin emails hardcoded for bootstrap).- RLS helpers:
is_admin(), plus self-select / self-update policies onprofiles. - Supabase clients for server (cookies-based) and browser, plus shared session-refresh proxy.
- Magic link + Google OAuth login flows via Server Actions.
- Pages:
/login,/account, plus/auth/callbackexchange route. - Proxy (formerly middleware in Next ≤15) gates everything except
/,/login,/auth/*,/docs/*.
Phase 0 — Foundation
- Project scaffold: Next.js 16 (App Router), Tailwind v4, shadcn/ui (neutral, Base UI primitives), Fumadocs at
/docs/*, Supabase CLI initialized. - Design doc committed at
docs/plans/2026-05-10-foreman-design.md. - HQ project + phase lists created (
G_XpbGT2J6Gx3J_3mXsT3underws-href). - GitHub repo published at github.com/amarasa/foreman (private).