Skip to content

Scheduled Report Runs

Compliance edition

This feature ships with Tayra.Compliance and requires a Compliance edition license. See Licensing for the edition comparison.

Tayra ships a hosted-service scheduler that periodically generates compliance reports and persists them via a pluggable IComplianceReportArchive. Removes the "I'll generate the Article 30 inventory when the auditor asks" toil - schedules emit reports on cadence and durable storage of the artifact is built in.

Reports inherit signing automatically when report signing is also registered - every scheduled artifact is then persisted with a detached ECDSA-P256 signature.

Wiring

csharp
services.AddTayra(opts => opts.LicenseKey = key)
    .AddCompliance(opts => { /* ... */ });

services.AddTayraScheduledComplianceReports(opts =>
{
    opts.ArchiveDirectory = "/var/tayra/reports";

    opts.AddSchedule(new ScheduledReportEntry
    {
        Name = "monthly-art30",
        ReportType = ScheduledReportType.Article30Inventory,
        Interval = TimeSpan.FromDays(30),
        Article30Options = new Article30Options
        {
            ControllerName = "Acme Corporation",
            DpoContact = "dpo@acme.example",
            ProcessingPurpose = "Customer service operations",
            LegalBasis = "Article 6(1)(b) - contract performance",
        },
    });

    opts.AddSchedule(new ScheduledReportEntry
    {
        Name = "weekly-coverage",
        ReportType = ScheduledReportType.EncryptionCoverage,
        Interval = TimeSpan.FromDays(7),
    });
});

The scheduler runs as a BackgroundService, wakes up at TickInterval (defaults to one minute), and evaluates each registered schedule. Reports inherit Tayra's regular logging and OpenTelemetry instrumentation.

Schedulable report types

Subject-specific reports (Article 15 access, Article 33/34 breach) are reactive rather than scheduled and are excluded. Only org-wide reports schedule sensibly:

ScheduledReportTypeWhat it generatesOutput
Article30InventoryGDPR Article 30 Records of Processing ActivitiesHTML
PiiInventoryJsonPII data map / inventoryJSON
PiiInventoryMarkdownPII data map / inventoryMarkdown
EncryptionCoverageProtected vs unprotected entity coverageHTML

The archive abstraction

IComplianceReportArchive is the storage seam. Tayra ships FileSystemComplianceReportArchive as the default - writes artifacts under {ArchiveDirectory}/{scheduleName}/{utcTimestamp}-{reportType}.{ext} with cross-platform safe filename sanitization.

To plug in S3, Azure Blob, GCS, or any other backend, register your own implementation before calling the extension:

csharp
services.AddSingleton<IComplianceReportArchive, S3ComplianceReportArchive>();
services.AddTayraScheduledComplianceReports(opts => /* ... */);

The interface is a single method:

csharp
public interface IComplianceReportArchive
{
    Task<string> SaveAsync(ComplianceReportArtifact artifact, CancellationToken ct = default);
}

ComplianceReportArtifact carries the schedule name, report type, generation timestamp, content type, file extension, and raw bytes - enough metadata for any backend to organize and catalog.

Scheduling semantics

  • Interval is mandatory - reports run every TimeSpan you specify once scheduling starts.
  • FirstRunAt (optional) lets you anchor the first execution; otherwise the schedule fires on the first scheduler tick after host startup.
  • TickInterval controls how often the scheduler wakes to evaluate due schedules. The default of one minute is right for daily/weekly/monthly cadence; tighten it if you genuinely need sub-minute granularity.
  • Failures are logged via ILogger and the loop continues - a single failed run never takes down the scheduler.

Combining with signing

Stack AddTayraReportSigning and AddTayraScheduledComplianceReports to get durable, archived, signed reports:

csharp
services.AddTayraReportSigning(opts =>
    opts.UseEcdsaP256(privateKeyPem, publicKeyPem));

services.AddTayraScheduledComplianceReports(opts =>
{
    opts.ArchiveDirectory = "/var/tayra/reports";
    opts.AddSchedule(/* … */);
});

Every artifact in the archive carries a detached signature an auditor can verify offline.

See Also