Skip to content

Change History

Q-Framework enables automatic change history tracking with a single entity declaration. No separate audit logic implementation is required.

Enabling Change History

java
@QfEntity(
    appKey = "app",
    name = @QfI18n(defaultMessage = "Product", texts = { @QfI18nText(locale = "ko", message = "상품") }),
    autoHistoryEnabled = true     // this single declaration enables change history
)
public class ProductEntity {

    @QfListAttribute(sortable = true)
    @QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfUpdateAttribute
    @QfDisplayLabel(text = "Product Name")
    private String name;

    @QfListAttribute(sortable = true)
    @QfCreateAttribute
    @QfUpdateAttribute
    @QfDisplayLabel(text = "Price")
    private Integer price;
}

Auto-Generated History API

GET /api/app/products/{id}/history

Example Response

json
{
  "success": true,
  "data": [
    {
      "historyId": "h-001",
      "action": "UPDATE",
      "changedAt": "2026-03-15T10:30:00",
      "changedBy": "user-123",
      "changedByName": "Jane Smith",
      "changes": [
        {
          "field": "price",
          "fieldLabel": "Price",
          "before": "10000",
          "after": "12000"
        }
      ]
    },
    {
      "historyId": "h-000",
      "action": "CREATE",
      "changedAt": "2026-03-01T09:00:00",
      "changedBy": "user-100",
      "changedByName": "John Doe"
    }
  ]
}

Automatic CRUD Audit Annotations (Modifier)

Automatically records the creator, updater, creation timestamp, and update timestamp.

java
@QfEntity(
    appKey = "app",
    name = @QfI18n(defaultMessage = "Product", texts = { @QfI18nText(locale = "ko", message = "상품") }),
    autoHistoryEnabled = true
)
public class ProductEntity {

    // ... business fields ...

    @QfCreatedBy              // automatically records creator ID
    private String createdBy;

    @QfCreatedAt              // automatically records creation timestamp
    private LocalDateTime createdAt;

    @QfUpdatedBy              // automatically records updater ID
    private String updatedBy;

    @QfUpdatedAt              // automatically records update timestamp
    private LocalDateTime updatedAt;
}

Fields declared with @QfCreatedBy, @QfCreatedAt, @QfUpdatedBy, and @QfUpdatedAt are automatically populated from the current user information returned by QfUserProvider. No manual assignment is needed.


Frontend History UI

vue
<template>
  <!-- History view UI rendered automatically -->
  <QfEntityHistory
    client-app="app"
    entity="product"
    :entity-id="productId"
  />
</template>

History Retention Policy

yaml
qf:
  history:
    retention-days: 365    # history retention period (days)
    max-records: 1000      # maximum history records per entity

TIP

History data is stored in a separate history table. Main table performance is not affected.


Next Steps

Released under the Apache 2.0 License.