Files
Masterarbeit/Versuche/Versuch 02/Ergenisse/software/SwRS_DataModel.md

779 lines
24 KiB
Markdown

# Software Data Model Specification
## Centron Enterprise Application - Data Architecture and Implementation
**Document Control**
- **Project**: Centron Enterprise Application
- **Version**: 1.0
- **Date**: 2025-09-30
- **Standard**: ISO/IEC/IEEE 29148:2018
- **Classification**: Software Data Model and Schema Documentation
---
## Table of Contents
1. [Data Model Overview](#1-data-model-overview)
2. [Entity Framework Architecture](#2-entity-framework-architecture)
3. [Domain Entity Categories](#3-domain-entity-categories)
4. [Database Schema Implementation](#4-database-schema-implementation)
5. [NHibernate Mapping Configuration](#5-nhibernate-mapping-configuration)
6. [Data Relationships and Constraints](#6-data-relationships-and-constraints)
7. [Data Validation and Business Rules](#7-data-validation-and-business-rules)
8. [Data Flow and Transformation](#8-data-flow-and-transformation)
---
## 1. Data Model Overview
### 1.1 Data Architecture Statistics
- **Total Entity Files**: 1,145 entity classes
- **NHibernate Mappings**: 956 FluentNHibernate mapping files
- **Domain Categories**: 268 business domain categories
- **Database Tables**: Estimated 800+ tables
- **Entity Relationships**: Complex web of one-to-many, many-to-many associations
### 1.2 Data Architecture Principles
**SW-DATA-ARCH-001**: The software SHALL implement domain-driven design principles
- **Entity Aggregates**: Related entities grouped into aggregate roots
- **Bounded Contexts**: Clear separation between business domains
- **Value Objects**: Immutable objects representing domain concepts
**SW-DATA-ARCH-002**: The software SHALL use standardized entity base classes
- **Base Entity**: `BaseEntity` with primary key I3D
- **Persisted Entity**: `PersistedEntity` with audit trail fields
- **Soft Delete Pattern**: IsDeleted flag for logical deletion
### 1.3 Data Storage Technologies
| Technology | Purpose | Implementation Location |
|------------|---------|------------------------|
| SQL Server | Primary database | Production and development |
| NHibernate | ORM Framework | `src/backend/Centron.DAO/` |
| FluentNHibernate | Mapping Configuration | `src/backend/Centron.DAO/Mappings/` |
| Entity Framework | Limited use | Some specialized components |
---
## 2. Entity Framework Architecture
### 2.1 Base Entity Hierarchy
**SW-ENT-001**: Base Entity Structure
```csharp
// File: src/backend/Centron.Entities/BaseEntity.cs
public abstract class BaseEntity
{
public virtual int I3D { get; set; } // Primary Key
}
// File: src/backend/Centron.Entities/PersistedEntity.cs
public class PersistedEntity : BaseEntity
{
public virtual DateTime? CreatedDate { get; set; }
public virtual DateTime? ChangedDate { get; set; }
public virtual int? CreatedByI3D { get; set; }
public virtual int? ChangedByI3D { get; set; }
public virtual bool IsDeleted { get; set; }
public virtual DateTime? DeletedDate { get; set; }
public virtual int? DeletedByI3D { get; set; }
}
```
**Design Requirements**:
- SW-ENT-001.1: All entities MUST inherit from BaseEntity
- SW-ENT-001.2: Business entities SHOULD inherit from PersistedEntity
- SW-ENT-001.3: Primary keys MUST use I3D naming convention
- SW-ENT-001.4: Foreign keys MUST end with I3D suffix
### 2.2 Entity Naming Conventions
**SW-ENT-002**: Naming Standard Implementation
- **Entity Classes**: PascalCase (e.g., `Account`, `AccountAddress`)
- **Properties**: PascalCase (e.g., `Name`, `CreatedDate`)
- **Foreign Keys**: EntityNameI3D (e.g., `AccountI3D`, `EmployeeI3D`)
- **Collection Properties**: Plural names (e.g., `Addresses`, `AccountTypes`)
**File Organization**:
- **Entities**: `src/backend/Centron.Entities/Entities/{Domain}/{EntityName}.cs`
- **Mappings**: `src/backend/Centron.DAO/Mappings/{Domain}/{EntityName}Maps.cs`
---
## 3. Domain Entity Categories
### 3.1 Account Management Domain
**SW-DOM-001**: Account Entity Model
- **Root Entity**: `Account` (src/backend/Centron.Entities/Entities/Accounts/Account.cs)
- **Related Entities**: 45+ account-related entity classes
**Core Account Entities**:
```csharp
// Account aggregate root
public class Account : BaseEntity, IAccount
{
public virtual int Number { get; set; }
public virtual string Name { get; set; }
public virtual string Matchcode { get; set; }
public virtual string Email { get; set; }
public virtual bool IsActive { get; set; }
public virtual bool IsLocked { get; set; }
// Navigation properties
public virtual IList<AccountAddress> Addresses { get; set; }
public virtual IList<AccountTypeToAccount> AccountTypes { get; set; }
}
// Account address value object
public class AccountAddress : PersistedEntity
{
public virtual int AccountI3D { get; set; }
public virtual string Street { get; set; }
public virtual string PostalCode { get; set; }
public virtual string City { get; set; }
public virtual int? CountryI3D { get; set; }
public virtual bool IsMainAddress { get; set; }
// Navigation properties
public virtual Account Account { get; set; }
public virtual IList<AccountAddressContact> Contacts { get; set; }
}
```
**Account Domain Entities**:
| Entity | Purpose | Key Relationships |
|--------|---------|------------------|
| Account | Core account data | → AccountAddress, AccountType |
| AccountAddress | Address information | → Account, Country, Contacts |
| AccountAddressContact | Contact persons | → AccountAddress, Employee |
| AccountContract | Service contracts | → Account, ContractKind |
| AccountType | Account classification | ← AccountTypeToAccount |
| AccountActivity | Activity logging | → Account, Employee |
### 3.2 Sales and Receipt Domain
**SW-DOM-002**: Receipt Entity Model
- **Entity Count**: 150+ receipt-related entities
- **Root Entities**: Receipt types (Offer, Order, Invoice, DeliveryList)
- **Complex Hierarchy**: Receipt → ReceiptItem → ReceiptItemArticle
**Receipt Entity Hierarchy**:
```csharp
// Abstract receipt base
public abstract class ReceiptBase : PersistedEntity, IReceiptBase
{
public virtual int Number { get; set; }
public virtual DateTime? CreatedAt { get; set; }
public virtual decimal CurrencyFactor { get; set; }
public virtual string Comment { get; set; }
public virtual ReceiptState State { get; set; }
// Customer relationship
public virtual int? CustomerI3D { get; set; }
public virtual Customer Customer { get; set; }
// Receipt items
public virtual IList<ReceiptItemBase> Items { get; set; }
}
// Specific receipt types
public class Offer : ReceiptBase
{
public virtual DateTime? ValidUntil { get; set; }
public virtual bool IsConverted { get; set; }
}
public class Order : ReceiptBase
{
public virtual DateTime? DesiredDeliveryDate { get; set; }
public virtual bool IsUrgent { get; set; }
}
public class Invoice : ReceiptBase
{
public virtual DateTime? DueDate { get; set; }
public virtual decimal TotalAmount { get; set; }
public virtual InvoiceType Type { get; set; }
}
```
**Receipt Domain Statistics**:
- **Receipt Types**: 8 main types (Offer, Order, Invoice, etc.)
- **Receipt Items**: 20+ item-related entities
- **Article Integration**: Links to merchandise management
- **Price Calculation**: Complex pricing entity relationships
### 3.3 Customer Asset Domain
**SW-DOM-003**: Asset Management Entities
- **Entity Count**: 80+ asset-related entities
- **Asset Lifecycle**: Purchase → Installation → Service → Disposal
- **Service Integration**: Links to helpdesk and support systems
**Core Asset Entities**:
```csharp
public class CustomerAsset : PersistedEntity
{
public virtual int CustomerI3D { get; set; }
public virtual int ArticleI3D { get; set; }
public virtual string SerialNumber { get; set; }
public virtual DateTime? PurchaseDate { get; set; }
public virtual DateTime? WarrantyEndDate { get; set; }
public virtual AssetCondition Condition { get; set; }
public virtual decimal PurchasePrice { get; set; }
public virtual string Location { get; set; }
// Navigation properties
public virtual Customer Customer { get; set; }
public virtual Article Article { get; set; }
public virtual IList<ServiceOrder> ServiceOrders { get; set; }
public virtual IList<AssetContract> Contracts { get; set; }
}
```
### 3.4 Administration Domain
**SW-DOM-004**: System Administration Entities
- **Entity Count**: 200+ administration entities
- **Categories**: Users, Rights, Settings, Company, Logging
- **Security Model**: Role-based access control implementation
**Key Administration Entities**:
| Entity Category | Entity Count | Key Entities |
|----------------|--------------|--------------|
| User Management | 25+ | Employee, User, UserLogin, UserRights |
| Company Structure | 30+ | Mandator, Branch, CompanyGroup |
| System Settings | 40+ | ApplicationSetting, SystemConfiguration |
| Document Management | 35+ | Document, Directory, FileReference |
| Audit and Logging | 20+ | AuditLog, SystemLog, ChangeTracking |
---
## 4. Database Schema Implementation
### 4.1 Primary Key Strategy
**SW-SCHEMA-001**: Primary Key Implementation
- **Column Name**: I3D (Integer 3 Digits, legacy naming)
- **Data Type**: INT IDENTITY(1,1) NOT NULL
- **Clustering**: Clustered primary key on I3D
**SQL Schema Pattern**:
```sql
CREATE TABLE [dbo].[Accounts] (
[I3D] INT IDENTITY(1,1) NOT NULL,
[Number] INT NOT NULL,
[Name] NVARCHAR(255) NOT NULL,
[Matchcode] NVARCHAR(64) NULL,
[Email] NVARCHAR(255) NULL,
[IsActive] BIT NOT NULL DEFAULT(1),
[CreatedDate] DATETIME2(2) NULL,
[ChangedDate] DATETIME2(2) NULL,
[CreatedByI3D] INT NULL,
[ChangedByI3D] INT NULL,
[IsDeleted] BIT NOT NULL DEFAULT(0),
CONSTRAINT [PK_Accounts] PRIMARY KEY CLUSTERED ([I3D])
);
```
### 4.2 Foreign Key Conventions
**SW-SCHEMA-002**: Foreign Key Implementation
- **Naming**: {ReferencedEntity}I3D
- **Nullable**: Most foreign keys nullable to support partial data
- **Constraints**: Declarative referential integrity
**Foreign Key Examples**:
```sql
-- Account to Employee reference
ALTER TABLE [Accounts] ADD CONSTRAINT [FK_Accounts_CreatedBy]
FOREIGN KEY ([CreatedByI3D]) REFERENCES [Employees]([I3D]);
-- Account Address to Account reference
ALTER TABLE [AccountAddresses] ADD CONSTRAINT [FK_AccountAddresses_Account]
FOREIGN KEY ([AccountI3D]) REFERENCES [Accounts]([I3D]);
```
### 4.3 Audit Trail Implementation
**SW-SCHEMA-003**: Audit Field Standard
- **Creation**: CreatedDate, CreatedByI3D, CreatedVersion
- **Modification**: ChangedDate, ChangedByI3D, ChangedVersion
- **Deletion**: IsDeleted, DeletedDate, DeletedByI3D
**Audit Trigger Pattern** (Implemented where needed):
```sql
CREATE TRIGGER [TR_Accounts_Audit] ON [Accounts]
AFTER INSERT, UPDATE
AS
BEGIN
UPDATE a SET
ChangedDate = GETUTCDATE(),
ChangedByI3D = SYSTEM_USER
FROM [Accounts] a
INNER JOIN inserted i ON a.I3D = i.I3D
END
```
---
## 5. NHibernate Mapping Configuration
### 5.1 FluentNHibernate Mapping Pattern
**SW-MAP-001**: Standard Mapping Implementation
- **Location**: `src/backend/Centron.DAO/Mappings/{Domain}/{Entity}Maps.cs`
- **Pattern**: ClassMap<TEntity> inheritance
- **Configuration**: Table name, column mappings, relationships
**Example Mapping Implementation**:
```csharp
// File: src/backend/Centron.DAO/Mappings/Accounts/AccountMaps.cs
public class AccountMaps : ClassMap<Account>
{
public AccountMaps()
{
// Table mapping
Table("Accounts");
// Primary key
Id(m => m.I3D).Column("I3D");
// Simple properties
Map(m => m.Number).Column("Number").Not.Nullable();
Map(m => m.Name).Column("Name").Length(255);
Map(m => m.Email).Column("Email").Length(255).Nullable();
Map(m => m.IsActive).Column("IsActive");
// Audit fields
Map(m => m.CreatedDate).Column("CreatedDate").Nullable();
Map(m => m.CreatedByI3D).Column("CreatedByI3D").Nullable();
Map(m => m.ChangedDate).Column("ChangedDate").Nullable();
Map(m => m.ChangedByI3D).Column("ChangedByI3D").Nullable();
// One-to-many relationships
HasMany(m => m.Addresses)
.KeyColumn("AccountI3D")
.Cascade.All()
.Lazy();
HasMany(m => m.AccountTypes)
.KeyColumn("AccountI3D")
.Cascade.All()
.Lazy();
}
}
```
### 5.2 Relationship Mapping Patterns
**SW-MAP-002**: Association Mapping Strategy
- **One-to-Many**: HasMany() with KeyColumn
- **Many-to-One**: References() with Column
- **Many-to-Many**: HasManyToMany() with intermediate table
- **Component**: Component() for value objects
**Complex Relationship Example**:
```csharp
public class ReceiptMaps : ClassMap<Receipt>
{
public ReceiptMaps()
{
Table("Receipts");
Id(m => m.I3D).Column("I3D");
// Many-to-one customer reference
References(m => m.Customer)
.Column("CustomerI3D")
.Nullable()
.Lazy();
// One-to-many receipt items
HasMany(m => m.Items)
.KeyColumn("ReceiptI3D")
.Cascade.AllDeleteOrphan()
.Lazy();
// Component mapping for value object
Component(m => m.DeliveryAddress, address =>
{
address.Map(a => a.Street).Column("DeliveryStreet");
address.Map(a => a.City).Column("DeliveryCity");
address.Map(a => a.PostalCode).Column("DeliveryPostalCode");
});
}
}
```
### 5.3 Lazy Loading Configuration
**SW-MAP-003**: Performance Optimization Strategy
- **Default**: Lazy loading enabled for collections
- **Eager Loading**: Fetch joins for frequently accessed associations
- **Batch Size**: Configured batch sizes for N+1 query prevention
**Lazy Loading Implementation**:
```csharp
// Lazy loading (default)
HasMany(m => m.Items).Lazy();
// Eager loading for critical paths
HasMany(m => m.Items)
.Fetch.Join()
.BatchSize(50);
// No lazy loading for small datasets
HasMany(m => m.StatusHistory)
.Not.LazyLoad()
.Cascade.All();
```
---
## 6. Data Relationships and Constraints
### 6.1 Domain Model Relationships
**SW-REL-001**: Core Business Relationships
```mermaid
erDiagram
ACCOUNT ||--o{ ACCOUNT_ADDRESS : has
ACCOUNT_ADDRESS ||--o{ ACCOUNT_ADDRESS_CONTACT : has
ACCOUNT ||--o{ RECEIPT : creates
RECEIPT ||--o{ RECEIPT_ITEM : contains
RECEIPT_ITEM }o--|| ARTICLE : references
CUSTOMER_ASSET }o--|| CUSTOMER : belongs_to
CUSTOMER_ASSET }o--|| ARTICLE : is_instance_of
CUSTOMER_ASSET ||--o{ SERVICE_ORDER : requires
```
**Key Relationship Patterns**:
1. **Account Hierarchy**: Account → Address → Contact
2. **Receipt Processing**: Customer → Receipt → Item → Article
3. **Asset Management**: Customer → Asset → Service → Contract
4. **User Management**: Employee → User → Rights → Functions
### 6.2 Referential Integrity
**SW-REL-002**: Database Constraint Implementation
- **Primary Keys**: Enforced at database level
- **Foreign Keys**: Declarative constraints with appropriate actions
- **Check Constraints**: Business rule enforcement
- **Unique Constraints**: Data uniqueness requirements
**Constraint Examples**:
```sql
-- Unique account number constraint
ALTER TABLE [Accounts] ADD CONSTRAINT [UQ_Accounts_Number]
UNIQUE ([Number]);
-- Check constraint for valid email format
ALTER TABLE [Accounts] ADD CONSTRAINT [CK_Accounts_Email]
CHECK ([Email] LIKE '%_@_%.__%' OR [Email] IS NULL);
-- Foreign key with cascade delete
ALTER TABLE [AccountAddresses] ADD CONSTRAINT [FK_AccountAddresses_Account]
FOREIGN KEY ([AccountI3D]) REFERENCES [Accounts]([I3D])
ON DELETE CASCADE;
```
### 6.3 Data Consistency Rules
**SW-REL-003**: Business Rule Enforcement
- **Account Status**: Active accounts cannot be deleted, only deactivated
- **Receipt Workflow**: State transitions must follow defined workflow
- **Financial Integrity**: Invoice totals must match item sum plus tax
- **Asset Tracking**: Assets must have valid customer and article references
---
## 7. Data Validation and Business Rules
### 7.1 Entity Validation Framework
**SW-VAL-001**: Validation Implementation
- **Level 1**: Property-level validation in entity setters
- **Level 2**: Entity-level validation in business logic
- **Level 3**: Cross-entity validation in aggregates
- **Level 4**: Database constraint validation
**Validation Pattern Example**:
```csharp
public class Account : BaseEntity, IValidatableObject
{
private string _name;
public virtual string Name
{
get => _name;
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Account name cannot be empty");
if (value.Length > 255)
throw new ArgumentException("Account name too long");
_name = value;
}
}
public IEnumerable<ValidationResult> Validate(ValidationContext context)
{
var results = new List<ValidationResult>();
// Email validation
if (!string.IsNullOrEmpty(Email) && !IsValidEmail(Email))
{
results.Add(new ValidationResult("Invalid email format",
new[] { nameof(Email) }));
}
// Account number validation
if (Number <= 0)
{
results.Add(new ValidationResult("Account number must be positive",
new[] { nameof(Number) }));
}
return results;
}
}
```
### 7.2 Business Rule Implementation
**SW-VAL-002**: Domain-Specific Validation Rules
- **Account Management**: Name uniqueness, valid contact information
- **Receipt Processing**: State transition validation, price consistency
- **Asset Management**: Serial number uniqueness, warranty date logic
- **Financial**: Tax calculation correctness, currency constraints
**Business Rule Examples**:
```csharp
public class AccountBusinessRules
{
public Result<bool> ValidateAccountCreation(Account account)
{
// Rule 1: Account name must be unique within mandator
if (IsAccountNameDuplicate(account.Name, account.MandatorI3D))
{
return Result.Error("Account name already exists in this mandator");
}
// Rule 2: At least one address must be marked as main address
if (account.Addresses?.Any(a => a.IsMainAddress) != true)
{
return Result.Error("Account must have at least one main address");
}
// Rule 3: Customer accounts must have valid tax number if required
if (account.AccountTypes.Any(t => t.Type.RequiresTaxNumber) &&
string.IsNullOrEmpty(account.TaxNumber))
{
return Result.Error("Tax number required for this account type");
}
return Result.Success(true);
}
}
```
---
## 8. Data Flow and Transformation
### 8.1 Entity-DTO Transformation Pipeline
**SW-FLOW-001**: Data Transformation Architecture
- **Inbound**: DTO → Entity conversion for API requests
- **Outbound**: Entity → DTO conversion for API responses
- **Validation**: Data validation at transformation boundaries
- **Security**: Sensitive field filtering during transformation
**Transformation Pipeline**:
```csharp
public class AccountDataTransformer
{
public Account ConvertDTOToEntity(AccountDTO dto)
{
// 1. Create entity instance
var entity = new Account();
// 2. Map simple properties
entity.Number = dto.Number;
entity.Name = dto.Name;
entity.Email = dto.Email;
// 3. Handle complex properties
entity.Addresses = dto.Addresses?
.Select(ConvertAddressDTO)
.ToList() ?? new List<AccountAddress>();
// 4. Apply business rules during conversion
ValidateAndApplyBusinessRules(entity);
return entity;
}
public AccountDTO ConvertEntityToDTO(Account entity)
{
// 1. Ensure entity is not connected to NHibernate session
NHibernateUtil.Initialize(entity);
// 2. Use ObjectMapper for conversion
var dto = ObjectMapper.Map<AccountDTO>(entity);
// 3. Filter sensitive information
FilterSensitiveFields(dto);
return dto;
}
}
```
### 8.2 Data Synchronization Patterns
**SW-FLOW-002**: Multi-Source Data Management
- **External APIs**: Sync product data from suppliers
- **Legacy Systems**: Import existing customer data
- **Web Services**: Real-time data exchange with client applications
- **Batch Processing**: Nightly data consolidation and cleanup
**Synchronization Example**:
```csharp
public class DataSynchronizationService
{
public async Task<Result<bool>> SynchronizeCustomerData()
{
// 1. Load pending sync items
var pendingSyncs = await LoadPendingSynchronizations();
// 2. Process each sync item
foreach (var sync in pendingSyncs)
{
try
{
// 3. Transform external data format
var entity = await TransformExternalData(sync.ExternalData);
// 4. Validate and merge with existing data
var mergeResult = await MergeWithExistingEntity(entity);
if (!mergeResult.IsSuccess) continue;
// 5. Save changes and mark sync complete
await SaveEntity(mergeResult.Value);
await MarkSyncComplete(sync.I3D);
}
catch (Exception ex)
{
await LogSyncError(sync.I3D, ex);
}
}
return Result.Success(true);
}
}
```
### 8.3 Change Tracking Implementation
**SW-FLOW-003**: Entity Change Detection
- **NHibernate Events**: Automatic change detection via interceptors
- **Audit Logging**: Complete audit trail of all entity modifications
- **Version Control**: Optimistic locking with version stamps
- **Change Notifications**: Event publishing for interested subscribers
**Change Tracking Pattern**:
```csharp
public class EntityChangeTracker : IInterceptor
{
public bool OnSave(object entity, object id, object[] state,
string[] propertyNames, IType[] types)
{
if (entity is PersistedEntity persistedEntity)
{
// Set audit fields for new entities
var now = DateTime.UtcNow;
var userId = GetCurrentUserId();
persistedEntity.CreatedDate = now;
persistedEntity.CreatedByI3D = userId;
// Log entity creation
LogEntityChange("CREATE", entity.GetType().Name, id, state);
}
return false;
}
public bool OnFlushDirty(object entity, object id, object[] currentState,
object[] previousState, string[] propertyNames, IType[] types)
{
if (entity is PersistedEntity persistedEntity)
{
// Set audit fields for modified entities
persistedEntity.ChangedDate = DateTime.UtcNow;
persistedEntity.ChangedByI3D = GetCurrentUserId();
// Log detailed field changes
LogFieldChanges(entity.GetType().Name, id, propertyNames,
previousState, currentState);
}
return false;
}
}
```
---
## Performance and Scalability
### Database Performance Optimization
**Indexing Strategy**:
- **Primary Keys**: Clustered indexes on I3D columns
- **Foreign Keys**: Non-clustered indexes on all FK columns
- **Search Fields**: Composite indexes on frequently searched combinations
- **Query Optimization**: Index hints and query plan analysis
**Sample Index Strategy**:
```sql
-- Primary key (clustered)
CREATE CLUSTERED INDEX [PK_Accounts] ON [Accounts]([I3D]);
-- Foreign key indexes
CREATE NONCLUSTERED INDEX [IX_Accounts_CreatedBy]
ON [Accounts]([CreatedByI3D]);
-- Search optimization indexes
CREATE NONCLUSTERED INDEX [IX_Accounts_Search]
ON [Accounts]([Name], [Matchcode], [Email])
INCLUDE ([Number], [IsActive]);
-- Date range queries
CREATE NONCLUSTERED INDEX [IX_Accounts_DateRange]
ON [Accounts]([CreatedDate], [ChangedDate])
WHERE [IsDeleted] = 0;
```
### Memory and Session Management
**NHibernate Performance**:
- **Session Scope**: Session-per-request pattern
- **Lazy Loading**: Optimized lazy loading configuration
- **Batch Processing**: Batch sizes configured for large datasets
- **Cache Strategy**: Second-level cache for reference data
---
**Document Approval**
- **Database Architect**: Schema design and constraints verified
- **Data Modeler**: Entity relationships and mappings validated
- **Performance Engineer**: Query optimization and indexing approved
- **Security Officer**: Data protection and audit requirements confirmed
- **Date**: 2025-09-30
- **Version Control**: Committed to repository requirements/software/