Design traceability within SpiraTeam - how?

Monday, April 20, 2026
Avatar

For a project in regulated environment I need to create a custom report showing that the requirements are propagating through software design and software architecture.

To achieve this, in the software Requirements Artifact area I've created the following structure:

SRS
   Requirement 1 
   Requirement 2
   Requirement 3
SAD
   Architecture 1
   Architecture 2
SDD
   Design 1
   Design 2
   Design 3
   Design 4

The Requirements artifacts got Component set to "Requirements", Architecture ones are "Architecture" and Design ones are set to "Design".

 

This is the report I want to get in the end:

RequirementsArchitectureDesign
Requirement 1Architecture 1Design 1
Design 2
Requirement 2 Design 3
Requirement 3Architecture 2Design 4

 

This way I could easily check if there is a gap in design traceability (it would be even nicer if I could paint the empy cell in a different colour, but can live without it).

Question -how can I achieve that? I understand that I need somehow to access the component record of the linked artifact, but not quite sure how?  

Can you please help me to change the code below so that it'll work as intended?

<td>               
     <xsl:value-of select="Name"/>             
</td>             
<td>               
     <xsl:if test="Requirements/ArtifactLink">                 
          <xsl:for-each select="Requirements/ArtifactLink">                     
               <xsl:if test="position() > 1 and ArtifactLink/Component = Architecture">, <br /> </xsl:if>                   
               <xsl:value-of select="ArtifactLinkTypeName"/>                 
          </xsl:for-each>               
     </xsl:if>             
</td>             
<td>               
     <xsl:if test="Requirements/ArtifactLink">                 
          <xsl:for-each select="Requirements/ArtifactLink">                     
               <xsl:if test="position() > 1 and ArtifactLink/Component = Design">, <br /> </xsl:if>                   
               <xsl:value-of select="ArtifactLinkTypeName"/>                 
          </xsl:for-each>               
     </xsl:if>             
</td>     

 

7 Replies
Monday, April 20, 2026
Avatar
re: inmarsys Monday, April 20, 2026

Hello,

I think this Knowledge Base article should help you to achieve this:

Creating a Custom Report with Grouped Headings

 

Regards,
Victoria -

Monday, April 20, 2026
Avatar
re: inflectra.Victoria Monday, April 20, 2026

Hi Victoria,

Thank you for your response.

I've looked at the KB but I am not sure if it'll actually solve the issue as I need to access not the Component itself but component of each linked requirement. Or, in pseudo-code:

FOR AllRequirements
   PRINT RequirementName in Column1
   IF LinkedRequirements != 0 THEN
      READ LinkedRequirement
      IF LinkedRequirement.Component = "Architecture" PRINT LinkedRequirement.Name in Column2
      IF LinkedRequirement.Component = "Design" PRINT LinkedRequirement.Name in Column3
   ENDIF
ENDFOR

Or am I missing something?

Wednesday, April 22, 2026
Avatar
re: inmarsys Monday, April 20, 2026

Hello,

I think this article will help you to achieve what you're trying to get: Building a Component-Based Traceability Matrix in Spira Using Custom ESQL and XSLT

 

Regards,
Victoria -

Friday, April 24, 2026
Avatar
re: inflectra.Victoria Wednesday, April 22, 2026

Hi Victoria, 

Thank you very much for your help.

I've created the report as per you KB and the results aren't quite what I was expecting.

Expectations:
 

RequirementArchitectureDesign
SRS    
Requirement 1Architecture 1Design 1,
Design 2,
Design 4
    
Requirement 2Architecture 1,
Architecture 2
Design 1,
Design 3,
Design 4
    
Requirement 3Architecture 2Design 3,
Design 4
  

 

Report output:

RequirementArchitectureDesign
SRS  
Requirement 1Architecture 1Design 1,
Design 2
Requirement 2 Design 3,
Design 4
Requirement 3  
SAD  
Architecture 1 Design 1,
Design 2
Architecture 2Architecture 1 
SDD  
Design 1Architecture 2 
Design 2  
Design 3Architecture 1 
Design 4Architecture 2 

 

To make it clear, the associations are as follows:
All requirements in SRS section have component set to "Requirements"), in SAD to "Architecture" and in SDD to "Design"
 

Requirement nameAssociated with (Related to)
SRSnone, just a header
Requirement 1Architecture 1
Design 1
Design 2
Design 4
Requirement 2Architecture 1
Architecture2 
Design 1
Design 3
Design 4
Requirement 3Architecture2 
Design 3
Design 4
SADnone, just a header
Architecture 1Requirement 1
Requirement 2
Architecture 2
Design 1
Design 2
Design 4
Architecture 2Requirement 2
Requirement 3
Architecture 1
Design 1
Design 3
Design 4
SDDnone, just a header
Design 1Requirement 1
Requirement 2
Architecture 1
Architecture2
Design 2Requirement 1
Architecture 1
Design 3Requirement 2
Requirement 3
Architecture 2
Design 4Requirement 1
Requirement 2
Requirement 3
Architecture 1
Architecture2
  

 

 
  
  

 

21 hours 36 minutes ago
Avatar
re: inmarsys Friday, April 24, 2026

