2.1: Requirements Management Systems


Overview

Requirements Management Systems (RMS) are the backbone of requirements engineering in ASPICE-compliant development. This section covers enterprise platforms, their capabilities, and AI-enhanced features for modern development.


Core RMS Capabilities

Essential Features Matrix

The following diagram maps the essential capabilities of a requirements management system, including traceability, baselining, change management, and reporting features required for ASPICE compliance.

RMS Essential Capabilities


Platform Comparison

Enterprise RMS Overview

Platform Vendor Deployment Primary Industries
IBM DOORS Next IBM Cloud/On-prem Automotive, Aerospace, Defense
Jama Connect Jama Cloud/On-prem Cross-industry, Medical
Polarion ALM Siemens Cloud/On-prem Automotive, Medical
Codebeamer PTC Cloud/On-prem Automotive, Rail
Helix RM Perforce Cloud/On-prem Automotive, Aerospace
Visure Visure Cloud/On-prem Defense, Aerospace

Feature Comparison

Note: Feature ratings reflect capabilities as of Q4 2024. Verify current features with vendors as capabilities evolve rapidly, especially for AI features.

Feature DOORS Jama Polarion Codebeamer Helix RM
Rich Text Editing Excellent Excellent Excellent Good Good
Custom Attributes Excellent Excellent Excellent Excellent Excellent
Hierarchical Struct Excellent Good Excellent Excellent Good
Trace Links Excellent Excellent Excellent Excellent Excellent
Impact Analysis Good Excellent Good Excellent Fair
Baseline Management Excellent Good Excellent Good Excellent
Review Workflows Good Excellent Excellent Excellent Fair
ReqIF Support Excellent Good Excellent Excellent Good
OSLC Compliance Excellent Fair Good Fair Fair
AI Features Good Good Fair Good Limited
REST API Good Excellent Good Excellent Good
Git Integration Fair Good Excellent Excellent Excellent

Legend: Excellent = Full support, Good = Strong support, Fair = Basic support, Limited = Minimal support


Traceability Architecture

Trace Link Model

The following diagram shows how the V-Model traceability chain flows through the RMS, connecting stakeholder needs through system and software requirements down to verification evidence. Each horizontal trace link enables impact analysis when requirements change.

V-Model Traceability Chain

Baseline Strategy

Baseline management preserves requirement snapshots at key project milestones. The baseline strategy diagram illustrates how progressive baselines support change control and audit readiness across the ASPICE assessment lifecycle.

Requirements Baseline Strategy


RMS Configuration Example

Project Setup Script

"""
RMS Project Configuration Script
Sets up requirements structure for ASPICE compliance
"""

from dataclasses import dataclass
from typing import List, Dict
from enum import Enum

class RequirementType(Enum):
    STAKEHOLDER = "STKH"
    SYSTEM = "SYS"
    SOFTWARE = "SWE"
    HARDWARE = "HWE"
    INTERFACE = "IFC"
    SAFETY = "SAF"
    SECURITY = "SEC"

class AttributeType(Enum):
    STRING = "string"
    ENUMERATION = "enumeration"
    INTEGER = "integer"
    DATE = "date"
    USER = "user"
    LINK = "link"

@dataclass
class RequirementAttribute:
    """Definition of a requirement attribute."""
    name: str
    attr_type: AttributeType
    required: bool = False
    values: List[str] = None  # For enumeration type

