feat: Add PDF/A validation endpoint (Feature 3)

Domain layer:

  - PdfAMetadata value object (isValid, pdfVersion, pageCount, encrypted, pdfaVersion, pdfaCompliant, errors, warnings)

Infrastructure layer:

  - IPdfProcessor.ValidatePdfAAsync() interface method

  - DevExpressPdfProcessor.ValidatePdfAAsync() implementation

  - DetectEncryption() - scans PDF raw data for /Encrypt keyword

  - DetectPdfAConformance() - parses XMP metadata (pdfaid:part, pdfaid:conformance)

  - Validation: encrypted PDF cannot be PDF/A compliant

Application layer:

  - ValidatePdfAQuery + ValidatePdfAQueryHandler (co-located)

  - ValidatePdfAQueryValidator (FluentValidation: PdfBytes XOR Base64Pdf)

  - PdfAValidationResult DTO

  - AutoMapper: PdfAMetadata -> PdfAValidationResult

API layer:

  - PdfValidationController.ValidatePdfAFromFile() (multipart/form-data)

  - PdfValidationController.ValidatePdfAFromBase64() (application/json)

  - XML documentation with response codes

Result:

  - POST /api/pdf/validation/validate-pdfa (both multipart and JSON)

  - Returns: conformance level, errors, warnings

  - Build: 0 errors, 4 warnings (DevExpress eval)

  - Tests: 20/20 passing

Next: Integration tests + Swagger test case
This commit is contained in:
2026-07-09 12:59:24 +02:00
parent 1ff7cbea11
commit cd50d45bd5
8 changed files with 365 additions and 3 deletions

View File

@@ -0,0 +1,47 @@
namespace DocumentOperator.Domain.Models.ValueObjects;
/// <summary>
/// PDF/A validation metadata including conformance level and validation errors/warnings
/// </summary>
public sealed class PdfAMetadata
{
public bool IsValid { get; }
public string PdfVersion { get; }
public int PageCount { get; }
public long FileSizeBytes { get; }
public bool Encrypted { get; }
public string? PdfAVersion { get; }
public bool PdfACompliant { get; }
public IReadOnlyList<string> Errors { get; }
public IReadOnlyList<string> Warnings { get; }
// Computed property
public double FileSizeMB => FileSizeBytes / 1024.0 / 1024.0;
public PdfAMetadata(
bool isValid,
string pdfVersion,
int pageCount,
long fileSizeBytes,
bool encrypted,
string? pdfaVersion,
bool pdfaCompliant,
IReadOnlyList<string> errors,
IReadOnlyList<string> warnings)
{
IsValid = isValid;
PdfVersion = pdfVersion;
PageCount = pageCount;
FileSizeBytes = fileSizeBytes;
Encrypted = encrypted;
PdfAVersion = pdfaVersion;
PdfACompliant = pdfaCompliant;
Errors = errors;
Warnings = warnings;
}
public override string ToString()
{
return $"PDF/A: {PdfAVersion ?? "None"}, {PageCount} pages, {FileSizeMB:F2} MB, Compliant: {PdfACompliant}";
}
}