Back to ER Diagrams
Project Management Logic

Project Management Logic

End-to-end procurement project tracking from initiation through closure -- phases, milestones, risk management, team allocation, budget integration, and formal closure workflows.

6 Tables
Phase-Gate Model
Risk Register
Team Allocation

1. Overview

The Project Management module in ProKure provides a structured framework for tracking procurement projects from initiation through closure. It integrates with CRM leads, budget planning, and vendor management to deliver full lifecycle visibility across all procurement activities.

Key Capabilities

  • Full project lifecycle management with phase-gate controls
  • Milestone tracking with contractual, internal, payment, and delivery types
  • Risk register with probability-impact scoring and response strategies
  • Team allocation with over-allocation detection across projects
  • Budget integration with 80% utilization alerting (BR-PRJ-003)
  • CRM lead-to-project traceability via crm_lead_id
  • Checklist-based closure workflow with lessons learned capture

2. Database Schema

proj.projects

Master project table -- core project information, status, budget, and CRM linkage

id (PK)
unique_guid
code
name
manager_id (FK→users)
customer_id (FK)
budget_amount
start_date
end_date
status
overall_progress
description
custom_data (JSONB)
is_active
is_deleted
created_at
created_by (FK)
updated_at
updated_by (FK)
metadata (JSONB)
crm_lead_id (FK)

proj.project_phases

Sequential project phases with gate review controls and completion tracking

id (PK)
project_id (FK)
phase_name
phase_number
planned_start
planned_end
actual_start
actual_end
status
completion_pct
gate_review_status
created_at

proj.project_milestones

Key milestones with type classification and overdue detection

id (PK)
project_id (FK)
milestone_name
milestone_type
planned_date
actual_date
status
description
created_at

proj.project_risks

Risk register with probability-impact scoring and mitigation tracking

id (PK)
project_id (FK)
risk_title
description
probability (1-5)
impact (1-5)
risk_score
risk_category
response_strategy
mitigation_plan
risk_owner (FK→users)
status
review_date
created_at

proj.project_team_members

Team assignment with role-based allocation and lifecycle management

id (PK)
project_id (FK)
user_id (FK→users)
role
department_id (FK)
allocation_pct
start_date
end_date
is_active
created_at
updated_at

proj.project_closures

Formal closure records with checklist, lessons learned, and approval workflow

id (PK)
project_id (FK)
closure_type
checklist_items (JSONB)
final_budget_spent
final_timeline_days
pending_deliverables
lessons_learned
closure_requested_by (FK)
closure_approved_by (FK)
status
closed_at
created_at

3. Project Lifecycle

Projects follow a five-stage lifecycle. Each stage maps to specific table interactions and status transitions.

  ┌───────────┐    ┌───────────┐    ┌───────────┐    ┌───────────┐    ┌───────────┐
  │ CREATION  │---->│ PLANNING  │---->│ EXECUTION │---->│ MONITORING│---->│  CLOSURE  │
  └─────┬─────┘    └─────┬─────┘    └─────┬─────┘    └─────┬─────┘    └─────┬─────┘
        v                v                v                v                v
   projects         phases          milestones         risks           closures
   (INSERT)       team_members     risks, work      budget chk        (INSERT)
   PLANNING        PLANNING         ACTIVE         ACTIVE/ON_HOLD   COMPLETED/CANCELLED
StageStatusTables AffectedKey Actions
CreationPLANNINGproj.projectsRecord created, code auto-generated, manager assigned
PlanningPLANNINGproject_phases, project_team_membersPhases defined, team allocated, milestones planned
ExecutionACTIVEproject_milestones, project_risksWork begins, milestones tracked, risks logged
MonitoringACTIVE / ON_HOLDproject_risks, project_milestonesProgress reviews, risk reassessment, budget checks
ClosureCOMPLETED / CANCELLEDproject_closuresChecklist completion, lessons learned, approval

4. Phase Management

Projects are divided into sequential phases. Each phase must pass a gate review before the next phase can begin.

  PLANNED ----> IN_PROGRESS ----> GATE_REVIEW ----> COMPLETED
                                       |
                                       | (Rejected)
                                       v
                                  IN_PROGRESS  (Rework required)
-- Phase status and gate review readiness
SELECT pp.phase_name, pp.phase_number, pp.completion_pct, pp.gate_review_status,
    CASE
        WHEN pp.completion_pct = 100 AND pp.gate_review_status = 'APPROVED'
        THEN 'Ready for next phase'
        WHEN pp.completion_pct = 100 THEN 'Awaiting gate review'
        ELSE 'In progress'
    END AS phase_readiness
FROM proj.project_phases pp
WHERE pp.project_id = @project_id ORDER BY pp.phase_number;

Gate Review Rules

  • Phase completion_pct must reach 100% before gate review can be requested
  • Gate review requires approval from the project manager or designated reviewer
  • Next phase cannot transition to IN_PROGRESS until prior phase gate is APPROVED
  • Rejected gate reviews return the phase to IN_PROGRESS for rework