class RMSProjectSetup:
    """Configure RMS project for ASPICE compliance."""

    def __init__(self, project_name: str):
        self.project_name = project_name
        self.modules = []
        self.attributes = []
        self.link_types = []

    def define_standard_attributes(self) -> List[RequirementAttribute]:
        """Define standard ASPICE-compliant attributes."""
        return [
            RequirementAttribute(
                name="ID",
                attr_type=AttributeType.STRING,
                required=True
            ),
            RequirementAttribute(
                name="Text",
                attr_type=AttributeType.STRING,
                required=True
            ),
            RequirementAttribute(
                name="Rationale",
                attr_type=AttributeType.STRING,
                required=False
            ),
            RequirementAttribute(
                name="Status",
                attr_type=AttributeType.ENUMERATION,
                required=True,
                values=["Draft", "In Review", "Approved", "Obsolete"]
            ),
            RequirementAttribute(
                name="Priority",
                attr_type=AttributeType.ENUMERATION,
                required=True,
                values=["High", "Medium", "Low"]
            ),
            RequirementAttribute(
                name="Verification Method",
                attr_type=AttributeType.ENUMERATION,
                required=True,
                values=["Test", "Analysis", "Review", "Demonstration"]
            ),
            RequirementAttribute(
                name="ASIL",
                attr_type=AttributeType.ENUMERATION,
                required=False,
                values=["QM", "ASIL-A", "ASIL-B", "ASIL-C", "ASIL-D"]
            ),
            RequirementAttribute(
                name="Owner",
                attr_type=AttributeType.USER,
                required=True
            ),
            RequirementAttribute(
                name="Created Date",
                attr_type=AttributeType.DATE,
                required=True
            ),
            RequirementAttribute(
                name="Modified Date",
                attr_type=AttributeType.DATE,
                required=True
            )
        ]

    def define_module_structure(self) -> Dict[str, Dict]:
        """Define requirements module structure."""
        return {
            "01_Stakeholder_Requirements": {
                "prefix": "STKH",
                "type": RequirementType.STAKEHOLDER,
                "parent": None,
                "description": "Customer and stakeholder requirements"
            },
            "02_System_Requirements": {
                "prefix": "SYS",
                "type": RequirementType.SYSTEM,
                "parent": "01_Stakeholder_Requirements",
                "description": "System-level requirements"
            },
            "03_Software_Requirements": {
                "prefix": "SWE",
                "type": RequirementType.SOFTWARE,
                "parent": "02_System_Requirements",
                "description": "Software requirements specification"
            },
            "04_Hardware_Requirements": {
                "prefix": "HWE",
                "type": RequirementType.HARDWARE,
                "parent": "02_System_Requirements",
                "description": "Hardware requirements specification"
            },
            "05_Interface_Requirements": {
                "prefix": "IFC",
                "type": RequirementType.INTERFACE,
                "parent": "02_System_Requirements",
                "description": "Interface specifications"
            },
            "06_Safety_Requirements": {
                "prefix": "SAF",
                "type": RequirementType.SAFETY,
                "parent": "02_System_Requirements",
                "description": "Functional safety requirements"
            },
            "07_Security_Requirements": {
                "prefix": "SEC",
                "type": RequirementType.SECURITY,
                "parent": "02_System_Requirements",
                "description": "Cybersecurity requirements"
            }
        }

    def define_link_types(self) -> List[Dict]:
        """Define traceability link types."""
        return [
            {
                "name": "derives",
                "source": "Parent Requirement",
                "target": "Child Requirement",
                "description": "Requirement decomposition"
            },
            {
                "name": "satisfies",
                "source": "Implementation",
                "target": "Requirement",
                "description": "Implementation satisfies requirement"
            },
            {
                "name": "verifies",
                "source": "Test Case",
                "target": "Requirement",
                "description": "Test verifies requirement"
            },
            {
                "name": "allocates",
                "source": "Requirement",
                "target": "Architecture Element",
                "description": "Requirement allocated to component"
            },
            {
                "name": "refines",
                "source": "Detail",
                "target": "Abstract",
                "description": "Refinement relationship"
            },
            {
                "name": "conflicts",
                "source": "Requirement",
                "target": "Requirement",
                "description": "Conflict between requirements"
            },
            {
                "name": "depends",
                "source": "Dependent",
                "target": "Dependency",
                "description": "Dependency relationship"
            }
        ]

    def generate_config(self) -> Dict:
        """Generate complete project configuration."""
        return {
            "project": {
                "name": self.project_name,
                "version": "1.0.0",
                "standard": "ASPICE 4.0"
            },
            "attributes": [attr.__dict__ for attr in self.define_standard_attributes()],
            "modules": self.define_module_structure(),
            "link_types": self.define_link_types(),
            "workflows": self._define_workflows(),
            "reports": self._define_reports()
        }

    def _define_workflows(self) -> List[Dict]:
        """Define requirement workflows."""
        return [
            {
                "name": "Standard Approval",
                "states": ["Draft", "In Review", "Approved", "Obsolete"],
                "transitions": [
                    {"from": "Draft", "to": "In Review", "action": "Submit for Review"},
                    {"from": "In Review", "to": "Approved", "action": "Approve"},
                    {"from": "In Review", "to": "Draft", "action": "Reject"},
                    {"from": "Approved", "to": "Obsolete", "action": "Deprecate"}
                ]
            }
        ]

    def _define_reports(self) -> List[Dict]:
        """Define standard reports."""
        return [
            {
                "name": "Traceability Matrix",
                "type": "matrix",
                "rows": "Software Requirements",
                "columns": "System Requirements",
                "link_type": "derives"
            },
            {
                "name": "Coverage Report",
                "type": "coverage",
                "source": "Requirements",
                "target": "Test Cases",
                "link_type": "verifies"
            },
            {
                "name": "Requirements Status",
                "type": "dashboard",
                "metrics": ["Total", "Draft", "In Review", "Approved"]
            }
        ]


# Usage
if __name__ == '__main__':
    setup = RMSProjectSetup("BCM_Door_Lock_Controller")
    config = setup.generate_config()

    print(f"Project: {config['project']['name']}")
    print(f"Modules: {len(config['modules'])}")
    print(f"Attributes: {len(config['attributes'])}")
    print(f"Link Types: {len(config['link_types'])}")

