EduShade
Audit Module

Export

Download audit logs as a JSON file with date-range and filter scoping

Export

The audit module exposes a single export endpoint — for audit logs only. It returns a JSON file scoped to the caller's tenant, optionally narrowed by date range, action, resource type, and module.

Endpoint

GET /v1/admin/audit/audit-logs/export
RequirementValue
AuthJWT
Permissionaudit.read
Tenant scopingAlways — from the JWT, never from the body

Request Body

Despite being a GET, the handler binds an ExportAuditLogsRequest (audit-service/dto/audit_log.go):

type ExportAuditLogsRequest struct {
    StartDate     time.Time   `json:"start_date"`     // required
    EndDate       time.Time   `json:"end_date"`       // required
    Format        string      `json:"format"`         // required, "csv" or "json"
    Actions       []string    `json:"actions"`
    ActorIDs      []uuid.UUID `json:"actor_ids"`
    ResourceTypes []string    `json:"resource_types"`
    Modules       []string    `json:"modules"`
}

Validation:

  • start_date, end_date, format are required.
  • format must be "csv" or "json" — but see the next section.

Output Format

Today: JSON only. Although format accepts "csv", the service hard-codes json.MarshalIndent and emits a .json filename. Passing format=csv will be accepted by validation, but the response body will still be JSON. Treat the parameter as forward-looking; CSV emission is not yet implemented.

The response body is a pretty-printed JSON array of audit log objects (the same AuditLogResponse shape returned by the list endpoint, sans pagination wrapper).

The filename is set on Content-Disposition:

audit_logs_2026-04-21_15-04-05.json

Filter Behaviour

This is the most surprising part of the export endpoint — read carefully:

Array filters are truncated to the first element. Actions, ResourceTypes, and Modules are sent as arrays in the request body. The service uses only req.Actions[0], req.ResourceTypes[0], req.Modules[0] when building the underlying filter. ActorIDs is ignored entirely.

Source: audit-service/services/audit_log_service.go::ExportAuditLogs:

if len(req.Actions) > 0 {
    filter.Action = req.Actions[0]
}
if len(req.ResourceTypes) > 0 {
    filter.ResourceType = req.ResourceTypes[0]
}
if len(req.Modules) > 0 {
    filter.Module = req.Modules[0]
}

Practically, this means:

  • Sending actions: ["create", "delete"] will export only create rows.
  • Sending actor_ids: [...] will be silently dropped — the export will include all actors.
  • Date range and tenant scoping are honoured normally.

Frontend Wiring

The admin Audit Logs page exposes a bulk Export toolbar action through useExportAction (frontend/src/lib/audit/actions.ts::exportAuditLogs). It always hits the same endpoint and downloads the resulting Blob as a JSON file.

The Activity Logs page also surfaces an Export button in its toolbar — but there is no activity-log export endpoint on the backend. The button currently routes through the same generic export plumbing as audit logs; treat it as a known UI gap until an activity-logs/export endpoint exists.

Pagination

The export does not paginate — it serializes whatever the underlying paginated query returns for the default page size of 50. To export a longer date range you currently need to:

  1. Call the list endpoint repeatedly with explicit page / per_page, or
  2. Tighten start_date / end_date until each export fits in 50 rows, or
  3. Run an offline query against the database directly.

This is a known sharp edge. If your retention window is small (default 90 days for activity, 365 days for audit), 50 rows often won't cover much.

Until the export endpoint paginates, treat it as a convenience for short-window snapshots:

  • "Give me the last hour of deletes" — works well.
  • "Give me everything from the last quarter for compliance review" — use the API list endpoint with explicit pagination instead, or query Postgres directly with audit.read-equivalent privileges.

Source

  • DTO: audit-service/dto/audit_log.go
  • Handler: audit-service/api/handlers/audit_log_handler.go::ExportAuditLogs
  • Service: audit-service/services/audit_log_service.go::ExportAuditLogs
  • Frontend client: frontend/src/lib/audit/actions.ts::exportAuditLogs

On this page