Enable @PersonalData.IsPotentiallyPersonal and @cap-js/audit-logging for automatic CRUD audit trails.
@PersonalData annotations to mark sensitive fieldsGDPR and SOX mandate immutable audit records for access to personal data. SAP Audit Log Service provides a tamper-proof, cloud-hosted log. CAP's audit-log plugin can generate these automatically from @PersonalData annotations — no custom logging code required for standard CRUD.
// db/schema.cds
using { managed, cuid } from '@sap/cds/common';
entity Customers : cuid, managed {
@PersonalData.FieldSemantics: 'DataSubjectID'
customerNumber : String; // ← unique identifier for the data subject
@PersonalData.IsPotentiallyPersonal: true
firstName : String;
@PersonalData.IsPotentiallyPersonal: true
lastName : String;
@PersonalData.IsPotentiallySensitive: true
dateOfBirth : Date; // sensitive — stricter logging
email : String;
@PersonalData.IsPotentiallyPersonal: true
phoneNumber : String;
}
annotate Customers with @PersonalData: {
EntitySemantics: 'DataSubject',
DataSubjectRole: 'Customer'
};
npm install @cap-js/audit-logging
// .cdsrc.json
{
"requires": {
"audit-log": {
"[production]": {
"kind": "audit-log-service",
"vcap": { "label": "auditlog" }
},
"[development]": {
"kind": "@cap-js/audit-logging",
"impl": "@cap-js/audit-logging/lib/sqlite" // logs to console in dev
}
}
}
}
# mta.yaml
resources:
- name: auditlog
type: org.cloudfoundry.managed-service
parameters:
service: auditlog
service-plan: premium
modules:
- name: bookshop-srv
requires:
- name: auditlog
| Operation | Auto-logged |
|---|---|
READ of @PersonalData entity |
Data access log entry |
| CREATE with personal fields | Data modification log |
| UPDATE of personal fields | Before/after values |
DELETE of @PersonalData entity |
Data erasure log |
Each log entry includes: timestamp, user ID, tenant, operation, entity name, data subject ID, and field values (before/after for updates).
const audit = await cds.connect.to('audit-log')
this.on('exportCustomerData', async (req) => {
const { customerId } = req.data
const data = await SELECT.from('Customers').where({ ID: customerId })
// Manually log a data access event
await audit.log('SensitiveDataExport', {
object: { type: 'Customers', id: { ID: customerId } },
data_subject: { type: 'Customer', id: customerId },
attributes: [{ name: 'export', new_value: 'GDPR export triggered' }],
tenant: req.tenant
})
return data
})
auditlog → Open SAP Audit Log Viewer# In dev, audit entries appear in console:
[audit] READ Customers { user: 'alice', subject: { ID: 'cust-001' }, fields: ['firstName','email'] }
[audit] UPDATE Customers { user: 'alice', field: 'email', old: 'a@b.com', new: 'c@d.com' }
@PersonalData.IsPotentiallyPersonal marks fields for automatic audit logging@PersonalData.EntitySemantics: 'DataSubject' identifies the person entityaudit.log(event, payload) for custom operations