Compliance Reports
Tayra provides compliance report generation through ITayraCompliance for producing formatted, self-contained HTML reports that cover the key GDPR reporting requirements. Each report type renders as a complete HTML document with embedded CSS — no external dependencies, no JavaScript, ready to print or email.
Report Types
The generator supports five report types:
| Report | Method | GDPR Article | Input |
|---|---|---|---|
| Records of Processing | GenerateArticle30Report | Art. 30 | PiiInventoryReport + Article30Options |
| Data Subject Access | GenerateAccessReport | Art. 15 | DataSubjectAccessReport |
| Breach Notification | GenerateBreachReport | Art. 33/34 | BreachNotificationReport |
| Encryption Coverage | GenerateEncryptionCoverageReport | Art. 32 | PiiInventoryReport |
| Key Lifecycle | GenerateKeyLifecycleReport | Art. 5(1)(e) | KeyLifecycleData |
Setup
Package Requirement
This feature requires the Tayra.Compliance package and a Compliance edition license. Data protection itself is handled by Tayra.Core — this package provides the reporting tooling.
dotnet add package Tayra.ComplianceRegister the compliance services:
using Tayra.Compliance;
services.AddTayra(opts => opts.LicenseKey = licenseKey)
// InMemoryKeyStore is used by default for development.
// For production, chain a secrets manager: .UseVaultKeyStore(...)
.AddCompliance(complianceOpts =>
{
complianceOpts.ApplicationName = "MyApp";
complianceOpts.AddEntityType<Customer>();
});This registers ITayraCompliance, which provides report generation alongside PII inventory, data subject access, and breach notification.
INFO
The compliance report generator is stateless. It formats data that you supply from other Tayra services. You can also construct the input objects manually if needed.
Art. 30 Report -- Records of Processing Activities
The Art. 30 report combines PII inventory data with controller-level metadata to produce a formal Records of Processing Activities document. This is the report your DPO submits to the supervisory authority.
Article30Options
Configure the controller information that appears in the report header:
| Property | Type | Default | Description |
|---|---|---|---|
ControllerName | string | "Organization" | Name of the data controller |
DpoContact | string? | null | DPO contact details |
ProcessingPurpose | string | "Service delivery and account management" | Purpose of processing |
LegalBasis | string | "Contract performance (Art. 6(1)(b))" | Legal basis for processing |
RetentionPeriod | string | "As defined by key retention policy" | Data retention period description |
Recipients | IList<string> | [] | Categories of data recipients |
ThirdCountryTransfers | bool | false | Whether data is transferred outside the EEA |
SecurityMeasures | string | "AES-256-GCM field-level encryption, HMAC-SHA256 blind indexes, crypto-shredding" | Description of security measures |
Example
public class ComplianceService
{
private readonly ITayraCompliance _compliance;
public ComplianceService(ITayraCompliance compliance)
{
_compliance = compliance;
}
public async Task GenerateArt30ReportAsync()
{
var inventoryReport = _compliance.GenerateInventory();
var options = new Article30Options
{
ControllerName = "Acme Corp",
DpoContact = "dpo@acme.com",
ProcessingPurpose = "Customer relationship management and order fulfillment",
LegalBasis = "Contract performance (Art. 6(1)(b))",
RetentionPeriod = "7 years after account closure",
Recipients = ["Payment processor", "Shipping provider"],
ThirdCountryTransfers = false,
SecurityMeasures = "AES-256-GCM field-level encryption, HMAC-SHA256 blind indexes, "
+ "crypto-shredding, TLS 1.3 in transit",
};
var html = _compliance.RenderArticle30Report(inventoryReport, options);
await File.WriteAllTextAsync("art30-report.html", html);
}
}The generated HTML includes:
- Controller Information -- Organization name, DPO contact, purpose, legal basis, retention period, security measures
- Categories of Personal Data -- Table of all entities with PII fields, encryption status, blind index count, and protecting integrations
- Summary -- Aggregate counts of entity types, PII fields, encrypted fields, and active integrations
Art. 15 Access Report -- Data Subject Access
The access report formats a DataSubjectAccessReport (from ITayraCompliance.ExportAccessAsync) into a presentable HTML document suitable for delivering to a data subject.
Example
public async Task GenerateAccessReportAsync(string subjectId)
{
var accessReport = await _compliance.ExportAccessAsync(subjectId);
var html = _compliance.RenderAccessReport(accessReport);
await File.WriteAllTextAsync($"access-report-{subjectId}.html", html);
}The generated HTML includes:
- Subject ID and generation timestamp
- Per-entity tables showing each field name, its decrypted value, and whether it has been redacted (crypto-shredded)
- Fields where the encryption key has been shredded are marked with a visual "Redacted" indicator
Art. 33/34 Breach Report -- Breach Notification
The breach report formats a BreachNotificationReport (from ITayraCompliance.AssessBreachAsync) into a document that contains both the DPA notification content (Art. 33) and the data subject notification content (Art. 34).
Example
public async Task GenerateBreachReportAsync(BreachDetails details)
{
var impact = await _compliance.AssessBreachAsync(details);
var notification = await _compliance.GenerateBreachReportAsync(impact);
var html = _compliance.RenderBreachReport(notification);
await File.WriteAllTextAsync("breach-report.html", html);
}The generated HTML includes:
- DPA notification deadline with overdue warning if the 72-hour window has passed
- Impact assessment -- severity level, affected subject count, affected key IDs, affected entity types
- DPA Notification (Art. 33) -- Nature of breach, affected subjects summary, affected data summary, likely consequences, measures taken
- Data Subject Notification (Art. 34) -- Description of what happened and recommended protective actions (only included when severity is High or Critical)
Encryption Coverage Report
The encryption coverage report shows which entities are fully encrypted, which are partially encrypted, and the overall coverage percentage. This is useful for internal security reviews and as evidence of Art. 32 compliance (security of processing).
Example
public async Task GenerateCoverageReportAsync()
{
var inventoryReport = _compliance.GenerateInventory();
var html = _compliance.RenderCoverageReport(inventoryReport);
await File.WriteAllTextAsync("encryption-coverage.html", html);
}The generated HTML includes:
- Overview -- Total entities with PII, fully encrypted count, partially encrypted count, overall coverage percentage
- Entity details table -- Each entity with its encryption status, total PII field count, encrypted field count, and per-entity coverage percentage
CI/CD Integration
Use the encryption coverage report as a deployment gate. Generate it during CI/CD and fail the pipeline if coverage drops below your threshold. See CLI Tool for command-line report generation.
Key Lifecycle Report
The key lifecycle report documents key management activity over a time period -- rotations, creations, deletions (shredding), and expirations. This supports Art. 5(1)(e) (storage limitation) and provides evidence that your key management practices are active and compliant.
KeyLifecycleData
Construct the input from your audit trail or key store events:
| Property | Type | Description |
|---|---|---|
ReportPeriodStart | DateTimeOffset | Start of the reporting period |
ReportPeriodEnd | DateTimeOffset | End of the reporting period |
Events | IReadOnlyList<KeyLifecycleEvent> | Key lifecycle events in the period |
KeyLifecycleEvent
| Property | Type | Description |
|---|---|---|
Timestamp | DateTimeOffset | When the event occurred |
EventType | string | Event type (e.g., "KeyCreated", "KeyRotated", "KeyDeleted", "KeyExpired") |
KeyId | string | The key identifier involved |
Details | string? | Optional additional details |
Example
public async Task GenerateKeyLifecycleReportAsync()
{
var now = DateTimeOffset.UtcNow;
var events = await _auditStore.GetKeyEventsAsync(
now.AddDays(-30), now);
var lifecycleData = new KeyLifecycleData
{
ReportPeriodStart = now.AddDays(-30),
ReportPeriodEnd = now,
Events = events.Select(e => new KeyLifecycleEvent
{
Timestamp = e.Timestamp,
EventType = e.EventType,
KeyId = e.KeyId,
Details = e.Details,
}).ToList(),
};
var html = _compliance.RenderKeyLifecycleReport(lifecycleData);
await File.WriteAllTextAsync("key-lifecycle-report.html", html);
}The generated HTML includes:
- Report period displayed in the header
- Event summary table -- Each event type with its count for the period
- Event log -- Full chronological list with timestamp, event type, key ID, and details
HTML Output
All reports render as self-contained HTML documents with embedded CSS. The styling uses system fonts and a clean table layout that works well in browsers, print dialogs, and email clients. There are no external CSS files, JavaScript dependencies, or image references -- the HTML file is the complete report.
// Write to file
var html = _compliance.RenderArticle30Report(inventory, options);
await File.WriteAllTextAsync("report.html", html);
// Return from an API endpoint
[HttpGet("/compliance/art30")]
public IActionResult GetArt30Report()
{
var inventory = _compliance.GenerateInventory();
var html = _compliance.RenderArticle30Report(inventory);
return Content(html, "text/html");
}
// Send via email
var html = _compliance.RenderBreachReport(notification);
await _emailService.SendAsync("dpo@acme.com", "Breach Report", html);See Also
- PII Data Map -- Generate the inventory data that feeds into Art. 30 and coverage reports
- GDPR Overview -- Full GDPR article mapping and feature index
- Breach Notification -- Assess breach impact and generate notification data
- Data Subject Access -- Export personal data for access reports