5. Milestone Tracking

Contractual

CONTRACTUAL
  • Tied to contract obligations
  • Legally binding deadlines
  • Penalty triggers on overdue

Internal

INTERNAL
  • Organization-defined targets
  • Progress checkpoints
  • Team coordination gates

Payment

PAYMENT
  • Linked to invoice processing
  • Triggers payment release
  • Budget impact tracked

Delivery

DELIVERY
  • Material/service receipt dates
  • GRN integration points
  • Vendor performance input
  UPCOMING ----(date passes)----> OVERDUE
      |
      | (actual_date set)
      v
  COMPLETED                       Note: CANCELLED can be set from any state
-- Overdue milestone detection (scheduled job)
UPDATE proj.project_milestones SET status = 'OVERDUE'
WHERE status = 'UPCOMING' AND planned_date < NOW() AND actual_date IS NULL;

-- Notify project managers of overdue milestones
SELECT p.name, pm.milestone_name, pm.milestone_type, pm.planned_date,
    NOW() - pm.planned_date AS days_overdue, u.email AS manager_email
FROM proj.project_milestones pm
JOIN proj.projects p ON p.id = pm.project_id
JOIN users u ON u.id = p.manager_id
WHERE pm.status = 'OVERDUE';

6. Risk Management

The risk register uses a probability-impact matrix to score and prioritize project risks. Each risk is assigned an owner, response strategy, and mitigation plan.

-- Risk score = Probability x Impact (range: 1 to 25)
risk_score = probability * impact
-- 1-4 = Low (green)  |  5-9 = Medium (yellow)  |  10-16 = High (orange)  |  17-25 = Critical (red)
  5x5 Risk Matrix         Impact:  1(VLow)  2(Low)  3(Med)  4(High)  5(VHigh)
  Probability:
  5 (Very High)                      5       10      15       20       25
  4 (High)                           4        8      12       16       20
  3 (Medium)                         3        6       9       12       15
  2 (Low)                            2        4       6        8       10
  1 (Very Low)                       1        2       3        4        5
StrategyDescriptionWhen to Apply
AVOIDEliminate risk by changing project scope or approachCritical risks with viable alternatives
MITIGATEReduce probability or impact through preventive actionHigh risks where full avoidance is not feasible
TRANSFERShift risk ownership to a third party (insurance, vendor)Financial or contractual risks
ACCEPTAcknowledge risk without active mitigationLow-scoring risks or unavoidable conditions
  OPEN ---(risk event occurs)---> MATERIALIZED ---(mitigation applied)---> MITIGATED ---> CLOSED
    |                                                                                       ^
    +---(resolved directly)---------------------------------------------------------------------+
-- Active high-priority risks requiring review
SELECT r.risk_title, r.risk_category, r.probability, r.impact, r.risk_score,
    r.response_strategy, u.full_name AS risk_owner, r.review_date
FROM proj.project_risks r
JOIN users u ON u.id = r.risk_owner
WHERE r.project_id = @project_id AND r.status = 'OPEN' AND r.risk_score >= 10
ORDER BY r.risk_score DESC;

7. Budget Integration

Project budgets are linked to planning.budgets for commitment tracking and utilization alerting.

-- Budget utilization check (BR-PRJ-003: Alert at 80%)
SELECT p.code, p.name, p.budget_amount, b.committed_amount, b.spent_amount,
    ROUND((b.spent_amount / NULLIF(p.budget_amount, 0)) * 100, 2) AS utilization_pct,
    CASE
        WHEN b.spent_amount >= p.budget_amount * 0.80 THEN 'ALERT: 80% threshold breached'
        WHEN b.spent_amount >= p.budget_amount * 0.60 THEN 'WARNING: Approaching threshold'
        ELSE 'Normal'
    END AS budget_status
FROM proj.projects p JOIN planning.budgets b ON b.project_id = p.id
WHERE p.status = 'ACTIVE' AND p.is_deleted = false;

Budget Commitment Tracking

  • Purchase Orders linked to the project increment committed_amount in planning.budgets
  • Invoice payments increment spent_amount upon three-way match approval
  • At 80% utilization, an automatic notification is sent to the project manager
  • Budget overruns require explicit approval from finance and project sponsor

8. CRM Integration

The crm_lead_id column in proj.projects enables end-to-end traceability from CRM lead conversion to project delivery.

  CRM Module                                 Project Module
  ┌─────────────────┐    Lead Conversion     ┌─────────────────────┐
  │  crm.leads      │------(Screen 124)----->│  proj.projects      │
  │  lead_id        │                        │  crm_lead_id = FK   │
  │  customer_name  │                        │  Inherits:          │
  │  deal_value     │                        │   - customer_id     │
  │  status = WON   │                        │   - budget_amount   │
  └─────────────────┘                        └─────────────────────┘
