---
name: archive-management
description: >
  نظام إدارة الأرشيف والوثائق الحكومية الإلكتروني.
  استخدم هذا الـ skill عند: أرشفة مستندات، إدارة ملفات، فهرسة وثائق،
  البحث في الأرشيف، تصنيف المستندات، إدارة دورة حياة الوثيقة، تتبع الاستعارات،
  الحفظ والإتلاف، أو أي مهمة تتعلق بالأرشيف الإلكتروني والورقي.
  يشمل OCR عربي وتكامل مع نظام الاتصالات الإدارية.
---

# Archive Management System
# نظام إدارة الأرشيف والوثائق

## Domain Model

```csharp
// === الوثيقة ===
public class Document : BaseAuditableEntity
{
    public int Id { get; set; }
    public string DocumentNumber { get; set; } = string.Empty;   // DOC-2024-00001
    public string Title { get; set; } = string.Empty;
    public string? Description { get; set; }
    public int DocumentTypeId { get; set; }
    public int ClassificationId { get; set; }
    public SecurityLevel SecurityLevel { get; set; }
    public int DepartmentId { get; set; }
    public int? FolderId { get; set; }

    // Metadata
    public string? ReferenceNumber { get; set; }
    public DateTime? DocumentDate { get; set; }
    public string? SourceEntity { get; set; }
    public string? Keywords { get; set; }
    public string? OcrText { get; set; }                 // نص OCR المستخرج
    public string? BarcodePath { get; set; }
    
    // Physical location (if paper)
    public string? PhysicalLocation { get; set; }        // رقم الدولاب/الرف/الملف
    public string? ShelfNumber { get; set; }
    public string? BoxNumber { get; set; }

    // Lifecycle
    public DocumentStatus Status { get; set; }
    public int RetentionPeriodYears { get; set; }
    public DateTime? RetentionExpiryDate { get; set; }
    public DisposalAction DisposalAction { get; set; }

    // Relations
    public DocumentType DocumentType { get; set; } = null!;
    public Classification Classification { get; set; } = null!;
    public Folder? Folder { get; set; }
    public List<DocumentVersion> Versions { get; set; } = new();
    public List<DocumentAttachment> Attachments { get; set; } = new();
    public List<DocumentBorrowing> Borrowings { get; set; } = new();
    public List<DocumentTag> Tags { get; set; } = new();
}

public enum SecurityLevel
{
    Public,             // عام
    Internal,           // داخلي
    Confidential,       // سري
    TopSecret           // سري للغاية
}

public enum DocumentStatus
{
    Draft,              // مسودة
    Active,             // نشط
    Archived,           // مؤرشف
    UnderReview,        // قيد المراجعة
    PendingDisposal,    // بانتظار الإتلاف
    Disposed,           // تم إتلافه
    Borrowed            // مُعار
}

public enum DisposalAction
{
    PermanentRetention,  // حفظ دائم
    Review,              // مراجعة
    Transfer,            // نقل للأرشيف الوطني
    Destroy              // إتلاف
}

// === التصنيف ===
public class Classification
{
    public int Id { get; set; }
    public string Code { get; set; } = string.Empty;       // 01.02.03
    public string NameAr { get; set; } = string.Empty;
    public int? ParentId { get; set; }
    public int Level { get; set; }
    public int DefaultRetentionYears { get; set; }
    public DisposalAction DefaultDisposalAction { get; set; }
}

// === المجلدات ===
public class Folder
{
    public int Id { get; set; }
    public string FolderNumber { get; set; } = string.Empty;
    public string NameAr { get; set; } = string.Empty;
    public int? ParentFolderId { get; set; }
    public int ClassificationId { get; set; }
    public int DepartmentId { get; set; }
    public FolderStatus Status { get; set; }
    public int DocumentCount { get; set; }
    public List<Document> Documents { get; set; } = new();
}

// === إصدارات الوثيقة ===
public class DocumentVersion
{
    public int Id { get; set; }
    public int DocumentId { get; set; }
    public int VersionNumber { get; set; }
    public string FilePath { get; set; } = string.Empty;
    public string FileName { get; set; } = string.Empty;
    public string ContentType { get; set; } = string.Empty;
    public long FileSize { get; set; }
    public string? FileHash { get; set; }           // SHA-256
    public string? ChangeNotes { get; set; }
    public int UploadedBy { get; set; }
    public DateTime UploadedAt { get; set; }
}

// === استعارة الوثائق ===
public class DocumentBorrowing : BaseAuditableEntity
{
    public int Id { get; set; }
    public string BorrowingNumber { get; set; } = string.Empty;
    public int DocumentId { get; set; }
    public int BorrowerEmployeeId { get; set; }
    public DateTime BorrowDate { get; set; }
    public DateTime DueDate { get; set; }
    public DateTime? ReturnDate { get; set; }
    public BorrowingStatus Status { get; set; }
    public string? Purpose { get; set; }
    public int? ApprovalWorkflowId { get; set; }
}
```

