name: saas-management
description: >
نظام إدارة اشتراكات البرمجيات كخدمة (SaaS) والتراخيص.
استخدم هذا الـ skill عند: إدارة اشتراكات SaaS، تتبع التراخيص، إدارة التكاليف،
مراقبة الاستخدام، تجديد الاشتراكات، إدارة المستخدمين، تقييم الموردين،
أو أي مهمة تتعلق بإدارة البرمجيات والخدمات السحابية والتراخيص.
SaaS & License Management
إدارة الاشتراكات والتراخيص
Domain Model
public class SaasSubscription : BaseAuditableEntity
{
public int Id { get; set; }
public string SubscriptionCode { get; set; } = string.Empty;
public string ServiceNameAr { get; set; } = string.Empty;
public string ServiceNameEn { get; set; } = string.Empty;
public string ProviderName { get; set; } = string.Empty;
public string? ProviderWebsite { get; set; }
// Subscription Details
public SaasCategory Category { get; set; }
public string PlanName { get; set; } = string.Empty;
public BillingCycle BillingCycle { get; set; }
public decimal MonthlyCost { get; set; }
public decimal AnnualCost { get; set; }
public string Currency { get; set; } = "SAR";
// License
public int TotalLicenses { get; set; }
public int UsedLicenses { get; set; }
public int AvailableLicenses => TotalLicenses - UsedLicenses;
public decimal CostPerLicense => TotalLicenses > 0 ? MonthlyCost / TotalLicenses : 0;
public LicenseType LicenseType { get; set; }
// Dates
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public DateTime? NextRenewalDate { get; set; }
public bool AutoRenew { get; set; }
public int RenewalNoticeDays { get; set; } = 30;
// Status
public SubscriptionStatus Status { get; set; }
public int OwnerDepartmentId { get; set; }
public int OwnerEmployeeId { get; set; }
// Contract
public int? ContractId { get; set; }
public int? PurchaseOrderId { get; set; }
public int? BudgetLineId { get; set; }
// Security
public DataResidency DataResidency { get; set; }
public bool HasSSOIntegration { get; set; }
public bool IsGovernmentCertified { get; set; }
public string? SecurityCertifications { get; set; }
public List<SaasUser> Users { get; set; } = new();
public List<SaasUsageLog> UsageLogs { get; set; } = new();
}
public enum SaasCategory
{
Productivity, // إنتاجية (Office 365, Google Workspace)
Communication, // اتصالات (Teams, Zoom, Slack)
ProjectManagement, // إدارة مشاريع (Jira, Asana)
CRM, // إدارة علاقات العملاء
HRM, // موارد بشرية
Finance, // مالية ومحاسبية
Security, // أمن معلومات
Development, // تطوير برمجيات
Design, // تصميم
Analytics, // تحليلات
CloudInfra, // بنية تحتية سحابية
Other // أخرى
}
public enum DataResidency
{
SaudiArabia, // داخل المملكة
GCC, // دول الخليج
MiddleEast, // الشرق الأوسط
International // دولي
}
// === استخدام المستخدمين ===
public class SaasUser
{
public int Id { get; set; }
public int SubscriptionId { get; set; }
public int EmployeeId { get; set; }
public string? ExternalUserId { get; set; }
public string Role { get; set; } = "user";
public DateTime AssignedDate { get; set; }
public DateTime? LastActiveDate { get; set; }
public bool IsActive { get; set; } = true;
public decimal MonthlyUsageHours { get; set; }
}
Cost Optimization Service
public class SaasOptimizationService
{
public async Task<OptimizationReport> AnalyzeAsync()
{
var report = new OptimizationReport();
// 1. Unused licenses
var subscriptions = await _context.SaasSubscriptions
.Include(s => s.Users)
.Where(s => s.Status == SubscriptionStatus.Active)
.ToListAsync();
foreach (var sub in subscriptions)
{
var unusedLicenses = sub.TotalLicenses - sub.UsedLicenses;
if (unusedLicenses > 0)
{
report.UnusedLicenses.Add(new()
{
Subscription = sub.ServiceNameAr,
UnusedCount = unusedLicenses,
MonthlySavings = unusedLicenses * sub.CostPerLicense
});
}
// 2. Inactive users (no login 30+ days)
var inactiveUsers = sub.Users.Where(u =>
u.IsActive && u.LastActiveDate < DateTime.UtcNow.AddDays(-30)).ToList();
if (inactiveUsers.Any())
{
report.InactiveUsers.Add(new()
{
Subscription = sub.ServiceNameAr,
InactiveCount = inactiveUsers.Count,
MonthlySavings = inactiveUsers.Count * sub.CostPerLicense
});
}
}
// 3. Upcoming renewals
report.UpcomingRenewals = subscriptions
.Where(s => s.NextRenewalDate <= DateTime.UtcNow.AddDays(60))
.Select(s => new RenewalAlert {
Subscription = s.ServiceNameAr,
RenewalDate = s.NextRenewalDate!.Value,
AnnualCost = s.AnnualCost
}).ToList();
// 4. Duplicate/overlapping services
report.PotentialDuplicates = subscriptions
.GroupBy(s => s.Category)
.Where(g => g.Count() > 1)
.Select(g => new DuplicateAlert
{
Category = g.Key.ToString(),
Services = g.Select(s => s.ServiceNameAr).ToList()
}).ToList();
return report;
}
}
SQL Schema
CREATE SCHEMA [SaaS];
CREATE TABLE [SaaS].[Subscriptions] (
[Id] INT IDENTITY(1,1) PRIMARY KEY,
[SubscriptionCode] NVARCHAR(50) NOT NULL UNIQUE,
[ServiceNameAr] NVARCHAR(200) NOT NULL,
[ServiceNameEn] NVARCHAR(200) NOT NULL,
[ProviderName] NVARCHAR(200) NOT NULL,
[Category] NVARCHAR(30) NOT NULL,
[BillingCycle] NVARCHAR(20) NOT NULL,
[MonthlyCost] DECIMAL(18,2) NOT NULL,
[AnnualCost] DECIMAL(18,2) NOT NULL,
[TotalLicenses] INT NOT NULL,
[UsedLicenses] INT NOT NULL DEFAULT 0,
[StartDate] DATE NOT NULL,
[EndDate] DATE NOT NULL,
[NextRenewalDate] DATE NULL,
[AutoRenew] BIT NOT NULL DEFAULT 0,
[Status] NVARCHAR(20) NOT NULL DEFAULT 'Active',
[DataResidency] NVARCHAR(20) NOT NULL DEFAULT 'SaudiArabia',
[OwnerDepartmentId] INT NOT NULL,
[CreatedAt] DATETIME2 NOT NULL DEFAULT GETUTCDATE()
);
-- Cost Overview View
CREATE VIEW [SaaS].[vw_CostOverview] AS
SELECT
Category,
COUNT(*) AS SubscriptionCount,
SUM(MonthlyCost) AS TotalMonthlyCost,
SUM(AnnualCost) AS TotalAnnualCost,
SUM(TotalLicenses) AS TotalLicenses,
SUM(UsedLicenses) AS TotalUsedLicenses,
SUM(TotalLicenses - UsedLicenses) AS TotalUnusedLicenses
FROM [SaaS].[Subscriptions] WHERE Status = 'Active'
GROUP BY Category;