Packages

Explicit semantic audit events for Ecto and PostgreSQL

Current section

Files

Jump to
audit_log ROADMAP.md
Raw

ROADMAP.md

# Roadmap
The core library stays framework-agnostic. Integrations belong in small
companion packages that translate framework data into explicit
`AuditLog.Context` values.
## Phoenix scope adapter
Build `audit_log_phoenix` as a separate package only after the core API
stabilises. This roadmap does not yet define the stability criterion.
Use Phoenix scopes as the audit-context boundary because applications already
pass them explicitly to context functions. The adapter must construct the
context at that boundary. It must not hide context in the process dictionary,
make `record!/5` inspect the current connection, or infer business actions from
routes and HTTP methods.
### Scope mapping
Phoenix scopes are application-defined and have no universal actor shape. The
adapter must require an application mapper:
```elixir
defmodule MyApp.AuditScope do
@behaviour AuditLogPhoenix.ScopeMapper
alias AuditLog.Actor
alias MyApp.Accounts.Scope
@impl true
def actor(%Scope{user: user}) do
Actor.new("user", user.id, label: user.email)
end
@impl true
def metadata(%Scope{organization: organization}) do
%{organization_id: to_string(organization.id)}
end
end
```
The application must decide the actor type, stable ID, snapshot label, and
tenant metadata. The adapter must not guess them from arbitrary structs.
### Controller requests
A Plug must build one context per HTTP request and store it under a
library-prefixed `conn.private` key:
```elixir
plug Plug.RequestId, assign_as: :request_id
plug AuditLogPhoenix.Plug,
scope_assign: :current_scope,
mapper: MyApp.AuditScope,
router: MyAppWeb.Router
```
Controllers and application contexts must retrieve and pass the context
explicitly:
```elixir
context = AuditLogPhoenix.context!(conn)
Accounts.correct_address(context, shareholder, attrs)
```
The Plug automates collection, not event recording. The domain operation still
chooses the action, subject, reason, and transaction boundary.
### Safe request metadata
By default, the Plug must collect only:
- request method;
- matched route pattern rather than the raw path;
- controller and action;
- the validated Plug request ID; and
- metadata returned by the application scope mapper.
Do not collect parameters, request bodies, query strings, cookies, sessions,
arbitrary headers, authorization values, or full URLs. Require applications to
opt in before collecting IP addresses or user agents because those values may
be sensitive, misleading, or unbounded.
The Plug request ID belongs in metadata. It is not necessarily a UUID and
therefore cannot automatically become the audit correlation ID. Generate one
correlation UUID per request unless the application supplies a separately
validated UUID.
### LiveView
A LiveView process can handle several business operations after mount. Reusing
one context for the socket's lifetime would group unrelated actions under one
correlation ID.
The first LiveView API must construct one context for each state-changing
client event:
```elixir
context =
AuditLogPhoenix.context!(socket,
event: "save"
)
```
The context must use the actor from `socket.assigns.current_scope`, generate a
new correlation UUID, and record the LiveView module and client event in
metadata. Add hook-based assignment only if tests show that every tested event
and socket receives an isolated context.
### Asynchronous follow-up work
Jobs must continue to use `Context.child/4` with the service actor that performs
the work. They must preserve the originating correlation ID and record the
causing event ID. Attributing later service work to the initiating web user
would be false.
### Delivery order
1. Define and test the `ScopeMapper` behaviour.
2. Add Plug context construction and safe request metadata.
3. Add controller integration tests for missing scopes and malformed IDs.
4. Add per-event LiveView context construction.
5. Test request, socket, task, and connection isolation.
6. Publish the adapter independently from the core package.
Automatic event generation, action inference, parameter capture, background-job
framework integrations, and ambient context remain out of scope.