Requirement Specification Management - sebiboga/testlink-upgraded GitHub Wiki

Requirement Specification Management (reqSpecMgmt)

Modernized screen: Requirement Specification Management (ASIDE: Requirements Design → Requirement Specification). Tracking issue #571. Legacy reference: lib/requirements/reqSpecListTree.php (feature reqSpecMgmt, ExtJS tree) + reqSpecEdit.php / reqEdit.php popups.

What it does

Replaces the legacy ExtJS tree with a flat, searchable DataTables view of every requirement specification of the active test project, plus a per-specification requirements panel — all as a standalone Dashio page backed by the JSON BFF api/reqspec/index.php.

Specifications table

Column Notes
Doc ID specification document id
Title click to open/close the requirements panel of that spec
Type localized label from req_spec_cfg.type_labels
Reqs number of requirements linked to the spec
Expected expected number of requirements (total_req)
Author login of the latest revision author
Last Update modification timestamp
Actions edit pen + delete (only with modify rights), otherwise a read-only eye icon

Requirements panel

Opened by clicking a specification title:

Column Notes
Doc ID requirement document id
Title click to edit; hover shows plain-text scope excerpt
Status color badge with localized status label (Draft/Review/Rework/Finish/Implemented/Valid/Not testable/Obsolete)
Type localized requirement type
Ver latest version number
Coverage expected coverage
Author version author login
Actions edit pen + delete (modify rights only)

Toolbar

  • Create Spec — modal with Document ID*, Title*, Specification Type (localized domain), Expected number of requirements, Scope (HTML allowed).
  • Create Requirement (in panel) — modal with Doc ID*, Title*, Status, Type, Expected coverage, Scope.
  • Locale switcher (all 10 bundles).

Access & permission

  • ASIDE entry switched in lib/functions/common.php ($actions->reqSpecMgmt → /gui/templates/requirements/reqSpecMgmt.html), same rights split as legacy: viewing needs mgt_view_req or mgt_modify_req; every write needs mgt_modify_req. Without rights the BFF answers HTTP 403 and the UI renders read-only.
  • Unauthenticated API calls get HTTP 401.