The following diagram compares the IBM DOORS product family, showing how DOORS Classic and DOORS Next Generation differ in architecture, deployment models, and integration capabilities.

![IBM DOORS Product Family](../diagrams/Part_III/13.01_DOORS_Product_Family_2.drawio.svg)

---

## DOORS Next Configuration

### Project Area Setup

```yaml
# DOORS Next Project Area Configuration
# doors-project-config.yaml

project_area:
  name: "BCM_Door_Lock_Controller"
  description: "Body Control Module - Door Lock Requirements"
  lifecycle: "ASPICE_Automotive"

process_configuration:
  template: "ASPICE-4.1-Automotive"
  iteration_type: "Milestone"

components:
  - name: "Stakeholder Requirements"
    abbreviation: "STKH"
    owner: "product_manager"

  - name: "System Requirements"
    abbreviation: "SYS"
    owner: "system_architect"

  - name: "Software Requirements"
    abbreviation: "SWE"
    owner: "sw_architect"

  - name: "Hardware Requirements"
    abbreviation: "HWE"
    owner: "hw_architect"

  - name: "Safety Requirements"
    abbreviation: "SAF"
    owner: "safety_manager"

  - name: "Security Requirements"
    abbreviation: "SEC"
    owner: "security_manager"

artifact_types:
  - name: "Requirement"
    attributes:
      - name: "ID"
        type: "string"
        required: true
      - name: "Title"
        type: "string"
        required: true
      - name: "Description"
        type: "rich_text"
        required: true
      - name: "Rationale"
        type: "rich_text"
        required: false
      - name: "Status"
        type: "enumeration"
        values: ["Draft", "Proposed", "Approved", "Implemented", "Verified", "Deleted"]
        required: true
      - name: "Priority"
        type: "enumeration"
        values: ["Must Have", "Should Have", "Could Have", "Won't Have"]
        required: true
      - name: "Verification Method"
        type: "enumeration"
        values: ["Test", "Analysis", "Review", "Demonstration"]
        required: true
      - name: "ASIL"
        type: "enumeration"
        values: ["QM", "ASIL-A", "ASIL-B", "ASIL-C", "ASIL-D"]
        required: false

link_types:
  - name: "Satisfies"
    source_type: "Requirement"
    target_type: "Requirement"
    direction: "forward"

  - name: "Derives From"
    source_type: "Requirement"
    target_type: "Requirement"
    direction: "backward"

  - name: "Verified By"
    source_type: "Requirement"
    target_type: "Test Case"
    direction: "forward"

  - name: "Implements"
    source_type: "Implementation"
    target_type: "Requirement"
    direction: "backward"

permissions:
  roles:
    - name: "Requirements Engineer"
      permissions: ["create", "edit", "delete", "view", "export"]

    - name: "Reviewer"
      permissions: ["view", "comment", "approve"]

    - name: "Viewer"
      permissions: ["view", "export"]

    - name: "Administrator"
      permissions: ["all"]

baselines:
  naming_convention: "{component}_{version}_{date}"
  auto_baseline_triggers:
    - on_approval_complete
    - on_milestone_completion

reports:
  - name: "Traceability Matrix"
    type: "matrix"
    format: ["html", "pdf", "excel"]

  - name: "Requirements Status Dashboard"
    type: "dashboard"
    widgets:
      - requirements_by_status
      - requirements_by_priority
      - trace_coverage

  - name: "Impact Analysis"
    type: "impact"
    depth: 3

The following diagram illustrates Jama Connect's architecture, showing its REST API layer, project containers, item types, and integration points with external development tools.

![Jama Connect Architecture](../diagrams/Part_III/13.01_Jama_Connect_Arch_3.drawio.svg)

### REST API Integration

```python
"""
Jama Connect REST API Client
For CI/CD integration and automation
"""

import requests
from typing import List, Dict, Optional
from dataclasses import dataclass

@dataclass
class JamaItem:
    """Jama item representation."""
    id: int
    global_id: str
    item_type: str
    fields: Dict
    parent_id: Optional[int] = None

