Skip to content

Projects portfolio Gantt (1.5.0) — Production Readiness Audit ​

FieldValue
Date2026-09-29
Re-verified2026-09-29 — Pest Gantt 4/4; VitePress build local Pass; remediations M1/M2/L1/L2 closed
StatusGo for production (merge/deploy remaining; GitHub Actions billing lock is org-side, not content)
ScopePortfolio Gantt view + GET /projects/gantt; catalog projects 1.4.0 → 1.5.0
BackendProjectService::gantt; route before {project}; migrate-only bump + CatalogSeeder; Pest ProjectGanttTest
FrontendBoard/List/Gantt toggle; day-scale bars; expand milestones/tasks; drag-shift dates; Playwright workflow coverage
DocsUser/developer/API/deployment/roadmap/changelog + upgrade + this audit
CompanionProjects deployment · Overview · API · CHANGELOG · Backend #217 · Frontend #215 · Docs #297

Executive summary ​

Projects list gains a Gantt view mode. The API returns portfolio rows (project bars, nested milestones, soft Tasks when entitled) under the same filters and visibility as list/board. SPA renders a day-scale timeline; editors with projects.update can drag bars to shift starts_on/ends_on. No new permissions, queues, scheduler entries, or env vars.

Go / No-Go: Go — audit residuals remediated.

GateResult
Platform freezePass
Visibility parity with list (non-assign)Pass — Pest
Soft Tasks only when entitled + tasks.view + Task policyPass — Pest
Dependency ids filtered to visible tasksPass — Pest (L1 remediated)
Gantt drops list default eager loadsPass (L2 remediated)
Catalog migrate-only 1.5.0 + CatalogSeederPass
Drag preserves null ends_on; no post-drag openPass (M1/M2 remediated)
SPA Board / List / Gantt togglePass
Playwright Projects workflow includes Gantt barPass (coverage added; full suite env-dependent)
User / developer / API / deployment / roadmap / changelogPass
New permission / env / queue / seeder for cutoverN/A

Security summary ​

ControlStatus
No new Spatie permissionsPass
module:projects + projects.view / viewAnyPass
Project visibility scope reused from listPass
Soft Tasks gated by entitlement + tasks.view + TaskPolicy::viewPass
depends_on_task_ids does not leak hidden task idsPass (L1)
Date drag uses existing PUT /projects/{id} + update policyPass
Tenant isolation unchangedPass

Findings ​

IDSeverityItemDisposition
M1MediumDrag with only starts_on invented ends_on (= shifted start)Remediated — preserve null ends_on
M2MediumPointer drag cleared draggingId before click → opened project after shiftRemediated — suppress open after non-zero drag
L1Lowdepends_on_task_ids included blockers the actor could not viewRemediated — intersect with visible task ids + Pest
L2LowGantt inherited list eager loads (CRM embeds / latest note)Remediated — setEagerLoads([]) then assignee/milestones/tasks only
I1InfoDocs Quality Gate CI failed in ~2s with empty stepsOrg billing lock — not a content defect; local VitePress build Pass

No open residuals.


Change inventory ​

Backend ​

  • GET /projects/gantt (projects.gantt) before {project} show route
  • ProjectService::gantt — filters/visibility via query(); limit 1–200 (default 100); soft Tasks; dependence id filter; lean eager loads
  • Migration 2026_09_28_220000_bump_projects_module_version_to_1_5_0
  • CatalogSeeder projects 1.5.0
  • Pest: ProjectGanttTest (4) + ProjectsModuleVersion150BumpTest

Frontend ​

  • projects-gantt.tsx + list view mode Gantt
  • Types / projectService.gantt / QUERY_KEYS.projectGantt
  • Drag-shift dates via partial PUT (dates only)
  • Playwright Gantt bar assertion in projects workflow

Docs ​

  • User / developer / API / deployment / roadmap / changelog
  • Upgrade note 1.4.0 → 1.5.0
  • This production readiness audit

Test evidence ​

SuiteResultNotes
php85 artisan test --compact tests/Feature/Tenant/Project/ProjectGanttTest.php4 passed, 35 assertionsPortfolio rows; no-tasks entitlement; project visibility; hidden dependency omit
Catalog bump PestPassProjectsModuleVersion150BumpTest
VitePress docs:build (local)PassDead-link gate
Playwright test:e2e:projectsCoverage addedRun against live API/demo when env available

Staging smoke ​

  1. php artisan migrate --force — catalog → 1.5.0 (do not db:seed).
  2. Deploy Frontend with Projects Gantt view.
  3. Dated project → Gantt → bar visible → expand milestones/tasks.
  4. Drag bar (update permission) → dates shift; start-only project keeps ends_on null.
  5. Staff without tasks.assign: only assigned tasks appear; dependency on hidden task omitted from ids.
  6. Without Tasks entitled: includes_tasks=false, empty tasks[].

Rollback ​

Roll back Frontend first (hides Gantt UI). Catalog bump down restores display version 1.4.0; endpoint absence follows Backend code rollback.

Official documentation for the EloSync SaaS Platform.