Behavior parity notes

  • Create attaches the spec to the test project node itself (same as the legacy root-level create); orphaned parent 0 would make the spec invisible to every tree walk (see #569 fix inside the BFF).
  • Duplicate document ids inside one spec are rejected server-side with the legacy message ("Duplicated document id …").
  • Spec delete uses delete_deep() — removes contained requirements, versions and revisions, exactly like legacy reqSpecCommands::doDelete.
  • Requirement delete removes ALL versions (requirement_mgr::delete()), like the legacy GUI action.

Main screen with specs table and requirements panel

Create Specification modal

Delete confirmation

Requirements Filter Panel (#1025)

The 2.0.1 rewrite originally dropped the entire filter panel that 1.9.20 provides through gui/templates/dashio/include/inc_filter_panel.tpl + tlRequirementFilterControl and get_filtered_req_map() (lib/functions/treeMenu.inc.php:1753-1889). It has been ported end to end.

Controls

Document ID · Title · Status · Requirement Type · Req. Spec. Type · Expected No. of Testcases · Has Relation of Type · Test Case ID · project Custom Fields (opt-in). Plus Apply, Reset Filters, Simple / Advanced Filters and the "Update list after every operation" setting. Advanced turns the single selects into multi-selects; Simple warns before trimming a multi-selection.

Apply is authoritative — typing alone does not re-query, matching the legacy button-driven panel.

Requirements filter panel with the Custom Field filters shown

Legacy semantics preserved

  • Any disables the filter. 0 anywhere in a multi-select returns null for that filter, i.e. unfiltered — not "match nothing".
  • A bare Test Case prefix is not a filter. filter_tc_id=REQA- is treated as "not filled in"; REQA-101 is a real filter.
  • Expected coverage 0 is not a filter; only a value > 0 applies.
  • Subtree pruning. A specification whose own plus subtree requirements no longer match disappears from the list, exactly as legacy did.
  • Relation sides. 3 / "related to" is an equal relation and matches either side of req_relations; 2_source / 2_destination are directional. Equal relations are published under the bare relation id, which is what legacy init_relation_type_select() sends.

BFF additions

GET ?action=options&tproject_id=N   -> also tcPrefix, childRequirementsManagement,
                                       expectedCoverageManagement, filterCFields,
                                       relationTypes, reqStatuses, reqTypes, specTypes
GET ?action=specs&tproject_id=N[&filter_*] -> filtered spec list
GET ?action=reqs&spec_id=N&tproject_id=N[&filter_*] -> filtered requirements

filter_doc_id, filter_title, filter_status, filter_type, filter_spec_type, filter_relation, filter_coverage, filter_tc_id and filter_cf_<fieldId> (comma-separated values allowed). All values are escaped with $db->prepare_string(); an injection probe returns 0 rows with no error.

Deliberate deviation

Filtering is evaluated on the latest spec revision / requirement version. Legacy matched any revision, which on the modern tables (built from the latest revision) could return rows the table never shows.

i18n

20 new rsf.* keys in all 10 locale bundles (de, en, es, fr, it, ja, pt, ro, ru, zh).

i18n

42 new keys (rs.*) added to all locale bundles: en, de, es, fr, it, ja, pt, ro, ru, zh. Every label, column header, modal title and message is translated; validated with python3 -m json.tool.

BFF endpoints (api/reqspec/index.php)

GET  ?action=options&tproject_id=N     -> domains, defaults, rights, project name
GET  ?action=specs&tproject_id=N       -> specs list (latest revision + req counts)
POST ?action=create_spec               {tproject_id,doc_id,title,type,total_req,scope}
POST ?action=update_spec&id=N          {…}
POST ?action=delete_spec&id=N&tproject_id=N
GET  ?action=reqs&spec_id=N&tproject_id=N -> requirements of a spec (latest versions)
POST ?action=create_req                {tproject_id,spec_id,req_doc_id,title,status,type,expected_coverage,scope}
POST ?action=update_req&id=N           {…}   (applies to latest version)
POST ?action=delete_req&id=N&tproject_id=N

Session-based auth; JSON I/O; per-request right checks (mgt_view_req / mgt_modify_req).

Bug found & fixed during testing

  • #572 — requirement_mgr::delete() emitted a PHP 8 E_WARNING ("Trying to access array offset on null") on every requirement deletion because $notifyOn is initialized null and only set via setNotifyOn(). Fixed with an is_array() guard (behavior unchanged). Verified clean Event Viewer after the fix.

Expected-Coverage Configuration Gate (#1516)

The Create/Edit Requirement modal now honours the two legacy expected-coverage configuration gates, mirroring the fix applied to the standalone reqEdit screen in #1376:

  1. Global gate — req_cfg->expected_coverage_management (config.inc.php:1666, default ENABLED). When set to DISABLED the Expected Coverage field is hidden entirely and the saved value is forced to 0.
  2. Per-type gate — req_cfg->type_expected_coverage (cfg/const.inc.php:759). By default, type "1" (Informational) is disabled. For a disabled type the field is hidden and the stored value is forced to 0.

The BFF (api/reqspec/index.php) exposes expectedCoverageManagement (bool) and expectedCoverageByType (map) in the options action. Save flows (create_req / update_req) persist through effectiveExpectedCoverage(), returning 0 when either gate blocks the field.

Testing

Suite 46 in tmp/TLU_Test_Cases.md: 16 / 16 PASS — CRUD round trip, duplicate-id validation, permission paths (admin/guest/anonymous), Romanian locale render, DB orphan check after deletes, Event Viewer check. Suite for #1516: 12/12 PASS. Suite for #1025 (filter panel): 40/40 PASS — 22 BFF filter cases across both actions, the legacy Any / prefix-only / equal-relation / subtree-pruning rules, an SQLi probe, 7 live browser interactions, clean console, 0 new Event Viewer Error/Warning rows.

⚠️ **GitHub.com Fallback** ⚠️