class JamaConnectClient:
    """Client for Jama Connect REST API."""

    def __init__(self, base_url: str, client_id: str, client_secret: str):
        self.base_url = base_url.rstrip('/')
        self.auth = (client_id, client_secret)
        self.session = requests.Session()
        self.session.auth = self.auth
        self.session.headers.update({
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        })

    def get_projects(self) -> List[Dict]:
        """Get all projects."""
        url = f"{self.base_url}/rest/latest/projects"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json().get('data', [])

    def get_items(self, project_id: int, item_type: Optional[str] = None,
                  start_at: int = 0, max_results: int = 50) -> List[Dict]:
        """Get items from a project."""
        url = f"{self.base_url}/rest/latest/items"
        params = {
            'project': project_id,
            'startAt': start_at,
            'maxResults': max_results
        }

        if item_type:
            params['itemType'] = item_type

        response = self.session.get(url, params=params)
        response.raise_for_status()
        return response.json().get('data', [])

    def get_item(self, item_id: int) -> Dict:
        """Get a specific item."""
        url = f"{self.base_url}/rest/latest/items/{item_id}"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json().get('data', {})

    def create_item(self, project_id: int, item_type_id: int,
                   fields: Dict, parent_id: Optional[int] = None) -> Dict:
        """Create a new item."""
        url = f"{self.base_url}/rest/latest/items"

        item_data = {
            'project': project_id,
            'itemType': item_type_id,
            'fields': fields,
            'location': {
                'parent': {'item': parent_id} if parent_id else None
            }
        }

        response = self.session.post(url, json=item_data)
        response.raise_for_status()
        return response.json().get('data', {})

    def update_item(self, item_id: int, fields: Dict) -> Dict:
        """Update an item."""
        url = f"{self.base_url}/rest/latest/items/{item_id}"
        response = self.session.put(url, json={'fields': fields})
        response.raise_for_status()
        return response.json().get('data', {})

    def get_relationships(self, item_id: int) -> List[Dict]:
        """Get relationships for an item."""
        url = f"{self.base_url}/rest/latest/items/{item_id}/relationships"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json().get('data', [])

    def create_relationship(self, from_item: int, to_item: int,
                           relationship_type: int) -> Dict:
        """Create a relationship between items."""
        url = f"{self.base_url}/rest/latest/relationships"

        rel_data = {
            'fromItem': from_item,
            'toItem': to_item,
            'relationshipType': relationship_type
        }

        response = self.session.post(url, json=rel_data)
        response.raise_for_status()
        return response.json().get('data', {})

    def get_baselines(self, project_id: int) -> List[Dict]:
        """Get baselines for a project."""
        url = f"{self.base_url}/rest/latest/baselines"
        params = {'project': project_id}
        response = self.session.get(url, params=params)
        response.raise_for_status()
        return response.json().get('data', [])

    def create_baseline(self, project_id: int, name: str,
                       description: str) -> Dict:
        """Create a new baseline."""
        url = f"{self.base_url}/rest/latest/baselines"

        baseline_data = {
            'project': project_id,
            'name': name,
            'description': description
        }

        response = self.session.post(url, json=baseline_data)
        response.raise_for_status()
        return response.json().get('data', {})

    def get_item_types(self, project_id: int) -> List[Dict]:
        """Get item types for a project."""
        url = f"{self.base_url}/rest/latest/itemtypes"
        params = {'project': project_id}
        response = self.session.get(url, params=params)
        response.raise_for_status()
        return response.json().get('data', [])

    def search_items(self, project_id: int, query: str) -> List[Dict]:
        """Search for items."""
        url = f"{self.base_url}/rest/latest/abstractitems"
        params = {
            'project': project_id,
            'contains': query
        }
        response = self.session.get(url, params=params)
        response.raise_for_status()
        return response.json().get('data', [])


class JamaMetrics:
    """Calculate requirements metrics from Jama Connect."""

    def __init__(self, client: JamaConnectClient):
        self.client = client

    def get_item_status_distribution(self, project_id: int) -> Dict:
        """Get item count by status."""
        items = self.client.get_items(project_id, max_results=1000)

        status_count = {}
        for item in items:
            status = item.get('fields', {}).get('status', 'Unknown')
            status_count[status] = status_count.get(status, 0) + 1

        return status_count

    def get_trace_coverage(self, project_id: int,
                          source_type: str, target_type: str) -> Dict:
        """Calculate traceability coverage."""
        source_items = self.client.get_items(
            project_id, item_type=source_type, max_results=1000
        )

        total = len(source_items)
        linked = 0

        for item in source_items:
            relationships = self.client.get_relationships(item['id'])
            if any(r for r in relationships):
                linked += 1

        coverage = (linked / total * 100) if total > 0 else 0

        return {
            'total': total,
            'linked': linked,
            'coverage_percentage': round(coverage, 2)
        }


# Usage
if __name__ == '__main__':
    client = JamaConnectClient(
        base_url='https://your-instance.jamacloud.com',
        client_id='your-client-id',
        client_secret='your-client-secret'
    )

    # Get projects
    projects = client.get_projects()
    print(f"Found {len(projects)} projects")

    # Calculate metrics
    metrics = JamaMetrics(client)
    for project in projects[:3]:
        status = metrics.get_item_status_distribution(project['id'])
        print(f"Project {project['name']}: {status}")

Siemens Polarion

Configuration

# Polarion Project Configuration
# polarion-project.xml

