Work on requirements management

This commit is contained in:
Sylvain Schneider
2026-03-13 10:23:40 +01:00
parent 16787ac642
commit 25fc14d6bd
9 changed files with 259 additions and 65 deletions

View File

@@ -1,26 +1,51 @@
#pragma once #pragma once
#include <chrono>
#include <dbus/api/api.h> #include <dbus/api/api.h>
#include <sdi_toolBox/generic/uuid.h>
namespace api::requirement namespace api::requirement
{ {
//-------------------------------------------------------------- //--------------------------------------------------------------
using TimePoint = std::chrono::system_clock::time_point;
//--------------------------------------------------------------
enum class Status
{
Draft, // The requirement is in draft state and has not been finalized
InReview, // The requirement is currently being reviewed by stakeholders
Approved, // The requirement has been approved and is ready for implementation
Rejected // The requirement has been rejected and will not be implemented
};
//--------------------------------------------------------------
struct Metadata
{
std::string uuid; // Unique identifier for the requirement, generated automatically
std::string id; // Unique identifier for the requirement, provided by the user (e.g., "REQ-001")
std::string author; // Name of the person who created the requirement
TimePoint created_at; // Creation timestamp
TimePoint updated_at; // Last update timestamp
};
//--------------------------------------------------------------
struct Details
{
std::string name; // Short name or title of the requirement
std::string description; // Detailed description of the requirement
std::string acceptance_criteria; // Criteria that must be met for the requirement to be considered complete
bool is_smart; // SMART indicator (Specific, Measurable, Achievable, Relevant, Time-bound)
};
//--------------------------------------------------------------
struct Classification
{
std::string type; // Type of the requirement (e.g., "Functional", "Non-Functional", "Performance", etc.)
std::string category; // Category of the requirement (e.g., "UI", "Backend", "Security", etc.)
int priority; // Priority level of the requirement (e.g., 1 for highest priority, 5 for lowest)
Status status; // Current status of the requirement (e.g., "Draft", "In Review", "Approved", "Rejected", etc.)
};
//--------------------------------------------------------------
struct Requirement struct Requirement
{ {
std::string uuid; Metadata metadata; // General information about the requirement
std::string parent_uuid; Details details; // Detailed information about the requirement
std::string id; Classification classification; // Classification information about the requirement
std::string type;
std::string name;
std::string description;
std::vector<Requirement> sub_requirements;
/* Default constructor */
Requirement()
{
uuid = sdi_toolBox::generic::UuidGenerator::uuid_v4(); // Generate a unique UUID for the requirement
}
}; };
//-------------------------------------------------------------- //--------------------------------------------------------------
@@ -37,11 +62,11 @@ struct RequirementEvent : dBus::api::DefaultData<dBus::makeID("requirement.requi
[[nodiscard]] std::string toString() const override [[nodiscard]] std::string toString() const override
{ {
return std::format("RequirementEvent: id={}, name={}, subRequirementsCount={}", // return std::format("RequirementEvent: id={}, name={}, subRequirementsCount={}",
requirementData.id, // requirementData.id,
requirementData.name, // requirementData.name,
requirementData.description, // requirementData.description);
requirementData.sub_requirements.size()); return "";
} }
}; };
//-------------------------------------------------------------- //--------------------------------------------------------------

View File

@@ -0,0 +1,73 @@
#include "RequirementManager.h"
#include "requirementItem.h"
#include <sdi_toolBox/generic/uuid.h>
using namespace std;
using namespace core::project;
//--------------------------------------------------------------
/* Default constructor */
RequirementManager::RequirementManager()
{
m_rootRequirement = make_shared<RequirementItem>(*this); // Create the root requirement item and set it as the root requirement
}
//--------------------------------------------------------------
/* Get the root requirement */
RequirementManager::RequirementItemPtr RequirementManager::getRootRequirement() const
{
return m_rootRequirement; // Return the root requirement item pointer
}
//--------------------------------------------------------------
/* Get the vector of child requirement items of the root requirement */
std::vector<RequirementManager::RequirementItemPtr> RequirementManager::getRootRequirementChild() const
{
return m_rootRequirement->getChildren(); // Return the vector of child requirement items of the root requirement
}
//--------------------------------------------------------------
/* Get a requirement by its UUID */
RequirementManager::RequirementItemPtr RequirementManager::getRequirement(const std::string &uuid) const
{
if (m_requirementsByUuid.contains(uuid))
return m_requirementsByUuid.at(uuid); // Return the requirement item pointer if found in the map
return {}; // Return nullptr if the requirement with the given UUID is not found
}
//--------------------------------------------------------------
/* Get the vector of child requirement items of a requirement by its UUID */
std::vector<RequirementManager::RequirementItemPtr> RequirementManager::getRequirementChildren(const std::string &uuid) const
{
if (m_requirementsByUuid.contains(uuid))
return m_requirementsByUuid.at(uuid)->getChildren(); // Return the vector of child requirement items if the requirement with the given UUID is found in the map
return {}; // Return an empty vector if the requirement with the given UUID is not found
}
//--------------------------------------------------------------
/* Generate a unique UUID string that is not already registered in the manager's internal map */
std::string RequirementManager::generateUniqueUuid() const
{
std::string uuid;
do
{
uuid = sdi_toolBox::generic::UuidGenerator::uuid_v4(); // Generate a random UUID v4 string
} while (isRequirementRegistered(uuid)); // Check if the generated UUID is already registered
return uuid; // Return the unique UUID string
}
//--------------------------------------------------------------
/* Check if a requirement with the given UUID is registered in the manager's internal map */
bool RequirementManager::isRequirementRegistered(const std::string &uuid) const
{
return m_requirementsByUuid.contains(uuid);
}
//--------------------------------------------------------------
/* Register a requirement in the manager's internal map for quick lookup by UUID */
void RequirementManager::registerRequirement(const RequirementItemPtr &requirement)
{
m_requirementsByUuid[requirement->metadata.uuid] = requirement;
}
//--------------------------------------------------------------
/* Unregister a requirement from the manager's internal map */
void RequirementManager::unregisterRequirement(const std::string &uuid)
{
m_requirementsByUuid.erase(uuid);
}
//--------------------------------------------------------------

View File

@@ -0,0 +1,42 @@
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
namespace core::project
{
class RequirementItem;
//--------------------------------------------------------------
class RequirementManager
{
using RequirementItemPtr = std::shared_ptr<RequirementItem>;
public:
RequirementManager(); // Default constructor
virtual ~RequirementManager() = default; // Default destructor
RequirementManager(const RequirementManager &obj) = delete; // Copy constructor
RequirementManager(RequirementManager &&obj) noexcept = delete; // Move constructor
RequirementManager &operator=(const RequirementManager &obj) = delete; // Copy assignment operator
RequirementManager &operator=(RequirementManager &&obj) noexcept = delete; // Move assignment operator
[[nodiscard]] RequirementItemPtr getRootRequirement() const; // Get the root requirement
[[nodiscard]] std::vector<RequirementItemPtr> getRootRequirementChild() const; // Get the vector of child requirement items of the root requirement
[[nodiscard]] RequirementItemPtr getRequirement(const std::string &uuid) const; // Get a requirement by its UUID
[[nodiscard]] std::vector<RequirementItemPtr> getRequirementChildren(const std::string &uuid) const; // Get the vector of child requirement items of a requirement by its UUID
// Requirement management functions
[[nodiscard]] std::string generateUniqueUuid() const; // Generate a unique UUID string that is not already registered in the manager's internal map
[[nodiscard]] bool isRequirementRegistered(const std::string &uuid) const; // Check if a requirement with the given UUID is registered in the manager's internal map
void registerRequirement(const RequirementItemPtr &requirement); // Register a requirement in the manager's internal map for quick lookup by UUID
void unregisterRequirement(const std::string &uuid); // Unregister a requirement from the manager's internal map
protected:
RequirementItemPtr m_rootRequirement; // Root requirement of the current project
std::unordered_map<std::string, RequirementItemPtr> m_requirementsByUuid; // Map of requirement UUID to requirement pointer for quick lookup
private:
};
//--------------------------------------------------------------
} // namespace core::project

View File

@@ -1,11 +0,0 @@
#include "projectData.h"
using namespace std;
using namespace core::project;
//--------------------------------------------------------------
/* Get the root requirement */
ProjectData::RequirementPtr ProjectData::getRootRequirement()
{
return m_rootRequirement;
}
//--------------------------------------------------------------

View File

@@ -1,29 +0,0 @@
#pragma once
#include <api/requirement.h>
#include <memory>
namespace core::project
{
//--------------------------------------------------------------
class ProjectData
{
using RequirementPtr = std::shared_ptr<api::requirement::Requirement>;
public:
ProjectData() = default; // Default constructor
virtual ~ProjectData() = default; // Default destructor
ProjectData(const ProjectData &obj) = delete; // Copy constructor
ProjectData(ProjectData &&obj) noexcept = delete; // Move constructor
ProjectData &operator=(const ProjectData &obj) = delete; // Copy assignment operator
ProjectData &operator=(ProjectData &&obj) noexcept = delete; // Move assignment operator
RequirementPtr getRootRequirement(); // Get the root requirement
protected:
RequirementPtr m_rootRequirement; // Root requirement of the current project
private:
};
//--------------------------------------------------------------
} // namespace core::project

View File

@@ -1,6 +1,6 @@
#include "projectManager.h" #include "projectManager.h"
#include "projectData.h" #include "RequirementManager.h"
using namespace std; using namespace std;
using namespace core::project; using namespace core::project;
@@ -117,7 +117,7 @@ void ProjectManager::on_projectOperationEvent(const ProjectOperationMessage_ptr
/* Process a file creation event */ /* Process a file creation event */
void ProjectManager::on_projectCreateFileEvent(const ProjectOperationMessage_ptr &message) void ProjectManager::on_projectCreateFileEvent(const ProjectOperationMessage_ptr &message)
{ {
m_projectData = make_shared<ProjectData>(); m_requirementManager = make_shared<RequirementManager>();
message->responsePromise.set_value(); message->responsePromise.set_value();
} }
@@ -165,7 +165,7 @@ void ProjectManager::on_projectSaveFileEvent(const ProjectOperationMessage_ptr &
/* Process a file close event */ /* Process a file close event */
void ProjectManager::on_projectCloseFileEvent(const ProjectOperationMessage_ptr &message) void ProjectManager::on_projectCloseFileEvent(const ProjectOperationMessage_ptr &message)
{ {
m_projectData = {}; m_requirementManager = {};
message->responsePromise.set_value(); message->responsePromise.set_value();
} }
//-------------------------------------------------------------- //--------------------------------------------------------------

View File

@@ -8,11 +8,11 @@
namespace core::project namespace core::project
{ {
class ProjectData; class RequirementManager;
//-------------------------------------------------------------- //--------------------------------------------------------------
class ProjectManager : public dBus::Node class ProjectManager : public dBus::Node
{ {
using ProjectPtr = std::shared_ptr<ProjectData>; using RequirementManagerPtr = std::shared_ptr<RequirementManager>;
public: public:
ProjectManager() = delete; // Default constructor ProjectManager() = delete; // Default constructor
@@ -27,7 +27,7 @@ class ProjectManager : public dBus::Node
protected: protected:
std::filesystem::path m_filePath; // Path of the currently opened project file std::filesystem::path m_filePath; // Path of the currently opened project file
ProjectPtr m_projectData; // Current project data, including the root requirement and all its sub-requirements RequirementManagerPtr m_requirementManager; // Pointer to the requirement manager of the current project
private: private:
void openFile(const std::filesystem::path &filePath); // Open a project file and load the requirements void openFile(const std::filesystem::path &filePath); // Open a project file and load the requirements

View File

@@ -0,0 +1,56 @@
#include "requirementItem.h"
#include "RequirementManager.h"
using namespace std;
using namespace core::project;
//--------------------------------------------------------------
/* Constructor */
RequirementItem::RequirementItem(RequirementManager &manager, const std::shared_ptr<RequirementItem> &parentRequirement)
: m_requirementManager(manager)
{
// Initialization
metadata.uuid = m_requirementManager.generateUniqueUuid(); // Generate a unique UUID for this requirement item
m_parent = parentRequirement; // Set the m_parent requirement item
// Register this requirement item in the manager's internal map
m_requirementManager.registerRequirement(shared_from_this());
}
//--------------------------------------------------------------
/* Append a child requirement item to this requirement item */
void RequirementItem::appendChild(const api::requirement::Requirement &child)
{
// Create a new requirement item for the child requirement and set this requirement item as its m_parent
const auto childItem = make_shared<RequirementItem>(m_requirementManager);
childItem->metadata = child.metadata;
childItem->details = child.details;
childItem->classification = child.classification;
// Prepare requirement links
childItem->metadata.uuid = m_requirementManager.generateUniqueUuid(); // Generate a unique UUID for this requirement item
childItem->m_parent = shared_from_this();
// Register this requirement item in the manager's internal map
m_requirementManager.registerRequirement(childItem);
}
//--------------------------------------------------------------
/* Remove a child requirement item from this requirement item by its UUID */
void RequirementItem::removeChild(const std::string &childUuid)
{
// Unregister the child requirement item from the manager's internal map
m_requirementManager.unregisterRequirement(childUuid);
// Find the child requirement item with the given UUID
const auto it = ranges::find_if(m_children,
[&childUuid](const RequirementItemPtr &child)
{ return child->metadata.uuid == childUuid; });
if (it != m_children.end())
m_children.erase(it); // Remove the child requirement item from the vector of children
}
//--------------------------------------------------------------
/* Get the vector of child requirement items of this requirement item */
std::vector<RequirementItem::RequirementItemPtr> RequirementItem::getChildren() const
{
return m_children;
}
//--------------------------------------------------------------

View File

@@ -0,0 +1,38 @@
#pragma once
#include <api/requirement.h>
#include <memory>
#include <vector>
namespace core::project
{
class RequirementManager;
//--------------------------------------------------------------
class RequirementItem : public std::enable_shared_from_this<RequirementItem>
, public api::requirement::Requirement
{
using RequirementItemPtr = std::shared_ptr<RequirementItem>;
public:
RequirementItem() = delete; // Default constructor
virtual ~RequirementItem() = default; // Default destructor
RequirementItem(const RequirementItem &obj) = delete; // Copy constructor
RequirementItem(RequirementItem &&obj) noexcept = delete; // Move constructor
RequirementItem &operator=(const RequirementItem &obj) = delete; // Copy assignment operator
RequirementItem &operator=(RequirementItem &&obj) noexcept = delete; // Move assignment operator
explicit RequirementItem(RequirementManager &manager, // Constructor
const std::shared_ptr<RequirementItem> &parentRequirement = nullptr);
// Children management functions
void appendChild(const api::requirement::Requirement &child); // Append a child requirement item to this requirement item
void removeChild(const std::string &childUuid); // Remove a child requirement item from this requirement item by its UUID
[[nodiscard]] std::vector<RequirementItemPtr> getChildren() const; // Get the vector of child requirement items of this requirement item
protected:
RequirementManager &m_requirementManager; // Reference to the requirement manager that owns this requirement item
std::weak_ptr<RequirementItem> m_parent; // Weak pointer to the m_parent requirement item (nullptr for root)
std::vector<RequirementItemPtr> m_children; // Vector of shared pointers to child requirement items
};
//--------------------------------------------------------------
} // namespace core::project