Skip to content

Audit trail · Compliance · .NET-native

Every change. Every value. Every time.

Reldavi records who changed what in your database, what it looked like before, and exactly when — without adding a millisecond to the request that made the change. Install a NuGet package, add three lines, and your audit trail starts filling itself.

No credit card. 100,000 events a month on the free plan, forever.

reldavi.com — Event detail updated shop.order Order A-1042 2026-09-19 14:32:07 PROPERTY BEFORE AFTER Status − Pending + Shipped ShippedAt + 2026-09-19 14:32 CardNumber − ************1111 + ************4242 Total − 1,249.00 + 1,099.00 TrackingNo + TR884210933 Who Emre Şahin IP address 203.0.113.9 Correlation id req-8f2c41 Source dotnet-efcore · web-02

Built for the questions auditors actually ask

5 min From dotnet add package to your first recorded change.
0 ms Added to your request path. Capture does no I/O and never waits.
4 SDKs MIT licensed and open source. Take the capture layer without the platform.
100% Self-hostable. One compose file, your servers, your data.

The problem

Your database knows what changed. It just will not tell you.

A row says status = "Shipped". It does not say who shipped it, when, from which IP, or that it was "Cancelled" ninety seconds earlier. When a customer disputes a charge, when a regulator asks for a change history, or when something is wrong and nobody knows who touched it, that missing context is the whole problem.

So teams build it themselves: a trigger here, an UpdatedBy column there, a JSON blob in a side table nobody indexes. It works until the first audit, and then somebody spends a quarter making it presentable.

Triggers are invisible

Database triggers run where your application cannot see them, cannot mask PII, and cannot record who the user was.

Side tables grow teeth

An audit table in your transactional database competes with production traffic for exactly the resource you cannot spare.

Logs are not evidence

Application logs get sampled, rotated and truncated. An auditor asks for seven years; your retention policy says fourteen days.

The product

A time machine for your data.

Every recorded change is one click from the before-and-after that produced it.

Read a change the way you read a pull request.

Property by property, old value against new, colour-coded and legible at a glance. No JSON blob to squint at, no log line to reconstruct. The properties you never changed are not there, because a diff that lists fifty unchanged fields buries the one that moved.

  • — Only what actually changed — writing a value back unchanged records nothing.
  • — Masked fields show their projection, never the original.
  • — Truncated change sets say so in the record rather than silently dropping fields.
reldavi.com — Event detail updated shop.order Order A-1042 2026-09-19 14:32:07 PROPERTY BEFORE AFTER Status − Pending + Shipped ShippedAt + 2026-09-19 14:32 CardNumber − ************1111 + ************4242 Total − 1,249.00 + 1,099.00 TrackingNo + TR884210933 Who Emre Şahin IP address 203.0.113.9 Correlation id req-8f2c41 Source dotnet-efcore · web-02
Timeline · Order A-1042 Timeline · Order A-1042 Order created 2026-09-12 09:14 · Ayşe Yıldırım Total updated 2026-09-14 11:02 · Mehmet Öztürk Status → Confirmed 2026-09-17 16:48 · Emre Şahin Status → Shipped 2026-09-19 14:32 · Emre Şahin Record archived 2026-09-19 18:05 · system

The full history of one record, in order.

Open any invoice, order or account and see everything that ever happened to it: who created it, every edit since, and who deleted it. Unbounded in time — the question "what happened to this record" does not come with a date range attached.

  • — One record's entire life, however far back your retention goes.
  • — Jump from any timeline entry straight into its diff.
  • — Shareable links, so a finding travels with its evidence.

Find the change, not the haystack.

Filter by resource, actor, action, correlation id or free text, across a window of any size. Results come back from a columnar store built for exactly this shape of question, not from a table fighting your production workload.

  • — Filter by who, what, when, which project and which request.
  • — Turkish-aware case-insensitive search — “İstanbul” matches “istanbul”.
  • — Cursor pagination, so page fifty costs the same as page one.
Audit trail Audit trail From 2026-09-01 To 2026-09-19 Resource type shop.order Actor All Apply Clear WHEN ACTION WHAT WHO CHANGES updated Sep 19, 14:32 shop.order Order A-1042 Emre Şahin 2 created Sep 19, 13:58 billing.invoice Invoice INV-8821 Ayşe Yıldırım 5 updated Sep 19, 11:20 shop.order Order A-1039 Mehmet Öztürk 1 deleted Sep 19, 10:05 identity.user User U-204 system 7 updated Sep 18, 17:44 billing.invoice Invoice INV-8814 Zeynep Çelik 3 created Sep 18, 16:12 shop.order Order A-1038 Can Demir 6

Integration

Three lines. Then stop thinking about it.

The .NET SDK hooks EF Core's save pipeline. You annotate what matters, and every insert, update and delete records itself from then on.

Install the package

One dotnet add package. It multi-targets .NET 8 and .NET 10, so you do not have to upgrade first.

Wire it up

Register the client, attach the interceptor to your DbContext, add the middleware that supplies the current user.

Mark what is sensitive

Attributes decide what is recorded, what is ignored and what is masked before it ever leaves your process.

That is the whole integration. No schema migration, no trigger, no change to your business logic.

// 1 · Install
dotnet add package Reldavi.EntityFrameworkCore
dotnet add package Reldavi.Client

// 2 · Program.cs
builder.Services.AddReldaviClient(options =>
{
    options.Endpoint = new Uri("https://ingest.reldavi.com");
    options.ApiKey   = builder.Configuration["Reldavi:ApiKey"]!;
});