project:
  id: "BCM_Door_Lock"
  name: "Body Control Module - Door Lock Controller"
  description: "ASPICE-compliant requirements management"

work_item_types:
  - id: "stakeholder_req"
    name: "Stakeholder Requirement"
    prefix: "STKH"
    color: "#4CAF50"

  - id: "system_req"
    name: "System Requirement"
    prefix: "SYS"
    color: "#2196F3"

  - id: "software_req"
    name: "Software Requirement"
    prefix: "SWE"
    color: "#9C27B0"

  - id: "test_case"
    name: "Test Case"
    prefix: "TC"
    color: "#FF9800"

custom_fields:
  - id: "rationale"
    name: "Rationale"
    type: "rich_text"
    applicable_types: ["stakeholder_req", "system_req", "software_req"]

  - id: "verification_method"
    name: "Verification Method"
    type: "enum"
    values: ["Test", "Analysis", "Review", "Demonstration"]
    applicable_types: ["system_req", "software_req"]

  - id: "asil"
    name: "ASIL"
    type: "enum"
    values: ["QM", "ASIL-A", "ASIL-B", "ASIL-C", "ASIL-D"]
    applicable_types: ["system_req", "software_req"]

link_roles:
  - id: "derives"
    name: "Derives From"
    opposite_role: "derived_by"
    source_types: ["system_req", "software_req"]
    target_types: ["stakeholder_req", "system_req"]

  - id: "verifies"
    name: "Verifies"
    opposite_role: "verified_by"
    source_types: ["test_case"]
    target_types: ["system_req", "software_req"]

workflows:
  - id: "req_workflow"
    name: "Requirement Workflow"
    applicable_types: ["stakeholder_req", "system_req", "software_req"]
    states:
      - id: "draft"
        name: "Draft"
        initial: true
      - id: "in_review"
        name: "In Review"
      - id: "approved"
        name: "Approved"
      - id: "implemented"
        name: "Implemented"
      - id: "verified"
        name: "Verified"
      - id: "obsolete"
        name: "Obsolete"
    transitions:
      - from: "draft"
        to: "in_review"
        action: "Submit for Review"
      - from: "in_review"
        to: "approved"
        action: "Approve"
      - from: "in_review"
        to: "draft"
        action: "Reject"
      - from: "approved"
        to: "implemented"
        action: "Mark Implemented"
      - from: "implemented"
        to: "verified"
        action: "Mark Verified"
      - from: "*"
        to: "obsolete"
        action: "Obsolete"
        conditions:
          - "hasPermission('obsolete_items')"

documents:
  - id: "srs_template"
    name: "Software Requirements Specification"
    template: "ASPICE_SRS_Template"
    allowed_types: ["software_req"]

baselines:
  naming_pattern: "{project}_{milestone}_{version}_{date}"
  auto_create:
    triggers:
      - on_milestone_completion
      - on_approval_gate

REST API Client

"""
Polarion REST API Client
For CI/CD integration and automation
"""

import requests
from zeep import Client
from zeep.transports import Transport
from typing import List, Dict, Optional

class PolarionClient:
    """Client for Polarion REST and SOAP APIs."""

    def __init__(self, server_url: str, username: str, password: str):
        self.server_url = server_url.rstrip('/')
        self.username = username
        self.password = password
        self.session = self._create_session()

    def _create_session(self) -> requests.Session:
        """Create authenticated session."""
        session = requests.Session()
        session.auth = (self.username, self.password)
        session.headers.update({
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        })
        return session

    def get_projects(self) -> List[Dict]:
        """Get all projects."""
        url = f"{self.server_url}/polarion/rest/v1/projects"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json().get('data', [])

    def get_work_items(self, project_id: str, query: str = "",
                      page_size: int = 100) -> List[Dict]:
        """Get work items with optional query."""
        url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems"
        params = {
            'query': query,
            'page[size]': page_size
        }
        response = self.session.get(url, params=params)
        response.raise_for_status()
        return response.json().get('data', [])

    def get_work_item(self, project_id: str, work_item_id: str) -> Dict:
        """Get a specific work item."""
        url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems/{work_item_id}"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json().get('data', {})

    def create_work_item(self, project_id: str, work_item_type: str,
                        title: str, fields: Dict) -> Dict:
        """Create a new work item."""
        url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems"

        payload = {
            'data': {
                'type': 'workitems',
                'attributes': {
                    'type': work_item_type,
                    'title': title,
                    **fields
                }
            }
        }

        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json().get('data', {})

    def update_work_item(self, project_id: str, work_item_id: str,
                        fields: Dict) -> Dict:
        """Update a work item."""
        url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems/{work_item_id}"

        payload = {
            'data': {
                'type': 'workitems',
                'id': f"{project_id}/{work_item_id}",
                'attributes': fields
            }
        }

        response = self.session.patch(url, json=payload)
        response.raise_for_status()
        return response.json().get('data', {})

    def get_linked_work_items(self, project_id: str,
                             work_item_id: str) -> List[Dict]:
        """Get linked work items."""
        url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems/{work_item_id}/linkedworkitems"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json().get('data', [])

    def create_link(self, project_id: str, source_id: str,
                   target_id: str, role: str) -> bool:
        """Create a link between work items."""
        url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems/{source_id}/linkedworkitems"

        payload = {
            'data': [{
                'type': 'linkedworkitems',
                'attributes': {
                    'role': role,
                    'targetWorkItem': f"{project_id}/{target_id}"
                }
            }]
        }

        response = self.session.post(url, json=payload)
        return response.status_code == 201

    def get_documents(self, project_id: str) -> List[Dict]:
        """Get documents in a project."""
        url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/spaces/_default/documents"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json().get('data', [])

    def get_baselines(self, project_id: str) -> List[Dict]:
        """Get baselines for a project."""
        # Query work items with baseline field
        return self.get_work_items(project_id, "type:baseline")

    def create_baseline(self, project_id: str, name: str,
                       description: str, work_item_ids: List[str]) -> Dict:
        """Create a baseline."""
        # Polarion baselines are typically created via LiveDoc or SOAP API
        # This is a simplified REST approach
        pass

    def run_query(self, project_id: str, lucene_query: str) -> List[Dict]:
        """Run a Lucene query."""
        return self.get_work_items(project_id, lucene_query)


