Skip to main content
Wildo.ai Coming soon

Audit trail

Keep a separate copy of your audit history

Wildo can copy older audit records into dated JSON artifacts in object storage. Your operational trail remains available, while a separate archive supports longer-term review and controlled handover.

A dated archive receives a copy of the audit history while the original remains.

Keep a separate copy of your audit history

Wildo can copy older audit records into dated JSON artifacts in object storage. Your operational trail remains available, while a separate archive supports longer-term review and controlled handover.

Archiving copies the records. It does not delete the originals.

Example — Keep a separate historical copy

An operator archives events older than three months. A reviewer receives the daily files for a selected period while administrators continue querying the original events through the application.

For engineers

The shared auditTrail configuration declares archiveAfterDays. This illustrative fragment opts into copying events older than 90 days; keep it in the authored application configuration, not a generated environment file.

auditTrail: {
  archiveAfterDays: 90,
},

Configure a reachable file-storage provider and run the application’s batch scheduling path. The registered audit-logs-archive job checks the current horizon on each execution. With no horizon, it performs no archive work and leaves the primary trail intact.

Recover missed days without a separate checkpoint

The batch writes a deterministic artifact per UTC day. It rewrites recent archivable windows and probes older windows for missing artifacts, so retrying the same period does not create a second archive identity. Successful artifact presence is the progress record.

For a first archival run over existing history, the batch input supplies explicit overrides:

Selected source from audit-logs-archive.batch.backend.service.ts:

export const AuditLogsArchiveBatchInputSchema = z.object({
  /** One-shot archival horizon override (days). Falls back to app config. */
  archiveAfterDaysOverride: z.number().int().min(1).max(2555).optional(),
  /** One-shot look-back width override (days) — for cold-start backfills. */
  lookbackDaysOverride: z.number().int().min(1).max(MAX_LOOKBACK_DAYS).optional(),
  /**
   * One-shot width override (days) for the missing-artifact probe sweep that runs BEYOND the
   * look-back. `0` disables the sweep for this run (pure look-back behaviour).
   */
  backfillProbeDaysOverride: z.number().int().min(0).max(MAX_LOOKBACK_DAYS).optional(),
}).strict();

This is the AuditLogsArchiveBatchInputSchema; use its lookbackDaysOverride when dispatching a wider historical run. Inspect error, windowsArchived, recordsArchived and truncatedWindows in the batch result, then check the corresponding storage artifacts. A complete archive interval needs zero truncated windows and the expected dates; artifact presence alone does not prove that every record was copied. A bounded scheduled look-back is recovery for missed runs, not an unlimited historical scan.

Follow one run from input to artifact

This illustrative operator scenario keeps the configured 90-day horizon and scans just the most recent fully archivable UTC day. It disables the older missing-artifact sweep for this invocation.

The following is a backend invocation fragment, not a public endpoint. batchExecutor is the initialized BatchesCronjobsExecutor_BackendService with the engine archive batch registered. Run it only from trusted operator-controlled backend code: the executor creates the batch’s internal context, and this archive is application-wide.

const result = await batchExecutor.executeCustomBatch('audit-logs-archive', {
  lookbackDaysOverride: 1,
  backfillProbeDaysOverride: 0,
});

Ordinary scheduled execution uses the registered batch and its configured defaults. The direct executor call above returns the batch result; a scheduler’s accepted-publication response does not return or prove that result.

Suppose the invocation begins at noon UTC on September 12, 2026, and the selected day contains two eligible records. These are illustrative result values, not an observed production run:

{
  "tickAt": "2026-09-12T12:00:00.000Z",
  "enabled": true,
  "archiveAfterDays": 90,
  "horizonAt": "2026-06-14T12:00:00.000Z",
  "storageConfigured": true,
  "lookbackDays": 1,
  "backfillProbeDays": 0,
  "windowsBackfilled": 0,
  "windowsScanned": 1,
  "windowsArchived": 1,
  "recordsArchived": 2,
  "truncatedWindows": 0,
  "error": null,
  "durationMs": 25
}

The horizon’s own day is not fully eligible, so this run selects June 13. The logical destination is the application-scoped audit-archive folder with the deterministic filename audit-archive-2026-06-13.json; the configured provider determines the physical storage path. A repeated write uses that same daily identity.

The artifact carries the following metadata. This shortened illustration omits the records array, which contains the two audit records in the actual artifact:

{
  "schemaVersion": 1,
  "kind": "audit-log-archive",
  "applicationId": "example-application",
  "dayWindowUtc": "2026-06-13",
  "windowStart": "2026-06-13T00:00:00.000Z",
  "windowEnd": "2026-06-14T00:00:00.000Z",
  "archivedAt": "2026-09-12T12:00:00.000Z",
  "recordCount": 2,
  "truncated": false
}

Check the application, window, record count and truncation flag against the intended run. An unrelated increase in storage object count is not evidence that this archive was written correctly.

Interpret an outcome before retrying

OutcomeResult signalsMeaning and next step
Disabledenabled: false, error: nullNo horizon was configured or supplied; no archive work runs
Storage absentenabled: true, storageConfigured: false, error: nullArchival was requested but skipped; configure a suitable provider before rerunning
Empty dayA window was scanned but produced no artifactNo records were selected for that day; a missing file can be legitimate
WrittenwindowsArchived and recordsArchived increaseInspect the corresponding artifact and its provenance; counts include rewritten daily artifacts
TruncatedtruncatedWindows > 0, artifact truncated: trueThe daily record cap was reached; that artifact is incomplete even if error is null
Errorerror contains a messageEarlier writes may remain; inspect partial counters and existing artifacts before deciding what to recover

The batch prefers configured Wildo-managed storage, then local-directory storage. A null error alone does not establish a write: disabled and unconfigured runs deliberately return non-error summaries. Failures during scanning or upload return the progress accumulated before the error rather than resetting it to zero.

Bound the historical interval deliberately

Only complete UTC days before the horizon’s day are selected. By default, each run rewrites the newest two eligible days and probes the preceding 90 days for missing artifacts. Existing probe-band artifacts are skipped; empty days intentionally produce no artifact.

The look-back and older probe span are capped together at 2,555 days. Increasing the look-back widens this horizon-relative interval; it is not an arbitrary start-date/end-date export API. A truncated artifact remains incomplete even when a later probe sees that its file exists. Review both coverage and truncation before treating an interval as complete.

Keep archive and retention decisions separate

The audit resource exposes no update or delete operation. Storage lifecycle, access to archived artifacts and the intended retention period remain operator decisions. This copy mechanism does not shrink the database or promise a backup of the rest of the application.

Choose the right audience for the artifact

The archive batch collects application-wide rows and explicitly bypasses contextual organization filtering. Its output is an operator artifact, not a customer-scoped download. For customer handover, use the bounded organization export and inspect its truncation result; do not hand over a raw application archive. Archival copies do not prune the primary rows.

Building a B2B product or an internal tool?

Wildo is not self-service yet. Tell us what you have in mind and we will say plainly whether it fits, and what happens next.