-- Trace project back to originating CRM lead
SELECT p.code, p.name, p.status, l.lead_code, l.customer_name,
    l.deal_value AS original_deal_value, p.budget_amount AS project_budget
FROM proj.projects p JOIN crm.leads l ON l.id = p.crm_lead_id
WHERE p.crm_lead_id IS NOT NULL;

9. Team Assignment

RolePermissionsTypical Allocation
MANAGERFull project control, team management, closure initiation50-100%
LEADPhase management, milestone updates, risk logging40-80%
MEMBERTask execution, milestone completion, time logging20-60%
OBSERVERRead-only access to project dashboards and reports5-10%
-- Detect over-allocated users (total allocation > 100% across active projects)
SELECT u.id, u.full_name,
    SUM(tm.allocation_pct) AS total_allocation,
    COUNT(tm.project_id) AS project_count,
    CASE WHEN SUM(tm.allocation_pct) > 100 THEN 'OVER-ALLOCATED' ELSE 'OK' END AS status
FROM proj.project_team_members tm
JOIN users u ON u.id = tm.user_id
JOIN proj.projects p ON p.id = tm.project_id
WHERE tm.is_active = true AND p.status IN ('PLANNING', 'ACTIVE')
GROUP BY u.id, u.full_name HAVING SUM(tm.allocation_pct) > 100
ORDER BY total_allocation DESC;

Team Lifecycle Management

  • Members are added with a start_date and optional end_date
  • Setting is_active to false removes a member from active project dashboards
  • When a member's end_date passes, a scheduled job marks is_active = false
  • Historical membership records are retained for audit and reporting

10. Closure Workflow

  DRAFT ----(submit)----> PENDING_APPROVAL ----(approve)----> APPROVED
                                |
                                | (reject)
                                v
                           REJECTED ----(revise)----> DRAFT

  Closure Types: COMPLETED | CANCELLED | SUSPENDED
-- Example checklist_items JSONB content
{
  "items": [
    { "key": "deliverables_accepted", "label": "All deliverables accepted by customer", "checked": true  },
    { "key": "invoices_settled",      "label": "All invoices settled",                   "checked": true  },
    { "key": "contracts_closed",     "label": "Vendor contracts formally closed",        "checked": false },
    { "key": "docs_archived",        "label": "Project documents archived",              "checked": true  },
    { "key": "team_released",        "label": "Team members released from allocation",   "checked": false },
    { "key": "lessons_documented",   "label": "Lessons learned documented",              "checked": true  }
  ]
}

-- Pending deliverables check before closure approval (BR-PRJ-004)
SELECT pm.milestone_name, pm.milestone_type, pm.status
FROM proj.project_milestones pm
WHERE pm.project_id = @project_id AND pm.status IN ('UPCOMING', 'OVERDUE');
-- If rows returned AND closure_type != 'CANCELLED', block closure

Closure Report Generation

  • Final budget comparison: budget_amount vs. final_budget_spent
  • Timeline analysis: planned duration vs. final_timeline_days
  • Pending deliverables listed for follow-up or write-off
  • Lessons learned captured as free-text for organizational knowledge base

11. Business Rules

Rule IDRule DescriptionEnforcementTables
BR-PRJ-001Project code is auto-generated and immutable after creationDatabase trigger prevents UPDATE on code columnproj.projects
BR-PRJ-002Only project manager or admin can add/remove team membersApplication-level RBAC check on INSERT/DELETEproj.project_team_members
BR-PRJ-003Budget utilization alert triggered at 80% of budget_amountScheduled job + notification serviceproj.projects, planning.budgets
BR-PRJ-004Cannot close project with pending milestones unless closure_type = CANCELLEDApplication-level validation on closure approvalproj.project_closures, proj.project_milestones
-- BR-PRJ-001: Trigger to prevent project code modification
CREATE OR REPLACE FUNCTION proj.prevent_code_update()
RETURNS TRIGGER AS $$
BEGIN
    IF OLD.code IS DISTINCT FROM NEW.code THEN
        RAISE EXCEPTION 'Project code is immutable and cannot be modified';
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_prevent_project_code_update
BEFORE UPDATE ON proj.projects
FOR EACH ROW EXECUTE FUNCTION proj.prevent_code_update();

-- BR-PRJ-004: Closure validation function
CREATE OR REPLACE FUNCTION proj.validate_closure(
    p_project_id INT, p_closure_type VARCHAR
) RETURNS BOOLEAN AS $$
DECLARE v_pending_count INT;
BEGIN
    IF p_closure_type = 'CANCELLED' THEN RETURN true; END IF;
    SELECT COUNT(*) INTO v_pending_count FROM proj.project_milestones
    WHERE project_id = p_project_id AND status IN ('UPCOMING', 'OVERDUE');
    RETURN v_pending_count = 0;
END;
$$ LANGUAGE plpgsql;

ProKure Database Documentation - Project Management Logic v1.0

Part of the ProKure Procurement Management System