class PolarionMetrics:
    """Calculate requirements metrics from Polarion."""

    def __init__(self, client: PolarionClient):
        self.client = client

    def get_status_distribution(self, project_id: str,
                               work_item_type: str) -> Dict:
        """Get work item count by status."""
        items = self.client.get_work_items(
            project_id, f"type:{work_item_type}"
        )

        status_count = {}
        for item in items:
            status = item.get('attributes', {}).get('status', 'Unknown')
            status_count[status] = status_count.get(status, 0) + 1

        return status_count

    def get_trace_coverage(self, project_id: str,
                          source_type: str, link_role: str) -> Dict:
        """Calculate traceability coverage."""
        source_items = self.client.get_work_items(
            project_id, f"type:{source_type}"
        )

        total = len(source_items)
        linked = 0

        for item in source_items:
            item_id = item.get('id', '').split('/')[-1]
            links = self.client.get_linked_work_items(project_id, item_id)

            # Check for links with specified role
            if any(l.get('attributes', {}).get('role') == link_role
                   for l in links):
                linked += 1

        coverage = (linked / total * 100) if total > 0 else 0

        return {
            'total': total,
            'linked': linked,
            'coverage_percentage': round(coverage, 2)
        }


# Usage
if __name__ == '__main__':
    client = PolarionClient(
        server_url='https://polarion-server.example.com',
        username='api_user',
        password='api_password'
    )

    # Get projects
    projects = client.get_projects()
    print(f"Found {len(projects)} projects")

    # Search requirements
    requirements = client.get_work_items(
        'BCM_Door_Lock',
        'type:software_req AND status:approved'
    )
    print(f"Found {len(requirements)} approved SW requirements")

PTC Codebeamer

Configuration

# Codebeamer Project Configuration
# codebeamer-config.yaml

project:
  name: "BCM_Door_Lock_Controller"
  description: "ASPICE-compliant requirements and ALM"
  template: "ASPICE_Automotive"

trackers:
  - name: "Stakeholder Requirements"
    key: "STKH"
    type: "requirement"
    workflow: "requirement_workflow"
    fields:
      - name: "Description"
        type: "wikitext"
        mandatory: true
      - name: "Rationale"
        type: "wikitext"
      - name: "Priority"
        type: "choice"
        options: ["Must Have", "Should Have", "Could Have", "Won't Have"]

  - name: "System Requirements"
    key: "SYS"
    type: "requirement"
    workflow: "requirement_workflow"
    fields:
      - name: "Description"
        type: "wikitext"
        mandatory: true
      - name: "Verification Method"
        type: "choice"
        options: ["Test", "Analysis", "Review", "Demonstration"]
      - name: "ASIL"
        type: "choice"
        options: ["QM", "ASIL-A", "ASIL-B", "ASIL-C", "ASIL-D"]

  - name: "Software Requirements"
    key: "SWE"
    type: "requirement"
    workflow: "requirement_workflow"

  - name: "Test Cases"
    key: "TC"
    type: "testcase"
    workflow: "testcase_workflow"

