Audit log

Every action — login, magic-link hit, file download/upload, package create/revoke/delete, admin operations — is recorded with timestamp, IP, user-agent, and a JSON details blob.

Where to find it

Admin → SettingsAudit log. Or visit /admin/audit directly. Filter by action, paginate, see the full timeline.

Action names

ActionSource
login_successSuccessful sign-in
login_failBad password
self_pw_changeUser changed own password
password_reset_requestForgot-password email requested
password_reset_completePassword reset via emailed link
admin_create_pkgPackage created via web UI
admin_add_fileFile added to package via web UI
admin_revokePackage link revoked
admin_delete_pkgPackage permanently deleted
admin_create_user / admin_disable_user / admin_reset_pwUser management
api_create_pkg / api_add_file / api_revoke / api_delete_pkgREST API operations
token_viewRecipient opened the magic-link landing page
file_downloadRecipient downloaded a file
file_upload_start / file_upload_completeInbound upload from recipient
token_invalid / token_expired / token_revokedFailed magic-link access (410)
setup_completeFirst-run wizard completed

What's recorded per row

ColumnNotes
tsUTC timestamp (millisecond precision)
actionOne of the names above
user_idNULL for magic-link hits (no internal user)
package_idNULL for non-package events; preserved after package delete via SET NULL
ipClient IP from X-Forwarded-For (when uvicorn trusts the proxy)
user_agentFor public-route hits only
details_jsonEvent-specific extras: {"file_id":"...","size":12345} etc.

Retention & pruning

No automatic retention policy yet. The table grows linearly with use. For high-volume installations:

-- example: keep last 365 days
DELETE FROM access_log WHERE ts < datetime('now', '-365 days');

Exporting

From SQLite:

sqlite3 /data/app.db -header -csv \
  "SELECT * FROM access_log WHERE ts > date('now','-30 days')" \
  > audit-30d.csv

Or via the REST API (admin-scope token):

curl -H "Authorization: Bearer $TOKEN" \
  "https://files.example.com/api/v1/admin/audit?limit=500&action=file_download" | jq

(Note: admin-audit API endpoint is on the roadmap; currently audit is web-UI only.)