# How to Set Up the Database for Enterprise Audit Features in Stirling-PDF

> Set up your Stirling-PDF database for enterprise audit features easily. Configure settings.yml and let JPA automatically create the audit_events table to track user and system actions.

- Repository: [Stirling Tools/Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Enable Enterprise mode, configure the `premium.proFeatures.audit` block in [`settings.yml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/settings.yml), and let the JPA entity `PersistentAuditEvent` automatically create the `audit_events` table to start recording user actions and system events.**

Stirling-PDF's enterprise audit system provides comprehensive logging of user actions and system events for compliance and security investigations. To set up the database for enterprise audit features, you must activate the Enterprise edition, configure retention policies, and verify automatic schema generation. This guide references the actual source implementation in the Stirling-Tools/Stirling-PDF repository to ensure accurate configuration.

## Enable Enterprise Edition Mode

The audit subsystem only functions when the application runs in Enterprise mode. The `runningEE` flag is injected into the audit components via Spring's dependency injection system.

In [`app/proprietary/src/main/java/stirling/software/proprietary/service/AuditService.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/proprietary/src/main/java/stirling/software/proprietary/service/AuditService.java), the constructor requires the Enterprise flag:

```java
public AuditService(..., @Qualifier("runningEE") boolean runningEE) {
    this.runningEE = runningEE;
}

```

To enable Enterprise mode, set `enterpriseEdition.enabled: true` in your [`settings.yml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/settings.yml) file, or use the official Stirling-PDF Enterprise Docker image which pre-configures this flag.

## Configure Audit Settings

Add the audit configuration block under `premium.proFeatures.audit` in **[`settings.yml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/settings.yml)**. The application loads these properties through `ApplicationProperties` and maps them to [`AuditConfigurationProperties.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/AuditConfigurationProperties.java).

```yaml
premium:
  proFeatures:
    audit:
      enabled: true               # Master switch for audit logging

      level: 2                    # 0=OFF, 1=BASIC, 2=STANDARD, 3=VERBOSE

      retentionDays: 90           # Days to keep records (0 = forever)

```

- **`enabled`**: Globally toggles audit logging on or off.
- **`level`**: Controls verbosity. The `AuditLevel` enum clamps values 0-3, with `STANDARD` (2) logging most business operations.
- **`retentionDays`**: Sets the automatic cleanup window. Configure this based on your compliance requirements.

## Database Schema Generation

The audit data persists in a table automatically generated by the JPA entity `PersistentAuditEvent`. Located in [`app/proprietary/src/main/java/stirling/software/proprietary/model/security/PersistentAuditEvent.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/proprietary/src/main/java/stirling/software/proprietary/model/security/PersistentAuditEvent.java), this entity defines the schema structure:

```java
@Entity
@Table(name = "audit_events", indexes = {
    @Index(name = "idx_audit_timestamp", columnList = "timestamp"),
    @Index(name = "idx_audit_principal", columnList = "principal"),
    @Index(name = "idx_audit_type", columnList = "type")
})
public class PersistentAuditEvent {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id;
    private String principal;
    private String type;
    @Column(columnDefinition = "text") 
    private String data;   // JSON blob of event details
    private Instant timestamp;
}

```

When the application starts, Spring Data JPA automatically creates the `audit_events` table with three indexes for optimized querying by time, user, and event type. No manual SQL DDL is required unless you use a custom database schema with Flyway or Liquibase migrations.

## Persisting Audit Events

Stirling-PDF provides three methods to log events, ranging from programmatic API calls to automatic aspect-based logging.

### Programmatic Logging via AuditService

Inject `AuditService` into your business logic to manually record events with structured data. This method is implemented in [`app/proprietary/src/main/java/stirling/software/proprietary/service/AuditService.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/proprietary/src/main/java/stirling/software/proprietary/service/AuditService.java).

```java
@Service
@RequiredArgsConstructor
public class PdfProcessingService {
    private final AuditService auditService;

    public void processPdf(MultipartFile file) {
        // Process the PDF...
        auditService.audit("PDF_PROCESSED", Map.of(
            "filename", file.getOriginalFilename(),
            "size", file.getSize(),
            "operation", "process"
        ));
    }
}

```

The `audit(String type, Map<String, Object> data)` method stores the event at the configured `STANDARD` level by default.

### Aspect-Based Logging with @Audited

For declarative logging, use the `@Audited` annotation on service methods. The aspect logic resides in [`app/proprietary/src/main/java/stirling/software/proprietary/audit/AuditAspect.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/proprietary/src/main/java/stirling/software/proprietary/audit/AuditAspect.java).

```java
@Service
public class UserService {

    @Audited(type = "USER_REGISTRATION", level = AuditLevel.BASIC)
    public User registerUser(String username, String email) { 
        // Registration logic...
    }

    @Audited(type = "PASSWORD_CHANGE", level = AuditLevel.BASIC, includeArgs = false)
    public void changePassword(String username, String newPassword) { 
        // Security-sensitive: arguments excluded from audit log
    }
}

```

### Automatic Controller Auditing

All Spring MVC controller methods annotated with `@GetMapping`, `@PostMapping`, or other request mappings are automatically audited at **STANDARD** level without additional code. This captures every HTTP request to the application for complete access logging.

## Querying and Exporting Audit Data

The REST API in [`app/proprietary/src/main/java/stirling/software/proprietary/controller/api/AuditRestController.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/AuditRestController.java) exposes paginated endpoints for data retrieval and compliance export. All endpoints require the `ADMIN` role and are prefixed with `/api/v1/proprietary`.

**Key endpoints:**
- **`GET /audit-events?page=0&pageSize=30`** – Returns paginated `AuditEventsResponse` with filter support by date, user, and event type.
- **`GET /audit-charts?period=week`** – Aggregates event counts for dashboard visualization.
- **`GET /audit-export?format=csv&startDate=2024-01-01&endDate=2024-01-31`** – Downloads audit logs as CSV or JSON for external analysis.
- **`GET /audit-event-types`** – Lists distinct event types for UI filtering.
- **`GET /audit-users`** – Lists distinct principals (users) who generated events.

Example cURL command to export last month's audit data:

```bash
curl -O -J \
     "https://your-server/api/v1/proprietary/audit-export?format=csv&startDate=$(date -d '-30 days' +%F)&endDate=$(date +%F)" \
     -H "Authorization: Bearer <admin-token>"

```

## Retention Policies and Automated Cleanup

Old audit records are purged automatically by `AuditCleanupService` in [`app/proprietary/src/main/java/stirling/software/proprietary/service/AuditCleanupService.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/proprietary/src/main/java/stirling/software/proprietary/service/AuditCleanupService.java). The service runs daily using Spring's `@Scheduled` annotation:

```java
@Scheduled(fixedDelay = 1, timeUnit = TimeUnit.DAYS)
public void cleanupOldAuditEvents() {
    // Deletes records older than retentionDays configuration
}

```

Set `retentionDays: 0` in [`settings.yml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/settings.yml) to disable automatic deletion and retain audit data indefinitely for long-term compliance archives. The cleanup service skips deletion when this value is zero, ensuring permanent retention.

## Summary

- **Enable Enterprise mode** by setting the `runningEE` flag to `true` via [`settings.yml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/settings.yml) or environment configuration.
- **Configure audit parameters** under `premium.proFeatures.audit` to control logging levels and data retention.
- **Verify schema creation** by checking that JPA generates the `audit_events` table from the `PersistentAuditEvent` entity automatically.
- **Log events** programmatically via `AuditService.audit()`, declaratively with `@Audited`, or automatically through controller interception.
- **Access audit data** through the REST API endpoints in `AuditRestController` for real-time monitoring or CSV export.
- **Manage retention** using `AuditCleanupService`, which respects the `retentionDays` setting to purge old records daily.

## Frequently Asked Questions

### Does the open-source edition of Stirling-PDF support audit logging?

No, the audit subsystem requires the Enterprise edition. The `AuditService` and related components check the `runningEE` flag during initialization, and all audit REST endpoints are annotated with `@EnterpriseEndpoint` to block access in open-source deployments. You must enable Enterprise mode via `enterpriseEdition.enabled: true` in [`settings.yml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/settings.yml) or use the Enterprise Docker image.

### What database table stores the enterprise audit events?

Audit events persist in the **`audit_events`** table, defined by the `PersistentAuditEvent` JPA entity in [`app/proprietary/src/main/java/stirling/software/proprietary/model/security/PersistentAuditEvent.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/proprietary/src/main/java/stirling/software/proprietary/model/security/PersistentAuditEvent.java). The table includes columns for `principal` (username), `type` (event category), `data` (JSON payload), and `timestamp`, with indexes on all queryable fields for performance.

### How do I export audit logs for compliance reporting?

Use the **`/api/v1/proprietary/audit-export`** endpoint with `format=csv` or `format=json` parameters. Specify date ranges using `startDate` and `endDate` query parameters (ISO 8601 format). This endpoint is protected by `ADMIN` role requirements and streams the full audit dataset matching your filters for external compliance tools or archival storage.

### Can I customize how long audit records are retained?

Yes, set the `retentionDays` property under `premium.proFeatures.audit` in [`settings.yml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/settings.yml). The `AuditCleanupService` reads this value daily and deletes records older than the specified threshold. Set `retentionDays: 0` to keep audit events indefinitely, which is recommended for environments with strict compliance requirements mandating multi-year log retention.