associations:
  - name: "derives_from"
    from_tracker: "System Requirements"
    to_tracker: "Stakeholder Requirements"
    propagate_suspect: true

  - name: "derives_from"
    from_tracker: "Software Requirements"
    to_tracker: "System Requirements"
    propagate_suspect: true

  - name: "verifies"
    from_tracker: "Test Cases"
    to_tracker: "Software Requirements"
    propagate_suspect: true

workflows:
  requirement_workflow:
    states:
      - name: "Draft"
        initial: true
      - name: "In Review"
      - name: "Approved"
      - name: "Implemented"
      - name: "Verified"
      - name: "Obsolete"
        final: true
    transitions:
      - from: "Draft"
        to: "In Review"
        permission: "requirement_submit"
      - from: "In Review"
        to: "Approved"
        permission: "requirement_approve"
      - from: "In Review"
        to: "Draft"
        permission: "requirement_reject"

baselines:
  auto_create:
    on_release: true
    on_milestone: true
  naming: "{project}_{tracker}_{version}_{date}"

integrations:
  git:
    enabled: true
    repositories:
      - url: "https://github.com/company/bcm-doorlock.git"
        branch_pattern: "feature/*"
        commit_association: true

  jenkins:
    enabled: true
    server: "https://jenkins.example.com"
    job_pattern: "BCM_*"

REST API Client

"""
PTC Codebeamer REST API Client
For CI/CD integration and automation
"""

import requests
from typing import List, Dict, Optional
from dataclasses import dataclass

@dataclass
class TrackerItem:
    """Codebeamer tracker item representation."""
    id: int
    name: str
    tracker_id: int
    status: str
    description: str
    custom_fields: Dict

class CodebeamerClient:
    """Client for Codebeamer REST API."""

    def __init__(self, base_url: str, username: str, password: str):
        self.base_url = base_url.rstrip('/')
        self.session = requests.Session()
        self.session.auth = (username, password)
        self.session.headers.update({
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        })

    def get_projects(self) -> List[Dict]:
        """Get all projects."""
        url = f"{self.base_url}/api/v3/projects"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json()

    def get_trackers(self, project_id: int) -> List[Dict]:
        """Get trackers in a project."""
        url = f"{self.base_url}/api/v3/projects/{project_id}/trackers"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json()

    def get_tracker_items(self, tracker_id: int, page: int = 1,
                         page_size: int = 100,
                         query_string: str = "") -> Dict:
        """Get items from a tracker."""
        url = f"{self.base_url}/api/v3/trackers/{tracker_id}/items"
        params = {
            'page': page,
            'pageSize': page_size
        }

        if query_string:
            params['queryString'] = query_string

        response = self.session.get(url, params=params)
        response.raise_for_status()
        return response.json()

    def get_item(self, item_id: int) -> Dict:
        """Get a specific item."""
        url = f"{self.base_url}/api/v3/items/{item_id}"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json()

    def create_item(self, tracker_id: int, name: str,
                   description: str, fields: Dict = None) -> Dict:
        """Create a new tracker item."""
        url = f"{self.base_url}/api/v3/trackers/{tracker_id}/items"

        payload = {
            'name': name,
            'description': description,
            **(fields or {})
        }

        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()

    def update_item(self, item_id: int, fields: Dict) -> Dict:
        """Update a tracker item."""
        url = f"{self.base_url}/api/v3/items/{item_id}"
        response = self.session.put(url, json=fields)
        response.raise_for_status()
        return response.json()

    def get_associations(self, item_id: int) -> List[Dict]:
        """Get associations (links) for an item."""
        url = f"{self.base_url}/api/v3/items/{item_id}/associations"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json()

    def create_association(self, from_id: int, to_id: int,
                          association_type: str) -> Dict:
        """Create an association between items."""
        url = f"{self.base_url}/api/v3/associations"

        payload = {
            'from': {'id': from_id},
            'to': {'id': to_id},
            'type': {'name': association_type}
        }

        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()

    def get_baselines(self, project_id: int) -> List[Dict]:
        """Get baselines for a project."""
        url = f"{self.base_url}/api/v3/projects/{project_id}/baselines"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json()

    def create_baseline(self, tracker_id: int, name: str,
                       description: str) -> Dict:
        """Create a baseline for a tracker."""
        url = f"{self.base_url}/api/v3/trackers/{tracker_id}/baselines"

        payload = {
            'name': name,
            'description': description
        }

        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()

    def run_cbql_query(self, query: str) -> List[Dict]:
        """Run a CBQL (Codebeamer Query Language) query."""
        url = f"{self.base_url}/api/v3/items/query"

        payload = {
            'queryString': query,
            'page': 1,
            'pageSize': 500
        }

        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json().get('items', [])

    def get_traceability_report(self, tracker_id: int,
                               downstream_tracker_id: int) -> Dict:
        """Get traceability report between trackers."""
        url = f"{self.base_url}/api/v3/trackers/{tracker_id}/traceability"
        params = {'downstreamTrackerId': downstream_tracker_id}

        response = self.session.get(url, params=params)
        response.raise_for_status()
        return response.json()


