A Symfony 8 REST API implementing the PERT/CPM critical path algorithm, demonstrated against real GitHub commit history.
Was previously a PM web-app, with the desire to use what I have learned to implement on my GitHub repos and finish my projects more efficiently.
This project implements the CPM (Critical Path Method) algorithm - topological sort, forward pass, backward pass, slack calculation, and critical path identification — and applies it to a GitHub repository's commit history as its input data.
Each commit becomes an activity. Each parent→child relationship becomes a dependency. Merge commits produce fan-in edges, so parallel development branches appear as parallel paths in the critical chain analysis.
The result: for any public GitHub repo, you can see which commits formed the longest elapsed-time thread (the critical chain), and which branches had buffer before they needed to merge.
CPM is a prospective planning tool — it needs estimated durations set before work begins. GitHub commit data is inherently retrospective. This project applies CPM to historical data, which produces a valid retrospective analysis but is not a PM planning tool. No GitHub data source (commits, issues, PRs) closes this gap without user-supplied duration estimates.
This mismatch was identified during development. The project was closed out as a working portfolio artifact rather than extended into something it couldn't be.
- PHP 8.4 — language runtime
- Symfony 8.0 — REST API framework, dependency injection, routing
- Doctrine ORM — entity mapping and migrations
- SQLite — local development database (
var/data.db) - Mermaid.js — critical chain diagram rendering in the demo
- GitHub REST API — commit history source
- PHP 8.4+
- Composer
git clone <repo-url>
cd ProjectManagement
composer install
php bin/console doctrine:migrations:migrate
php bin/console doctrine:fixtures:load
php -S localhost:8000 -t public public/index.phpVisit http://localhost:8000 — the demo page loads automatically.
GET /api/projects— list all imported projectsGET /api/projects/{id}— project name and idGET /api/projects/{id}/critical-path— ES, EF, LS, LF, slack, is_critical per activityGET /api/projects/{id}/network-diagram— nodes, edges, Mermaid string, project durationPOST /api/github/import— body{ "url": "https://github.com/{owner}/{repo}" }, returns{ "project_id": <int> }
- No pagination — only the most recent 100 commits are fetched per import
- Duration is elapsed hours — time between a commit and its most recent in-window parent, rounded to the nearest hour. Commits in the same session show
< 1h. This is elapsed time, not effort. - No URL normalization —
.gitsuffix and trailing slash variants are treated as separate projects - Re-import replaces — same URL overwrites existing activities in place, same
project_id - No route-level test for the import endpoint — mapper logic has unit tests; controller persistence is manually verified
Closed. The CPM engine and GitHub importer are complete and working. Further development (issues/PRs as activities, prospective planning input, deployment) would require a different data model that this project's architecture doesn't support without a redesign.