## Document Processing Pipeline

```csharp
public interface IDocumentProcessingService
{
    Task<Document> IngestDocumentAsync(Stream file, DocumentMetadata metadata);
    Task<string> ExtractTextOcrAsync(int documentId);
    Task GenerateBarcodeAsync(int documentId);
    Task IndexForSearchAsync(int documentId);
}

public class DocumentProcessingService : IDocumentProcessingService
{
    public async Task<Document> IngestDocumentAsync(Stream file, DocumentMetadata metadata)
    {
        // 1. Virus scan
        await _virusScanService.ScanAsync(file);
        
        // 2. Generate unique file name and store
        var storedPath = await _fileStorage.SaveAsync(file, metadata.FileName);
        
        // 3. Generate barcode
        var barcode = await _barcodeService.GenerateAsync(metadata.DocumentNumber);
        
        // 4. Create document record
        var document = new Document
        {
            DocumentNumber = await GenerateDocumentNumber(),
            Title = metadata.Title,
            DocumentTypeId = metadata.DocumentTypeId,
            ClassificationId = metadata.ClassificationId,
            SecurityLevel = metadata.SecurityLevel,
            Status = DocumentStatus.Active,
            BarcodePath = barcode
        };
        
        // 5. Create first version
        document.Versions.Add(new DocumentVersion
        {
            VersionNumber = 1,
            FilePath = storedPath,
            FileName = metadata.FileName,
            FileSize = file.Length,
            FileHash = ComputeHash(file)
        });
        
        _context.Documents.Add(document);
        await _context.SaveChangesAsync();
        
        // 6. OCR extraction (background)
        await _backgroundJobs.EnqueueAsync(() => ExtractTextOcrAsync(document.Id));
        
        // 7. Index for search (background)
        await _backgroundJobs.EnqueueAsync(() => IndexForSearchAsync(document.Id));
        
        return document;
    }
}
```

## Search Service

```csharp
public interface IArchiveSearchService
{
    Task<PaginatedList<DocumentSearchResult>> SearchAsync(ArchiveSearchQuery query);
    Task<List<DocumentSearchResult>> FullTextSearchAsync(string searchTerm);
    Task<List<DocumentSearchResult>> AdvancedSearchAsync(AdvancedSearchCriteria criteria);
}

public class ArchiveSearchQuery
{
    public string? SearchTerm { get; set; }
    public int? DocumentTypeId { get; set; }
    public int? ClassificationId { get; set; }
    public int? DepartmentId { get; set; }
    public SecurityLevel? SecurityLevel { get; set; }
    public DateTime? DateFrom { get; set; }
    public DateTime? DateTo { get; set; }
    public string? Keywords { get; set; }
    public DocumentStatus? Status { get; set; }
    public int PageNumber { get; set; } = 1;
    public int PageSize { get; set; } = 20;
}
```

