"""Structured audit lines for Workflow Studio mutating APIs. These are operator logs, not a separate audit table: every line is a single JSON object with a stable ``action`` plus the ids needed to reconstruct who did what. Secrets never go in. """ from __future__ import annotations import json import logging from typing import Any logger = logging.getLogger("deerflow.workflows.audit") def audit_workflow(action: str, *, user_id: str, **fields: Any) -> None: payload = {"action": action, "userId": user_id, **fields} logger.info("workflow.audit %s", json.dumps(payload, ensure_ascii=False, default=str)) __all__ = ["audit_workflow"]