Right, spent some time with Grok and Claude and here's the solution. 

The issue is that the KB is assuming that the associations are ALWAYS done from the same end (from Requirements to Architecture and Design). If any of the artifacts are linked other way round (which is normal), then it won't work.

Here's the updated ESQL:

SELECT 
  RQ.REQUIREMENT_ID,
  RQ.NAME AS REQUIREMENT_NAME,
  RQ.COMPONENT_NAME AS BASE_COMPONENT,
  LR.NAME AS LINKED_NAME,
  LR.COMPONENT_NAME AS LINKED_COMPONENT
FROM SpiraTestEntities.R_Requirements AS RQ
LEFT JOIN SpiraTestEntities.R_ArtifactAssociations AS AA 
  ON AA.SOURCE_ARTIFACT_TYPE_ID = 1 
  AND AA.DEST_ARTIFACT_TYPE_ID = 1
  AND (
    (RQ.REQUIREMENT_ID = AA.SOURCE_ARTIFACT_ID)
    OR
    (RQ.REQUIREMENT_ID = AA.DEST_ARTIFACT_ID)
  )
LEFT JOIN SpiraTestEntities.R_Requirements AS LR 
  ON LR.IS_DELETED = False
  AND LR.COMPONENT_NAME != 'Requirements'
  AND (
    (AA.DEST_ARTIFACT_ID = LR.REQUIREMENT_ID AND RQ.REQUIREMENT_ID = AA.SOURCE_ARTIFACT_ID)
    OR
    (AA.SOURCE_ARTIFACT_ID = LR.REQUIREMENT_ID AND RQ.REQUIREMENT_ID = AA.DEST_ARTIFACT_ID)
  )
WHERE RQ.PROJECT_ID = ${ProjectId}
  AND RQ.IS_DELETED = False
  AND RQ.COMPONENT_NAME = 'Requirements'

The XSLT shall be updated too:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:key name="ReqGroup" match="*[REQUIREMENT_ID]" use="REQUIREMENT_ID" />
  
  <!-- Only treat non-Requirements components as column headers -->
  <xsl:key name="ComponentGroup" 
    match="*[string-length(LINKED_COMPONENT) &gt; 0 and LINKED_COMPONENT != 'Requirements']" 
    use="LINKED_COMPONENT" />

  <xsl:template match="/">
    <table class="DataGrid" style="width:100%">
      
      <tr>
        <th>Requirement Name</th>
        
        <xsl:for-each select="//*[string-length(LINKED_COMPONENT) &gt; 0 and LINKED_COMPONENT != 'Requirements']
                                 [generate-id() = generate-id(key('ComponentGroup', LINKED_COMPONENT)[1])]">
          <xsl:sort select="LINKED_COMPONENT" />
          <th>
            <xsl:value-of select="LINKED_COMPONENT"/>
          </th>
        </xsl:for-each>
      </tr>

      <xsl:for-each select="//*[REQUIREMENT_ID][generate-id() = generate-id(key('ReqGroup', REQUIREMENT_ID)[1])]">
        
        <xsl:variable name="CurrentReqID" select="REQUIREMENT_ID" />
        
        <tr>
          <td>
            <xsl:value-of select="REQUIREMENT_NAME"/>
          </td>

          <xsl:for-each select="//*[string-length(LINKED_COMPONENT) &gt; 0 and LINKED_COMPONENT != 'Requirements']
                                   [generate-id() = generate-id(key('ComponentGroup', LINKED_COMPONENT)[1])]">
            <xsl:sort select="LINKED_COMPONENT" />
            
            <xsl:variable name="CurrentColComponent" select="LINKED_COMPONENT" />

            <td>
              <xsl:for-each select="key('ReqGroup', $CurrentReqID)[LINKED_COMPONENT = $CurrentColComponent]">
                <xsl:if test="position() &gt; 1">, <br /></xsl:if>
                <xsl:value-of select="LINKED_NAME"/>
              </xsl:for-each>
            </td>
            
          </xsl:for-each>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>

</xsl:stylesheet>

 

As a result, the following report will be generated (note: not all of the requirements in the project got associations, to test the Gap Analysis functionality)


 
Requirement NameArchitectureDesign
SRS  
Requirement 1Architecture 1Design 1,
Design 2,
Design 4
Requirement 2Architecture 1,
Architecture 2
Design 3,
Design 4,
Design 1
Requirement 3Architecture 2Design 3,
Design 4
Requirement 4

Architecture 2

Design 4,
Design 1,
Design 2
Requirement 5Architecture 1 
Requirement 6  

 

 

 

21 hours 35 minutes ago
Avatar
re: inmarsys Wednesday, April 29, 2026

Maybe the KB should be updated too?

6 hours 8 minutes ago
Avatar
re: inmarsys Wednesday, April 29, 2026

Hello,

Thank you very much for your valuable input! It is very helpful indeed.

 

Regards,
Victoria -

Spira Helps You Deliver Quality Software, Faster and With Lower Risk

And if you have any questions, please email or call us at +1 (202) 558-6885

 

Statistics
  • Started: Monday, April 20, 2026
  • Last Reply: 6 hours 8 minutes ago
  • Replies: 7
  • Views: 143