class CodebeamerMetrics:
    """Calculate requirements metrics from Codebeamer."""

    def __init__(self, client: CodebeamerClient):
        self.client = client

    def get_status_distribution(self, tracker_id: int) -> Dict:
        """Get item count by status."""
        result = self.client.get_tracker_items(tracker_id, page_size=1000)
        items = result.get('items', [])

        status_count = {}
        for item in items:
            status = item.get('status', {}).get('name', 'Unknown')
            status_count[status] = status_count.get(status, 0) + 1

        return status_count

    def get_trace_coverage(self, source_tracker: int,
                          target_tracker: int) -> Dict:
        """Calculate traceability coverage."""
        source_items = self.client.get_tracker_items(
            source_tracker, page_size=1000
        ).get('items', [])

        total = len(source_items)
        linked = 0

        for item in source_items:
            associations = self.client.get_associations(item['id'])
            # Check for associations to target tracker
            if any(a.get('to', {}).get('tracker', {}).get('id') == target_tracker
                   for a in associations):
                linked += 1

        coverage = (linked / total * 100) if total > 0 else 0

        return {
            'total': total,
            'linked': linked,
            'coverage_percentage': round(coverage, 2)
        }

    def get_suspect_links(self, tracker_id: int) -> List[Dict]:
        """Get items with suspect links."""
        query = f"tracker.id = {tracker_id} AND suspectLink = true"
        return self.client.run_cbql_query(query)


# Usage
if __name__ == '__main__':
    client = CodebeamerClient(
        base_url='https://codebeamer.example.com/cb',
        username='api_user',
        password='api_password'
    )

    # Get projects
    projects = client.get_projects()
    print(f"Found {len(projects)} projects")

    # Query requirements
    requirements = client.run_cbql_query(
        "tracker.name = 'Software Requirements' AND status = 'Approved'"
    )
    print(f"Found {len(requirements)} approved SW requirements")

    # Check for suspect links
    metrics = CodebeamerMetrics(client)
    suspects = metrics.get_suspect_links(tracker_id=123)
    print(f"Found {len(suspects)} items with suspect links")

CI/CD Integration

Unified Pipeline

// Jenkinsfile for multi-platform RMS integration
pipeline {
    agent any

    parameters {
        choice(
            name: 'RMS_PLATFORM',
            choices: ['jama', 'polarion', 'codebeamer'],
            description: 'Requirements Management System'
        )
    }

    environment {
        RMS_CREDENTIALS = credentials("${params.RMS_PLATFORM}-credentials")
    }

    stages {
        stage('Requirements Validation') {
            steps {
                script {
                    def validator = load "scripts/${params.RMS_PLATFORM}_validator.groovy"
                    def result = validator.runQualityCheck(
                        server: env.RMS_SERVER,
                        project: env.PROJECT_NAME
                    )

                    if (result.failedCount > 0) {
                        unstable("${result.failedCount} requirements failed quality check")
                    }
                }
            }
        }

        stage('Traceability Check') {
            steps {
                script {
                    def checker = load "scripts/${params.RMS_PLATFORM}_trace.groovy"
                    def coverage = checker.getTraceCoverage(
                        server: env.RMS_SERVER,
                        project: env.PROJECT_NAME,
                        sourceType: 'Software Requirement',
                        targetType: 'Test Case'
                    )

                    echo "Trace coverage: ${coverage}%"

                    if (coverage < 95) {
                        unstable("Trace coverage ${coverage}% below 95% threshold")
                    }
                }
            }
        }

        stage('Export Requirements') {
            when {
                branch 'main'
            }
            steps {
                script {
                    sh """
                        python3 scripts/rms_export.py \
                            --platform ${params.RMS_PLATFORM} \
                            --format reqif \
                            --output requirements.reqif
                    """

                    archiveArtifacts 'requirements.reqif'
                }
            }
        }
    }
}

Summary

Jama, Polarion, Codebeamer Overview:

  • Jama Connect: Modern UI, strong API, medical device focus
  • Polarion: Full ALM, Siemens ecosystem, automotive strength
  • Codebeamer: DevOps native, Git integration, agile support
  • Common Features: Traceability, baselines, REST APIs
  • Selection Factors: Industry focus, ecosystem fit, existing tools

Summary

Requirements Management Systems Overview:

  • Core Capabilities: Capture, trace, baseline, report
  • Enterprise Platforms: DOORS Next, Jama, Polarion, Codebeamer
  • Integration Standards: ReqIF, OSLC, REST APIs
  • AI Enhancement: NLP analysis, auto-tracing, quality metrics
  • ASPICE Alignment: SYS.2, SWE.1, SUP.8, SUP.10