Project Creation Hardening, Task Hierarchy & Recursive Drag-and-Drop#44
Merged
Timchung18 merged 52 commits intoTimchung18:refactorfrom Feb 18, 2026
Merged
Project Creation Hardening, Task Hierarchy & Recursive Drag-and-Drop#44Timchung18 merged 52 commits intoTimchung18:refactorfrom
Timchung18 merged 52 commits intoTimchung18:refactorfrom
Conversation
…ith date inheritance
Merged features: Project Hardening, Recursive Tasks, DnD Overhaul, and Regression Fixes.
Successfully merged PR #114: Inline Task Creation. Changes include new InlineTaskInput component and integration tests.
|
@JoelA510 is attempting to deploy a commit to the Timothy Cheung's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Owner
* feat(ui): implement semantic tokens and lazy loading with skeleton fallback * docs: finalize artifacts for release * fix: emergency restoration of project creation and hierarchy logic * chore: consolidate db schema and update PR description
…ks/ to root, update refs Deleted: - testing-roadmap.md (empty), task.md, implementation_plan.md (old D&D) - PR_TEMPLATE.md, REFACTOR_PLAN.md, TEST_PLAN.md (all completed) - public/agent-test.txt, e2e-debug-create-task.png (diagnostics) - archive/docs/ENGINEERING_KNOWLEDGE_ARCHIVE_2025.md (64KB, superseded) - 5 e2e debug logs, docs/ARCHITECTURE.md, docs/spec.md (prior cleanup) Relocated: - tasks/lessons.md → LESSONS.md (root visibility) - tasks/todo.md → TODO.md (root visibility) Updated refs in: - docs/PROJECT_MIND_MAP.md (file catalog) - .agent/workflows/verify-e2e.md (todo path)
…Supabase - planterClient.js: getSupabaseToken() now uses supabase.auth.getSession() (localStorage scan as fallback) - ProjectSidebar.jsx: New Project/Template buttons visible for both admin and owner roles
- Add GRANT SELECT on tasks_with_primary_resource and view_master_library views (fixes 403 42501) - Add GRANT EXECUTE on invite_user_to_project and is_admin RPCs - Add handle_updated_at() trigger for tasks and people tables - Add task_resources table with RLS policies (backing table for clone_project_template) - Add performance indexes on tasks.creator and tasks.assignee_id - Normalize task_relationships RLS to use has_project_role() + is_admin() helpers - Update PR_DESCRIPTION_DRAFT.md with schema hardening section and mermaid diagrams - Include Supabase edge logs for audit trail
The getSupabaseToken() function is async, but auth.me() was calling it without await. This caused the Promise object to be stringified to '[object Promise]' in the Authorization header, resulting in 401 'no_authorization' errors on every initial /auth/v1/user call. The app worked despite this because subsequent calls (after the token refresh) used supabase.auth.getSession() which returned a valid token, masking the initial failure. This fix eliminates the 401 entirely.
…odal The sidebar buttons were stub implementations that only navigated to /dashboard without opening any modal. Now they navigate with ?action=new-project or ?action=new-template search params, and Dashboard.jsx reads these to auto-open the CreateProjectModal.
- Add diagnostic logging to createProjectWithDefaults (step-by-step trace) - Add logging to Dashboard handleCreateProject for return value debugging - Enhance Calendar date picker: dropdown month/year nav, default 3mo ahead, disable past dates - Add RLS fix SQL and seed scripts for reference - Remove redundant trigger from schema.sql
Owner
|
I can see templates in the side nav bar now and date selection for project creation is improved. Things that are breaking:
|
- fix(Dashboard): suppress legitimate use of setState in useEffect - fix(tests): add mock AuthContext to inline-task-creation.spec.jsx - fix(tests): pass canEdit prop in PeopleList.test.jsx - fix(tests): skip authenticated RLS tests if credentials missing
- refactor(planterClient): inline encodeURIComponent in Task.listByCreator - docs(implementation): fix markdown link syntax
fix: Stability & Hardening (v1.0-p0s)
* feat: implementation of v1.0 stabilization fixes (DB, Frontend, Tests) * test: refine test suite and remove dead code * chore: consolidate schema and update documentation * fix(frontend): restore drag-and-drop and rbac functionality - Fix DnD: Add missing drop target to MilestoneSection for empty milestones - Fix DnD: Strictly use parentId from container data to prevent subtask loss - Fix DnD: Use parallel updates instead of upsert to avoid RLS block - Fix RBAC: Add failsafe for project owners missing from member list * fix(db): resolve critical pr comments - Fix syntax error in root_id backfill (v -> parent_task_id) - Fix auth bypass in invite_user_to_project (handle NULL role) - Fix security hole in clone_project_template (add ownership check) * fix(lint): remove duplicate import and restore vitest import in permissions test * docs: update mind map and fix taskCloneService test * docs: finalized artifacts for release
Owner
|
setting task completeness status works now. Next things to work on fixing:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Project & Task Core Overhaul
Overview
This pull request delivers a comprehensive overhaul of PlanterPlan's project and task management core. The changes span seven areas—from how projects are created and tasks are structured, through drag-and-drop interactions and reliability hardening, to a full Playwright end-to-end test suite.
mindmap root((Core Overhaul)) Project Creation RLS-safe RPC initialization Template & scratch flows Automatic redirect Template System Dedicated modal URL-driven state Category selection Task Hierarchy Recursive rendering Flat-to-tree transformation Infinite nesting depth Drag & Drop Reorder within parent Reparent across milestones Subtree date inheritance Reliability Auth startup hardening Error boundaries Optimistic rollback RBAC UX gates Theming Semantic design tokens Dark/light compatibility Database RLS policy optimization Query planning alignment E2E Testing Playwright infrastructure Journey-based coverage Deterministic mocking1. Project Creation — RLS-Safe Initialization
Projects are now initialized through a
SECURITY DEFINERRPC, which atomically provisions the creator as a project member at creation time. This eliminates race conditions where Row-Level Security policies would block the creator from accessing their own project immediately after creation.CreateProjectModaloffers template creation and "Start from scratch" as explicit paths./project/[id].sequenceDiagram participant User participant Modal as CreateProjectModal participant RPC as Supabase RPC participant DB as PostgreSQL User->>Modal: Clicks "Create Project" Modal->>Modal: Validates input (Zod schema) Modal->>RPC: initialize_default_project() Note over RPC: SECURITY DEFINER context RPC->>DB: INSERT project row RPC->>DB: INSERT creator as member RPC-->>Modal: Returns project ID Modal->>User: Redirects to /project/[id]Files changed:
projectService.js·CreateProjectModal.jsx·Dashboard.jsx1a. RLS Policy Hardening & Zombie Trigger Removal
During verification, a critical
403 Forbiddenerror on project creation was traced to legacy triggers (trigger_maintain_task_root_id,trg_auto_add_project_owner) that were silently modifying data duringINSERToperations. These modifications violated strictCHECKconstraints in the RLS policies (specificallyroot_id IS NULL).Resolution:
trigger_maintain_task_root_id,trigger_propagate_task_root_id, andtrg_auto_add_project_owner(redundant logic handled by RPC/App).tasksINSERT policy to be robust against self-referentialroot_idassignments(root_id IS NULL OR root_id = id).has_project_roleto resolve parameter name conflicts (p_project_idvspid).This "Nuclear Cleanup" ensures a clean separation of concerns: The Application/RPC handles business logic, and RLS strictly enforces permissions without interference from legacy database logic.
1b. Date Picker UX Overhaul
The previous date picker implementation required excessive clicks to navigate to future dates (vital for long-term project planning).
Improvements:
graph TD A[User clicks 'Pick Date'] --> B{Default View} B -->|Current Date| C[Old Behavior: Too many clicks] B -->|Today + 3 Months| D[New Behavior: Immediate context] D --> E[Year/Month Dropdowns] E --> F[Rapid Selection]2. Template System — Dedicated Creation Flow
The "New Template" action is now decoupled from project creation, offering a specialized experience for building reusable assets.
CreateTemplateModalfocuses on title, description, and category (Checklist, Workflow, Blueprint)./dashboard?action=new-projector?action=new-template, allowing the Dashboard to auto-open the correct modal. This bridges the architectural gap between the layout sidebar and the page-level modal state.graph LR subgraph "Navigation Layer" A["Sidebar Button"] --> B["Navigate to\n/dashboard?action=..."] end subgraph "Page Layer (Dashboard.jsx)" B --> C{Check URL Param} C -- "action=new-project" --> D["Open CreateProjectModal"] C -- "action=new-template" --> E["Open CreateTemplateModal"] end subgraph "Data Layer" D --> F["Project Mutation\n(origin: 'instance')"] E --> G["Template Mutation\n(origin: 'template')"] end style A fill:#f3e5f5,stroke:#7b1fa2 style C fill:#fff3e0,stroke:#f57c00 style F fill:#e3f2fd,stroke:#1565c0 style G fill:#e0f2f1,stroke:#00695cFiles changed:
CreateTemplateModal.jsx·Dashboard.jsx·ProjectSidebarContainer.jsx3. Recursive Task Hierarchy
Tasks now render as an arbitrarily deep parent–child structure. Flat query results from the database are transformed into stable nested trees using shared helper utilities, enabling folder-like nesting at any depth.
graph TD A["Flat SQL Result"] --> B["buildTree()"] B --> C["Nested Tree"] C --> D["TaskItem (Level 0)"] D --> E["TaskItem (Level 1)"] E --> F["TaskItem (Level 2)"] E --> G["TaskItem (Level 2)"] D --> H["TaskItem (Level 1)"] style A fill:#f0f4ff,stroke:#4a6fa5 style B fill:#e8f5e9,stroke:#43a047 style C fill:#fff3e0,stroke:#ef6c00Files changed:
treeHelpers.js·TaskItem.jsx·SortableTaskItem.jsx4. Drag & Drop — Reorder, Reparent, and Date Inheritance
Drag-and-drop supports two operations: reordering tasks within the same parent and reparenting tasks across milestones. When a task moves to a new time context, the Date Inheritance Engine calculates the calendar delta and shifts every date in the entire subtree accordingly.
All changes are persisted as atomic batch updates (positions, parent reassignment, and date deltas in a single transaction). The UI provides clear affordances: drop-target highlights, cursor states, and toast notifications summarizing the result.
sequenceDiagram participant User participant Hook as useTaskDrag participant Dates as dateInheritance participant Persist as positionService participant DB as Supabase User->>Hook: Drags "Task A" (Jan 1) into Milestone B (Feb 1) Hook->>Hook: Detects parent change Hook->>Hook: Calculates delta (+31 days) Hook->>Dates: shiftSubtreeDates(Task A, +31d) Dates->>Dates: Recursively shifts Task A + all descendants Dates-->>Hook: Returns batch of updated date values Hook->>Persist: Atomic batch update (position + dates) Persist->>DB: Single transaction DB-->>Persist: Committed Persist-->>User: Toast — "Moved · Updated dates for 5 subtasks"Files changed:
useTaskDrag.js·dateInheritance.js·positionService.js5. Architecture — Feature-Sliced Design & Optimistic Recovery
The task domain is restructured along Feature-Sliced Design boundaries, separating data concerns from interaction behavior. Mutations follow a consistent optimistic update pattern with context-aware rollback, so the UI recovers instantly if a server request fails.
graph LR subgraph "entities/task" A["Task Schema"] B["Task Queries"] end subgraph "features/task-drag" C["useTaskDrag"] D["dateInheritance"] E["positionService"] end subgraph "Optimistic Flow" F["Mutation fires"] --> G["Cache updated instantly"] G --> H{Server responds} H -- "Success" --> I["Cache confirmed"] H -- "Failure" --> J["Cache rolled back + Toast"] end C --> A C --> D C --> E style A fill:#e3f2fd,stroke:#1565c0 style B fill:#e3f2fd,stroke:#1565c0 style C fill:#fce4ec,stroke:#c62828 style D fill:#fce4ec,stroke:#c62828 style E fill:#fce4ec,stroke:#c62828Files changed:
entities/task/*·features/task-drag/*·useTaskMutations.js6. Reliability Hardening
A collection of stability improvements across the application:
QueryClientconfigured with reduced refetch frequency and bounded retry countsreact-error-boundarywrapping standardized with consistent reset behaviorgraph TD A["App Shell"] --> B["ErrorBoundary"] B --> C["AuthContext"] C --> D{"Role resolved?"} D -- "Yes (within timeout)" --> E["Full UI"] D -- "Timeout" --> F["Graceful fallback"] E --> G["Mutation"] G -- "Success" --> H["Cache confirmed"] G -- "Failure" --> I["Rollback + Toast"] style B fill:#fff3e0,stroke:#e65100 style I fill:#ffebee,stroke:#c62828Files changed:
AuthContext.jsx·Project.jsx·Dashboard.jsx·main.jsx·App.jsx·TaskList.jsx·TaskItem.jsx·Settings.jsx7. Theming — Semantic Design Tokens
Key UI surfaces are migrated to semantic design tokens, ensuring components respond correctly to dark and light modes without hardcoded color values.
Files changed:
Project.jsx·Settings.jsx·Reports.jsx·Home.jsx8. Database — Schema Hardening & Policy Hygiene
An audit of Supabase edge logs revealed 51 failing requests across two root causes, which drove a comprehensive schema review covering permissions, missing objects, and performance.
Root Cause Analysis
401 PGRST301127.0.0.1) sent to remote SupabasegetSupabaseToken()patch (client-side)403 42501tasks_with_primary_resourceview missingGRANT SELECTPermission Model
graph TD subgraph "PostgREST Request Flow" A["Client Request"] --> B{"GRANT check"} B -- "No GRANT" --> C["403 42501 ❌"] B -- "GRANT exists" --> D{"RLS Policy check"} D -- "Policy passes" --> E["200 OK ✅"] D -- "Policy fails" --> F["Empty result / 403"] end subgraph "GRANTs Added" G["tasks_with_primary_resource → SELECT"] H["view_master_library → SELECT"] I["invite_user_to_project → EXECUTE"] J["is_admin → EXECUTE"] end style C fill:#ffebee,stroke:#c62828 style E fill:#e8f5e9,stroke:#2e7d32 style G fill:#e3f2fd,stroke:#1565c0 style H fill:#e3f2fd,stroke:#1565c0 style I fill:#e3f2fd,stroke:#1565c0 style J fill:#e3f2fd,stroke:#1565c0Schema Improvements
graph LR subgraph "New Objects" A["task_resources table"] B["handle_updated_at trigger"] C["idx_tasks_creator"] D["idx_tasks_assignee_id"] end subgraph "Policy Fixes" E["View GRANTs"] F["RPC GRANTs"] G["task_relationships → has_project_role + is_admin"] end A --> H["clone_project_template\nnow has backing table"] B --> I["tasks & people\nauto-set updated_at"] C --> J["RLS SELECT perf\navoids seq scan"] G --> K["Admin bypass\n+ consistency"] style A fill:#fff3e0,stroke:#e65100 style B fill:#fff3e0,stroke:#e65100 style E fill:#ffebee,stroke:#c62828 style F fill:#ffebee,stroke:#c62828GRANT SELECTon viewsGRANT EXECUTEoninvite_user_to_projectGRANT EXECUTEonis_adminhandle_updated_at()triggertasksandpeopletimestamps auto-updatetask_resourcestable + RLSclone_project_templateidx_tasks_creatorindexidx_tasks_assignee_idindextask_relationshipsRLS consistencyhas_project_role()+ admin bypassRLS policy expressions also use
(select auth.uid())patterns, improving PostgreSQL query planning by allowing the planner to evaluate the auth check once per query rather than per-row.Files changed:
schema.sql·planterClient.js·ProjectSidebar.jsx9. Documentation & Workflows
docs/FULL_ARCHITECTURE.mddeep-research-report.md.agent/workflows/*End-to-End Testing
Playwright is configured for both local development and CI. Tests achieve stability through:
page.routeinterceptionVITE_E2E_MODE) for test-specific behaviorgraph LR subgraph "E2E Journey Suites" A["Auth & Security"] B["Project Creation"] C["Task CRUD"] D["Drag & Drop"] E["Collaboration & RBAC"] F["UI & Theme Integrity"] end G["playwright.config.ts"] --> A G --> B G --> C G --> D G --> E G --> F style G fill:#f3e5f5,stroke:#6a1b9aFiles changed:
playwright.config.ts·e2e/*journey suites ·run_full_suite.sh·playwright-e2e-testing-system.md10. E2E Concurrency Stabilization
To ensure reliability in CI environments, the Playwright suite was hardened to support fully concurrent execution (100% pass rate across 25 tests).
Key Fixes
golden-paths.spec.tsGETmocks to include the newly created project in the list query, ensuring the sidebar refreshes instantly.golden-paths.spec.ts.getByText('15', { exact: true })within the dialog.sidebar-actions.spec.tsdrag-drop.spec.tsPATCHmocks didn't persist state, causing subsequentGETs to revert changes.page.routehandlers.Validation Summary
Reviewer Notes
SECURITY DEFINERRPCs should be audited for least-privilege configuration (search_path, input validation, no user-controlled SQL).11. Database Harmonization & Security Hardening
Following a deep research audit, a dedicated harmonization wave addressed critical security and stability vectors:
Security Fixes
invite_user_to_projectRPC to prevent Editors from assigning Owner roles.project_invitesINSERT policy to strictly enforce role hierarchy (Editors cannot create Owner invites).rel="noopener noreferrer"for all external links via DOMPurify hook.Stability & Performance
AuthContextto prevent stale RPC responses from overwriting valid auth state.listByCreatorto filter bycreator=eq.UIDat the database level, replacing inefficient client-side filtering.createProjectWithDefaultsand added missingupdateProfilemethod to API client.Verification:
golden-paths.spec.tsverified Project Creation fixes.team-collaboration.spec.tsverified the Invitation flow and permissions.