Database
LesliAudit uses collection code 05 and engine code 01. Its migrations live under db/migrate/v1.0 and are loaded into the host application's migration set.
| Migration code | Table | Responsibility |
|---|---|---|
05.01.00.01.10 | lesli_audit_accounts | Engine state for a Lesli account |
05.01.11.01.10 | lesli_audit_account_logs | Account-level activity records |
05.01.11.02.10 | lesli_audit_account_devices | Aggregated browser, platform, and device observations from successful logins |
05.01.11.03.10 | lesli_audit_account_requests | Account request counts by controller and action |
05.01.12.01.10 | lesli_audit_user_logs | User-specific activity records |
05.01.12.02.10 | lesli_audit_user_journals | Individual user request journals |
05.01.12.03.10 | lesli_audit_user_requests | User request analytics |
Choosing the Correct Record
The similarly named tables do not contain interchangeable data:
| Model and table | Record granularity | Primary use | Audit evidence? |
|---|---|---|---|
AccountLog / lesli_audit_account_logs | One explicitly emitted tenant-level business or security event | Account lifecycle and operations whose actor may be a user | Yes |
UserLog / lesli_audit_user_logs | One explicitly emitted user activity event | A user's business or security history | Yes |
AccountRequest / lesli_audit_account_requests | One counter per tenant, date, controller, and action | Traffic totals and controller trends | No |
UserRequest / lesli_audit_user_requests | One counter per tenant, user, optional session, date, controller, and action | Per-user request totals | No |
UserJournal / lesli_audit_user_journals | One normalized row per captured HTTP request | Detailed user timing and request history | No |
AccountDevice / lesli_audit_account_devices | One counter per tenant, date, platform, browser, and device category | Successful-login distribution by normalized agent category | No |
User requests versus user journals
UserRequest is an aggregate counter. Repeated matching requests increase request_count; the row is intended for totals and grouped reports. It does not preserve the time of every individual request and must not be used to prove that a business operation occurred.
UserJournal is an individual request event. Its tenant-scoped event_uid identifies the captured event, date stores its reporting and retention day, and created_at records the exact time it was stored. When enable_journals is true, normalized request, user, and session dimensions are available for operational history and working-hours reports.
In short:
- query
user_requeststo answer how many matching requests a user made; - query retained
user_journalsto answer when individual requests were captured; - query
user_logsto answer which explicit auditable operations the user performed.
Neither request table replaces UserLog. A controller request can finish without representing a business change, while one business operation may also emit multiple outcome events.
The accounts table uses create_table_lesli_shared_account_10(:lesli_audit) and adds a unique index over account_id, so each core account has exactly one audit account. Request and device tables use a dedicated date column for their aggregation bucket and normal Rails timestamps for record lifecycle metadata.
The engine owns its foreign-key lifecycle rules. Core account soft deletion keeps every physical row intact. Hard deletion cascades from the core account to its Audit account and then to all tenant audit data. A hard-deleted user cascades aggregate request rows and nullifies actor references on journals and activity events, preserving their immutable identity snapshots.
LesliAudit installs the audit association on Lesli::Account through LesliAudit::AccountAssociations. Every Audit-owned record then belongs to LesliAudit::Account, while user-owned records also reference Lesli::User. Destroying an Audit account is a deliberate hard purge and deletes its dependent Audit records.
The initial schema enforces required tenant and dimension columns, nonnegative 64-bit counters, and tenant-first unique indexes. Logger upserts identify these constraints by index name so column order can continue to support account-scoped access. Session identifiers remain nullable opaque references and do not create a database dependency on LesliShield.
Journal rows use a tenant-scoped unique event_uid. Request counters and journals are written synchronously by LesliAudit::LoggerInterface; no background analytics job or processing lifecycle is required.
Device dimensions follow a separate path. log_devices parses and aggregates the user agent only after a successful login; ordinary request logging never increments AccountDevice.
Account and user activity logs require an operation, use text for their human-readable description, and index account plus creation time for tenant history queries. User histories additionally index user plus creation time. actor_uid is an immutable identity snapshot: the user_id foreign key may be set to null when a user is hard-deleted, while the event and actor snapshot are retained. Persisted activity rows are append-only at the model layer; status changes such as attempted, failed, and succeeded are separate rows.
Run schema operations through the host application:
bin/rails lesli:db:prepare
bin/rails db:migrate:status
Run configured retention cleanup manually with:
bin/rails lesli_audit:retention:cleanup
The retention operation is available to host schedulers through LesliAudit::RetentionCleanupJob. Cleanup uses the date indexes for journals and analytics and the created_at indexes for activity histories, deleting in bounded batches. Activity histories are skipped while audit_retention_days is nil.
Audit data can grow quickly. New queries should remain account-scoped and be supported by indexes matching their filters and grouping columns.
The retention and reliability rules differ between aggregated analytics, short-lived journals, and durable activity events. See Architecture and Data Policy before changing a table or adding a new event source.
See Database Architecture and Migration Versioning for shared rules.
Last Update: 2026/10/23