## SQL Schema

```sql
CREATE SCHEMA [Archive];

CREATE TABLE [Archive].[Documents] (
    [Id] INT IDENTITY(1,1) PRIMARY KEY,
    [DocumentNumber] NVARCHAR(50) NOT NULL UNIQUE,
    [Title] NVARCHAR(500) NOT NULL,
    [Description] NVARCHAR(2000) NULL,
    [DocumentTypeId] INT NOT NULL,
    [ClassificationId] INT NOT NULL,
    [SecurityLevel] NVARCHAR(20) NOT NULL DEFAULT 'Internal',
    [DepartmentId] INT NOT NULL,
    [FolderId] INT NULL,
    [OcrText] NVARCHAR(MAX) NULL,
    [Keywords] NVARCHAR(500) NULL,
    [PhysicalLocation] NVARCHAR(200) NULL,
    [Status] NVARCHAR(20) NOT NULL DEFAULT 'Active',
    [RetentionPeriodYears] INT NOT NULL DEFAULT 5,
    [RetentionExpiryDate] DATE NULL,
    [CreatedBy] INT NOT NULL,
    [CreatedAt] DATETIME2 NOT NULL DEFAULT GETUTCDATE()
);

-- Full-Text Search
CREATE FULLTEXT INDEX ON [Archive].[Documents](
    [Title] LANGUAGE 'Arabic',
    [Description] LANGUAGE 'Arabic',
    [OcrText] LANGUAGE 'Arabic',
    [Keywords] LANGUAGE 'Arabic'
) KEY INDEX PK__Documents;

CREATE TABLE [Archive].[DocumentVersions] (
    [Id] INT IDENTITY(1,1) PRIMARY KEY,
    [DocumentId] INT NOT NULL FOREIGN KEY REFERENCES [Archive].[Documents]([Id]),
    [VersionNumber] INT NOT NULL,
    [FilePath] NVARCHAR(500) NOT NULL,
    [FileName] NVARCHAR(300) NOT NULL,
    [FileSize] BIGINT NOT NULL,
    [FileHash] NVARCHAR(64) NULL,
    [UploadedBy] INT NOT NULL,
    [UploadedAt] DATETIME2 NOT NULL DEFAULT GETUTCDATE()
);

CREATE TABLE [Archive].[Classifications] (
    [Id] INT IDENTITY(1,1) PRIMARY KEY,
    [Code] NVARCHAR(20) NOT NULL UNIQUE,
    [NameAr] NVARCHAR(200) NOT NULL,
    [ParentId] INT NULL FOREIGN KEY REFERENCES [Archive].[Classifications]([Id]),
    [Level] INT NOT NULL,
    [DefaultRetentionYears] INT NOT NULL DEFAULT 5
);

CREATE TABLE [Archive].[Borrowings] (
    [Id] INT IDENTITY(1,1) PRIMARY KEY,
    [DocumentId] INT NOT NULL FOREIGN KEY REFERENCES [Archive].[Documents]([Id]),
    [BorrowerEmployeeId] INT NOT NULL,
    [BorrowDate] DATE NOT NULL,
    [DueDate] DATE NOT NULL,
    [ReturnDate] DATE NULL,
    [Status] NVARCHAR(20) NOT NULL DEFAULT 'Active',
    [Purpose] NVARCHAR(500) NULL
);
```

## Reports

| التقرير | الوصف |
|---------|--------|
| سجل الوثائق | جميع الوثائق مع تصنيفاتها |
| تقرير الاستعارات | الوثائق المعارة والمتأخرة |
| تقرير الإتلاف | الوثائق المستحقة للإتلاف |
| إحصائيات الأرشيف | عدد الوثائق حسب النوع/التصنيف/القسم |
| تقرير الحفظ | جدول الاحتفاظ بالوثائق |
| سجل الوصول | من اطلع على أي وثيقة |
| تقرير الرقمنة | نسبة الوثائق المرقمنة |
