# Events, traces and audit logs

> How services tell each other what happened, and how every action is recorded.

Source: https://docs.dashfordevs.com/v1/how-it-works/events-and-logs · Topic: How the platform works · Updated: 2026-11-07

## Events: the outbox

When something happens in one service that another needs to know (an order is placed, so inventory must turn a reservation into a sale), the first service **publishes an event**.

```dfd-diagram
{
  "type": "flow",
  "title": "An event from orders to inventory",
  "layout": "LR",
  "nodes": [
    { "id": "tx", "label": "orders: save order", "kind": "service", "detail": "The order row and the outbox row are written in the SAME database transaction." },
    { "id": "outbox", "label": "outbox row", "kind": "data", "detail": "If the order rolls back, so does the event. Nothing is ever sent for a change that did not happen." },
    { "id": "dispatch", "label": "dispatcher", "kind": "service", "detail": "After commit, delivers the event. Retries with backoff, keeps order per record, dead-letters after repeated failure." },
    { "id": "tapi", "label": "tapi", "kind": "gateway" },
    { "id": "inv", "label": "inventory: /internal/events/", "kind": "service", "detail": "Verifies the HMAC signature, refuses replays, applies each event exactly once (by event id)." }
  ],
  "edges": [
    { "from": "tx", "to": "outbox", "label": "same transaction" },
    { "from": "outbox", "to": "dispatch", "label": "after commit" },
    { "from": "dispatch", "to": "tapi", "label": "signed request" },
    { "from": "tapi", "to": "inv" }
  ],
  "steps": [
    { "title": "Write once", "focus": ["tx", "outbox"], "text": "The change and the event are one transaction." },
    { "title": "Deliver after commit", "focus": ["dispatch"], "text": "A dispatcher sends it, retrying until it is acknowledged." },
    { "title": "Signed, through the gateway", "focus": ["tapi"], "text": "Every service-to-service call is signed with a pairwise key, and goes through tapi like everything else." },
    { "title": "Applied exactly once", "focus": ["inv"], "text": "The receiver checks the signature, ignores replays, and remembers which events it already applied." }
  ]
}
```

Events carry **ids and amounts, never personal data**. A receiver that needs details asks the owning service for them, with permission checks.

## Traces

Every action a person takes (opening a page, saving a product) is a **trace**. Every hop that served it (the dashboard, each service, any service that one called) sends one span: the route template, method, status, timing, who, which organization, and **which records and field names** were touched. Never a value. Members with `logs:read` see their organization's traces under **Organization → Logs**.

## Audit logs

Each service keeps its own **append-only, hash-chained audit log**. Every entry includes a hash of the previous one, so removing or editing an entry breaks the chain, and the chains are verified. Audit entries record ids and field names, never values. Staff can read every chain from the admin console; each staff read is itself audited.