builder.Services.AddReldaviEntityFrameworkCore(options =>
    options.MaskHashSecret = builder.Configuration["Reldavi:MaskSecret"]);

builder.Services.AddDbContext<ShopDbContext>((sp, options) => options
    .UseNpgsql(connectionString)
    .UseReldavi(sp));

// 3 · After authentication, so changes are attributed to a real user
app.UseAuthentication();
app.UseReldavi();

Performance

Auditing that cannot slow you down.

The capture path does no network calls, takes no locks and never awaits. When the buffer fills, it sheds load and tells you — because an audit pipeline having a bad day must never become your checkout having a bad day.

Your infrastructure Your app EF Core interceptor Buffer In memory, bounded Ingestion Batched, gzipped Event store Columnar, compressed Masking happens here Nothing here is on your request path

No I/O on your thread

Capture writes into an in-memory buffer and returns. Every network call happens on a background dispatcher.

Fails open, loudly

A capture error is logged and swallowed, never raised into your transaction. Dropped events are counted so you can alert on them.

Rollback leaves no trace

Events are published only after your transaction commits. A failed save records nothing — as it should.

Batched and compressed

Events ship in batches, gzipped. Audit JSON is highly repetitive and compresses by roughly an order of magnitude.

And here is the number

Capturing one event costs the calling thread about two microseconds at the 99th percentile — the call your code makes inside its own transaction, not the delivery, which happens later on a background thread. The harness that measures it ships in the repository as build/loadtest.sh, so you can run it on your own hardware rather than taking the figure from a marketing page. It also fails the build if the number moves by an order of magnitude, which is the regression worth catching: somebody making capture synchronous.

Zero-PII

Sensitive values never leave your servers.

Masking happens inside your process, before anything is buffered. We cannot leak what we were never sent.

Mark a property [AuditMask] and Reldavi records a projection instead of the value: the last four digits of a card, a keyed hash of a national ID that stays searchable without being reversible, a redacted password. The original is never written to the buffer, never serialized onto the wire, and never reaches our storage.

Read the security overview

IN YOUR APPLICATION WHAT WE RECEIVE 4242 4242 4242 4242 ************4242 12345678901 sha256:9f2b1c74a0e8… emre@contoso.com e***@contoso.com P@ssw0rd! ***

Compliance

Which obligation are you answering?

Five rules that turn a change history from good practice into something somebody can fine you for. All four work today, including the agent-specific record the AI Act asks for.

KVKK

Processing records, retention periods and destruction. Masking happens at source, and the data can stay in Türkiye or on your own servers.

GDPR

Article 30 records of processing and Article 17 erasure, with data minimisation by design — the SDK records the properties you mark and nothing else.

EU AI Act, Article 12

In force since 2 August 2026: high-risk AI systems must record events automatically, and Article 26 makes deployers keep those logs for at least six months. Events carry a first-class agent record — model, version, tool call, whose authority, and the whole prompt rather than four kilobytes of it.

GoBD (Germany)

German tax law has a word for what this is: Revisionssicherheit. Records must be complete, traceable to who made them, unalterable once written, and readable for ten years — and an auditor may ask for them in a machine-readable export. Sealed daily roots make "unalterable" something somebody can check rather than something a vendor asserts, and the export is CSV or NDJSON with the hashes beside it.

SOC 2 and ISO 27001

Change history with actor attribution, records that nothing edits, defined retention and evidence you can export.

Language-agnostic

Your .NET service is not your only service.

The ingestion contract is a published JSON Schema. Every client implements the same one, so a Go worker and a Python job land in the same timeline as your ASP.NET API.

.NET

Automatic capture through an EF Core interceptor. Nothing to call by hand.

Node.js

Zero dependencies, no build step. diff() helper included.

Python

No runtime dependencies — the client speaks HTTP over the standard library.

Go

Standard library only. A buffered channel and one background dispatcher.

Every SDK guarantees the same thing: capture never blocks, never throws, masks before buffering, and drains on shutdown. All four are MIT licensed, so the capture layer is yours whether or not the platform is.

And we check that they actually agree

Four implementations of one wire format drift in the way nobody notices — a field spelled differently in one of them, a timestamp without its offset, a body encoded as Latin-1 — and the place it surfaces is your integration, on the day you are wiring up a second service. So every build runs all four SDKs against a real ingestion endpoint over a real socket, posts the same event from each, and reads it back through the real query API. One expected row, four languages. A language whose toolchain is missing is reported as unchecked, never as passing.

Deployment

Our servers or yours. Same product.

Reldavi Cloud

We run it. You get an endpoint and a dashboard, and we handle scaling, upgrades and backups.

  • — Up in minutes
  • — Managed retention and archival
  • — Regional data residency

Self-hosted

One compose file brings up the whole stack on your infrastructure. Nothing calls home.

  • — Flat price, unlimited events
  • — Your network, your backups
  • — Air-gapped friendly — no CDN, no external fonts

Pricing

Priced per event, not per person.

Audit logging is infrastructure, so it should not cost more because your team grew. Every plan includes unlimited users, the full dashboard and every SDK.

Free

$0/month

100,000 events a month

Team

$49/month

2,000,000 events a month

Business

$199/month

10,000,000 events a month

Enterprise

$899+/month

50,000,000+ events a month

Pricing

Start recording today. Answer the audit next year.

Free for 100,000 events a month, forever. No credit card, no sales call.

Or read who builds this, and what it refuses to do.