### Example Mandatory Workflow for Adding Event Tracking Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Illustrates the correct approach to adding event tracking to a new resource, emphasizing planning, documentation review, and proper configuration before implementation. ```text User: "Add event tracking to a new User resource" CORRECT Approach: 1. Plan the implementation steps: - Read relevant core files (lib/events/events.ex, etc.) - Study test patterns in test/support/accounts/user.ex - Check generated DSL docs in documentation/dsls/ if needed - Create User resource with AshEvents.Events extension - Configure event_log reference - Add actor attribution to actions - Test event creation INCORRECT Approach: - Jumping straight to editing User resource - Adding AshEvents.Events extension without understanding configuration - Forgetting to configure event_log reference - Missing actor attribution setup ``` -------------------------------- ### Define User Resource with Event Logging Source: https://github.com/ash-project/ash_events/blob/main/README.md Configure a User resource to use AshEvents and define an event log resource. This example shows how to trigger a welcome email after user creation using an after_action hook. ```elixir defmodule MyApp.Accounts.User do use Ash.Resource, extensions: [AshEvents.Events] events do event_log MyApp.Events.Event end attributes do uuid_primary_key :id attribute :email, :string attribute :name, :string end actions do create :create do accept [:email, :name] change after_action(fn cs, record, ctx -> MyApp.Notifications.EmailNotification |> Ash.Changeset.for_create(:send_email, %{ recipient_email: user.email, template: "welcome_email", data: %{ user_name: user.name }, ash_events_metadata: %{ triggered_by: "user_creation", user_id: user.id } }) |> Ash.create!() {:ok, record} end) end end end ``` -------------------------------- ### Debug Event Creation in IEx Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/quick-reference.md Workflow for debugging event creation issues. Starts by running the test suite, then inspects the event log configuration, and finally tests with a minimal example in IEx. ```bash # 1. Run full test suite to identify failures mix test.reset && mix test # 2. Inspect event log configuration manually iex -S mix > MyApp.Events.EventLog.__ash_extension_config__() # 3. Test with minimal example in IEx # Create simple action with explicit actor, verify event created ``` -------------------------------- ### Branch Naming Convention Examples Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Examples of descriptive branch names based on issue type and number, following a consistent convention for bug fixes and features. ```bash # Bug fixes: fix/- # Features: feat/- # Example: fix/87-ash-phoenix-nested-forms ``` -------------------------------- ### Define Event Log Resource with AshEvents.EventLog Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Always start by creating a centralized event log resource using the AshEvents.EventLog extension. Configure primary key type and actor persistence. ```elixir defmodule MyApp.Events.Event do use Ash.Resource, extensions: [AshEvents.EventLog] event_log do # Required: Module that implements clear_records! callback clear_records_for_replay MyApp.Events.ClearAllRecords # Recommended for new projects primary_key_type Ash.Type.UUIDv7 # Store actor information persist_actor_primary_key :user_id, MyApp.Accounts.User persist_actor_primary_key :system_actor, MyApp.SystemActor, attribute_type: :string end end ``` -------------------------------- ### Ash Event Log Structure Example Source: https://github.com/ash-project/ash_events/blob/main/README.md An example of the structure for an event log entry in MyApp.Events.Event. This captures details about the event, including resource, action, data, and metadata. ```elixir %MyApp.Events.Event{ id: "123e4567-e89b-12d3-a456-426614174000", resource: MyApp.Accounts.User, record_id: "8f686f8f-6c5e-4529-bc78-164979f5d686", action: :create, action_type: :create, user_id: "d7874250-4f50-4e72-b32c-ff779852c1bd", # if persist_actor_primary_key is configured data: %{ "name" => "Jane Doe", "email" => "jane@example.com" }, changed_attributes: %{ "status" => "active", # Default value applied "slug" => "jane-doe", # Auto-generated from name "uuid" => "550e8400-e29b-41d4-a716-446655440000" # Auto-generated UUID }, metadata: %{ "source" => "api", "request_id" => "req-abc123" }, version: 2, occurred_at: ~U[2023-06-15 14:30:00Z] } ``` -------------------------------- ### Configure Custom Advisory Lock Key Generator Source: https://github.com/ash-project/ash_events/blob/main/README.md Configure a custom `AshEvents.AdvisoryLockKeyGenerator` behavior module to implement a different strategy for setting specific advisory lock keys. This example also sets a default advisory lock value. ```elixir event_log do persist_actor_primary_key :user_id, MyApp.Accounts.User persist_actor_primary_key :system_actor, MyApp.SystemActor, attribute_type: :string advisory_lock_default_value 31337 # or [1337, 31337] advisory_lock_key_generator MyApp.MyCustomAdvisoryLockKeyGenerator end ``` -------------------------------- ### Add ash_events Dependency Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/readme-update-guide.md Add `ash_events` to your dependencies in `mix.exs` to install the package. ```elixir defp deps do [ {:ash_events, "~> 0.4.0"} ] end ``` -------------------------------- ### Example Scenario for Changed Attributes Tracking Source: https://github.com/ash-project/ash_events/blob/main/README.md Illustrates how AshEvents captures attributes that are modified during an action but were not part of the original input, such as defaults or auto-generated fields. ```elixir # Original input User |> Ash.Changeset.for_create(:create, %{ name: "John Doe", email: "john@example.com" }) |> Ash.create!(actor: current_user) # If your User resource has: # - status: defaults to "active" # - slug: auto-generated from name ("john-doe") # These will be captured as changed_attributes in the event ``` -------------------------------- ### Create User and Observe Event Data Source: https://github.com/ash-project/ash_events/blob/main/README.md Demonstrates creating a user with specific attributes and shows the resulting event data, including changed attributes. This illustrates how auto-generated attributes are captured. ```elixir # When you create a user: user = User |> Ash.Changeset.for_create(:create, %{ name: "Jane Smith", email: "jane@example.com" }) |> Ash.create!(actor: current_user) # The event will contain: # event.data = %{"name" => "Jane Smith", "email" => "jane@example.com"} # event.changed_attributes = %{"status" => "active", "slug" => "jane-smith"} ``` -------------------------------- ### Run Test Database Migrations Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Runs migrations for the test database. Use this to apply schema changes to the test environment. ```bash mix test.migrate ``` -------------------------------- ### Testing Commands Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Commands for running tests, including options for detailed output. ```bash mix test # Run all tests (41 tests, ~1 second) mix test --trace # Run tests with detailed output ``` -------------------------------- ### Create Worktree and Switch Branch Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md This script uses cmux to open a new terminal split and then uses 'wt switch' to create a new worktree and branch for development. It includes a verification step. ```bash # Open a temporary split in the current workspace cmux new-split right # => returns surface: # Create the worktree (wt switch auto-cds into it) cmux send --surface surface: "wt switch -c " cmux send-key --surface surface: Enter # Wait and verify it completed sleep 5 && cmux read-screen --surface surface: --lines 20 ``` -------------------------------- ### Database Management Commands Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Commands for managing the test database, including resetting, creating, and migrating. ```bash mix test.reset # Reset test database (preferred) mix test.create # Create test database mix test.migrate # Run migrations mix test.generate_migrations # Generate migrations ``` -------------------------------- ### List Open GitHub Issues Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Use the GitHub CLI to list open issues. This is the first step in identifying an issue to work on. ```bash gh issue list --state open ``` -------------------------------- ### Create Test Database Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Creates the test database. This command is part of the test database management workflow. ```bash mix test.create ``` -------------------------------- ### Define Event Log Resource Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Sets up a resource to act as an event log. Configure `clear_records_for_replay`, `primary_key_type`, and `persist_actor_primary_key` for specific event logging needs. ```elixir defmodule MyApp.Events.Event do use Ash.Resource, extensions: [AshEvents.EventLog] event_log do clear_records_for_replay MyApp.Events.ClearAllRecords primary_key_type Ash.Type.UUIDv7 persist_actor_primary_key :user_id, MyApp.User end end ``` -------------------------------- ### Create an Event Log Resource Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/readme-update-guide.md Define an Event Log resource using the `AshEvents.EventLog` extension. Configure `clear_records_for_replay` if needed. ```elixir defmodule MyApp.Events.Event do use Ash.Resource, extensions: [AshEvents.EventLog] event_log do clear_records_for_replay MyApp.Events.ClearAllRecords end end ``` -------------------------------- ### Run All Quality Checks Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Executes all quality checks for the project. Use this to ensure code quality and adherence to standards. ```bash mix check ``` -------------------------------- ### Enable Event Logging on Resources Source: https://github.com/ash-project/ash_events/blob/main/README.md Add the `AshEvents.Events` extension to resources that need event tracking. Specify the event log resource and optionally ignore certain actions or define current action versions. ```elixir defmodule MyApp.Accounts.User do use Ash.Resource, extensions: [AshEvents.Events] events do # Specify your event log resource event_log MyApp.Events.Event # Optionally ignore certain actions. This is mainly used for actions # that are kept around for supporting previous event versions, and # are configured as replay_overrides in the event log (see above). ignore_actions [:old_create_v1] # Optionally specify version numbers for actions current_action_versions create: 2, update: 3, destroy: 2 end # Rest of your resource definition... attributes do # ... end actions do # ... end end ``` -------------------------------- ### Run All Tests Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Executes all tests in the project. This is a fundamental command for verifying code correctness. ```bash mix test ``` -------------------------------- ### Debug DSL Configuration in IEx Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/quick-reference.md Workflow for debugging Ash DSL configuration issues. Includes checking compilation, inspecting generated configurations, verifying field visibility, and testing DSL options manually in IEx. ```bash # 1. Check DSL compilation mix compile --force --warnings-as-errors # 2. Inspect generated configuration iex -S mix > MyResource.__ash_extension_config__() > MyResource.__ash_events_config__() # 3. Check EventLog public_fields configuration iex -S mix > AshEvents.EventLog.Info.event_log_public_fields!(MyApp.EventLog) > # Returns: :all, [:id, :version], or [] # 4. Verify field visibility iex -S mix > attrs = Ash.Resource.Info.attributes(MyApp.EventLog) > Enum.filter(attrs, & &1.public?) # 5. Test DSL options manually in IEx ``` -------------------------------- ### Minimal usage-rules.md Template Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/usage-rules-update-guide.md A basic structure for a usage-rules.md file, including essential sections like Quick Reference, Core Patterns, Common Gotchas, Advanced Features, Troubleshooting, and External Resources. ```markdown # PackageName Usage Rules ## Quick Reference - Key requirement: [Most critical configuration step] - Primary usage: [Most common command/pattern] ## Core Patterns [Most common usage patterns with examples] ## Common Gotchas - **Critical**: [Most important constraint] - [Other common issues] ## Advanced Features [Optional but important capabilities] ## Troubleshooting [Common errors and solutions] ## External Resources - [Official documentation](link) - [Important guides](link) ``` -------------------------------- ### Reset and Run All Tests Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/quick-reference.md Resets the test database and then runs the full test suite. This is a common command for verifying fixes and ensuring overall system health after changes. ```bash mix test.reset && mix test # Reset and run all tests ``` -------------------------------- ### Create Development Workspace with Claude Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md This command creates a new workspace with Claude running in the specified directory and sets up a tidewave split. It's used to prepare the development environment for an issue. ```bash # Create workspace with Claude running in the worktree directory cmux new-workspace --name "" --cwd --command "claude" # => returns workspace: # Add a right split for tidewave cmux new-split right --workspace workspace: # => returns surface: cmux send --workspace workspace: --surface surface: "mix tidewave" cmux send-key --workspace workspace: --surface surface: Enter ``` -------------------------------- ### Create Users with Automatic Event Logging Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/readme-update-guide.md After setting up event tracking, creating or updating resources will automatically log events. The `actor` can be specified during the action. ```elixir user = MyApp.User.create!(%{name: "John"}, actor: current_user) # Events are automatically created and stored ``` -------------------------------- ### Enable Event Tracking on Resources Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Add the AshEvents.Events extension to resources that need event tracking. Configure the event log resource, action versions, replay strategies, and sensitive attribute storage. ```elixir defmodule MyApp.Accounts.User do use Ash.Resource, extensions: [AshEvents.Events] events do # Required: Reference your event log resource event_log MyApp.Events.Event # Optional: Specify action versions for schema evolution current_action_versions create: 2, update: 3, destroy: 2 # Optional: Configure replay strategies for changed attributes replay_non_input_attribute_changes [ create: :force_change, # Default strategy update: :as_arguments, # Alternative strategy legacy_action: :force_change ] # Optional: Allow storing specific sensitive attributes (by default, sensitive attributes are excluded) store_sensitive_attributes [:hashed_password, :api_key] # Optional: Ignore specific actions (usually legacy versions) ignore_actions [:old_create_v1] end # Rest of your resource definition... end ``` -------------------------------- ### Configure Event Log Settings Source: https://github.com/ash-project/ash_events/blob/main/documentation/dsls/DSL-AshEvents.EventLog.md Configure the event log for a resource, including clearing records for replay, setting record ID types, and persisting actor primary keys. ```elixir event_log do clear_records_for_replay MyApp.Events.ClearAllRecords record_id_type :integer # (default is :uuid) persist_actor_primary_key :user_id, MyApp.Accounts.User persist_actor_primary_key :system_actor, MyApp.SystemActor, attribute_type: :string end ``` -------------------------------- ### Configure Replay Overrides Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Set up replay overrides to route events to specific legacy actions when schema versions change. This ensures proper handling of historical data. ```elixir # In Event Log Resource replay_overrides do replay_override MyApp.User, :create do versions [1] route_to MyApp.User, :old_create_v1 end end ``` -------------------------------- ### Configure AshEvents.EventLog Resource Source: https://context7.com/ash-project/ash_events/llms.txt Configure the AshEvents.EventLog resource to store events, including primary key type, actor attribution, and public field visibility. Use replay_overrides to route old event versions to legacy actions during replay. ```elixir defmodule MyApp.Events.Event do use Ash.Resource, domain: MyApp.Events, data_layer: AshPostgres.DataLayer, extensions: [AshEvents.EventLog] postgres do table "events" repo MyApp.Repo end event_log do # Required for replay; omit if using audit-only mode clear_records_for_replay MyApp.Events.ClearAllRecords # UUIDv7 is recommended for time-ordered primary keys primary_key_type Ash.Type.UUIDv7 # record_id type must match the primary key type of tracked resources record_id_type :uuid # Actor attribution: one entry per actor type persist_actor_primary_key :user_id, MyApp.Accounts.User persist_actor_primary_key :system_actor, MyApp.SystemActor, attribute_type: :string # Optional: expose fields to public interfaces (GraphQL, JSON API) # public_fields :all public_fields [:id, :resource, :action, :occurred_at, :user_id] # Optional: encrypt all event data and metadata with a Cloak vault # cloak_vault MyApp.Vault # Optional: customise the advisory lock key (default: 2_147_483_647) # advisory_lock_key_default 31337 end # Route version-1 create events to a legacy action during replay replay_overrides do replay_override MyApp.Accounts.User, :create do versions [1] route_to MyApp.Accounts.User, :create_v1 end replay_override MyApp.Accounts.User, :update do versions [1, 2] route_to MyApp.Accounts.User, :update_v2 route_to MyApp.Accounts.UserV3, :update # fan-out to multiple actions end end actions do defaults [:read] end end ``` -------------------------------- ### Mixed Replay Strategies for Different Actions Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Demonstrates a common pattern of using different replay strategies for various event actions within an Ash application. ```elixir # Mixed strategies for different actions replay_non_input_attribute_changes [ create: :force_change, # Preserve exact creation state update: :as_arguments, # Allow recomputation on updates legacy_import: :as_arguments # Recompute legacy data ] ``` -------------------------------- ### Quality Checks Commands Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Commands for code formatting, linting, type checking, and documentation generation. ```bash mix format # Format code mix credo --strict # Linting with strict rules mix dialyzer # Type checking mix docs # Generate documentation ``` -------------------------------- ### Generate Test Database Migrations Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Generates new migrations for the test database. This command is useful when making schema changes. ```bash mix test.generate_migrations ``` -------------------------------- ### Configure Event Logging and Versioning for a Resource Source: https://context7.com/ash-project/ash_events/llms.txt Define event logging behavior for a resource, including current action versions and actions to ignore during event generation. ```elixir events do event_log MyApp.Events.Event current_action_versions create: 2, update: 3 # Exclude legacy actions from generating new events ignore_actions [:create_v1] end ``` -------------------------------- ### Replay All Events Source: https://github.com/ash-project/ash_events/blob/main/README.md Replay all recorded events to rebuild resource state by running the `:replay` action on the event log resource with an empty argument map. ```elixir MyApp.Events.Event |> Ash.ActionInput.for_action(:replay, %{}) |> Ash.run_action!() ``` -------------------------------- ### Test User Event Creation and State Replay with AshEvents Source: https://context7.com/ash-project/ash_events/llms.txt Tests the creation of user events and verifies that the system can replay events to rebuild state. Ensures that actions like create and update are correctly logged and can be restored. ```elixir defmodule MyApp.UserEventTest do use MyApp.DataCase, async: false alias MyApp.Accounts.User alias MyApp.Events.Event require Ash.Query test "create action produces a correctly structured event" do user = User |> Ash.Changeset.for_create(:create, %{email: "t@example.com", name: "Test"}, authorize?: false, context: %{ash_events_metadata: %{source: "test"}} ) |> Ash.create!() [event] = Event |> Ash.Query.filter(record_id == ^user.id) |> Ash.read!(authorize?: false) assert event.resource == User assert event.action == :create assert event.action_type == :create assert event.version == 2 assert event.data["email"] == "t@example.com" assert event.metadata["source"] == "test" assert Map.has_key?(event.changed_attributes, "status") # default was captured end test "replay rebuilds state from events" do user = User |> Ash.Changeset.for_create(:create, %{email: "r@example.com", name: "Replay"}, authorize?: false) |> Ash.create!() user |> Ash.Changeset.for_update(:update, %{name: "Replayed Name"}, authorize?: false) |> Ash.update!() # Wipe state MyApp.Events.ClearAllRecords.clear_records!(authorize?: false) assert Ash.read!(User, authorize?: false) == [] # Replay :ok = Event |> Ash.ActionInput.for_action(:replay, %{}) |> Ash.run_action!(authorize?: false) restored = Ash.get!(User, user.id, authorize?: false) assert restored.name == "Replayed Name" end end ``` -------------------------------- ### Run Tests with Trace Output Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Runs all tests with detailed trace output, which can be helpful for debugging. ```bash mix test --trace ``` -------------------------------- ### Debug Replay Issues in IEx Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/quick-reference.md Workflow for debugging replay issues. Involves running the test suite, manually testing record clearing, checking event ordering, and performing step-by-step replay in IEx. ```bash # 1. Run full test suite first mix test.reset && mix test # 2. Test clear records manually iex -S mix > MyApp.Events.ClearAllRecords.clear_records!([]) # 3. Check event ordering manually iex -S mix > MyApp.Events.EventLog |> Ash.Query.sort(:inserted_at) |> Ash.read!() # 4. Test step-by-step replay manually in IEx # Clear -> Create one event -> Replay -> Verify state ``` -------------------------------- ### Resource-Specific Event Configurations Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Different resources can have distinct event configurations, including specifying the event log and versioning for actions. ```elixir # Different resources can have different event configurations defmodule MyApp.Accounts.User do events do event_log MyApp.Events.Event current_action_versions create: 2, update: 1 end end ``` ```elixir defmodule MyApp.Blog.Post do events do event_log MyApp.Events.Event current_action_versions create: 1, update: 3, destroy: 1 end end ``` -------------------------------- ### Reset Test Database Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Drops, creates, and migrates the test database. Always use `mix test.reset` instead of `mix ecto.reset` for test database management. ```bash mix test.reset ``` -------------------------------- ### Debug Build/Compilation Issues Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/quick-reference.md Workflow for debugging build and compilation issues. Involves cleaning the build directory, forcing a recompile with error details, checking dependency consistency, and running the test suite after fixes. ```bash # 1. Clean compile with error details rm -rf _build/ && mix compile --force --warnings-as-errors # 2. Check dependency consistency mix deps.get && mix deps.compile --force # 3. Run full test suite after fixing compilation mix test ``` -------------------------------- ### Replay Events Using the `replay` Action Source: https://context7.com/ash-project/ash_events/llms.txt The `replay` action on the event log resource allows for replaying events to rebuild state. It can replay all events, up to a specific event ID, or up to a specific point in time. Lifecycle hooks are suppressed during replay. ```elixir alias MyApp.Events.Event # Replay all events (full rebuild) :ok = Event |> Ash.ActionInput.for_action(:replay, %{}) |> Ash.run_action!() # Replay up to a specific event ID (point-in-time by sequence) :ok = Event |> Ash.ActionInput.for_action(:replay, %{last_event_id: 5000}) |> Ash.run_action!() # Replay up to a specific wall-clock timestamp :ok = Event |> Ash.ActionInput.for_action(:replay, %{ point_in_time: ~U[2024-03-01 00:00:00Z] }) |> Ash.run_action!() ``` -------------------------------- ### Implement Legacy Actions for Event Replay Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Create legacy action implementations for handling old event versions during replay. Mark these legacy actions with `ignore_actions` to prevent them from creating new events. ```elixir defmodule MyApp.Accounts.User do actions do create :create do # Current implementation end end actions do create :old_create_v1 do # Implementation for version 1 events end end events do event_log MyApp.Events.Event ignore_actions [:old_create_v1] # Don't create new events for legacy actions end end ``` -------------------------------- ### Debugging Pattern Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md A common debugging pattern involves resetting the database, running the full test suite, and then manually inspecting issues in IEx. ```bash # 1. Reset database and run full test suite mix test.reset && mix test # 2. Check individual issues manually in IEx iex -S mix ``` -------------------------------- ### Configure Multiple Actor Types for Event Logging Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Configure multiple actor types when different entities perform actions. Specify the primary key and resource for each actor type. ```elixir event_log do persist_actor_primary_key :user_id, MyApp.Accounts.User persist_actor_primary_key :system_actor, MyApp.SystemActor, attribute_type: :string persist_actor_primary_key :api_client_id, MyApp.APIClient end ``` -------------------------------- ### Essential README Structure Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/readme-update-guide.md This markdown structure provides a comprehensive template for a project's README file, covering key sections for end-users. ```markdown # Project Title Brief, compelling description (1-2 sentences) ## Why [Project Name]? Value proposition and key benefits ## Features Core capabilities and benefits ## Quick Start Minimal working example (copy-paste ready) ## Installation Quick installation instructions ## Usage Comprehensive examples and patterns ## Configuration Configuration options and customization ## Advanced Features Complex usage patterns and edge cases ## [Project-Specific Section] (if applicable) Domain-specific content (e.g., "Event Log Structure" for event systems) ## How It Works High-level explanation of the approach ## Best Practices End-user best practices for production use ## Troubleshooting Common user issues and solutions ## Documentation Links to comprehensive documentation ## Community Contributing guidelines and support channels ## Reference API documentation links ``` -------------------------------- ### Configure Encrypted Event Log Source: https://context7.com/ash-project/ash_events/llms.txt Set up an event log resource with encryption using a Cloak vault. This automatically includes all sensitive attributes from the tracked resource. ```elixir defmodule MyApp.Events.SecureEvent do use Ash.Resource, extensions: [AshEvents.EventLog] event_log do cloak_vault MyApp.Vault # any Cloak vault module clear_records_for_replay MyApp.Events.ClearAllRecords persist_actor_primary_key :user_id, MyApp.Accounts.User end end defmodule MyApp.Accounts.User do events do event_log MyApp.Events.SecureEvent # Do NOT add store_sensitive_attributes here — all sensitive attrs # are automatically included because the event log is encrypted. end attributes do attribute :email, :string, public?: true attribute :hashed_password, :string, sensitive?: true # auto-included in events end end ``` -------------------------------- ### Configure Events with Only Actions and Replay Options Source: https://github.com/ash-project/ash_events/blob/main/documentation/dsls/DSL-AshEvents.Events.md This configuration specifies the event log module and restricts event creation to only the listed actions. It also configures how non-input attribute changes are replayed for specific action versions. ```elixir events do event_log MyApp.Events.EventLog only_actions [:create, :update, :destroy] current_action_versions create: 2, update: 3, destroy: 2 replay_non_input_attribute_changes [create_v1: :as_arguments, update_v2: :force_change] end ``` -------------------------------- ### View Specific GitHub Issue Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Use the GitHub CLI to view the details of a specific issue by its number. This helps in understanding the problem. ```bash gh issue view ``` -------------------------------- ### Configure Advisory Locks for High Concurrency Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Set a default advisory lock key or provide a custom key generator for scenarios requiring high concurrency. ```elixir event_log do advisory_lock_key_default 31337 advisory_lock_key_generator MyApp.CustomAdvisoryLockKeyGenerator end ``` -------------------------------- ### Set Actor at Call Site for Event Logging Source: https://context7.com/ash-project/ash_events/llms.txt Demonstrates how to specify the actor performing an action when creating a changeset, which will then be persisted in the event log. ```elixir User |> Ash.Changeset.for_create(:create, %{email: "user@example.com", name: "Test"}, [ actor: %MyApp.SystemActor{name: "import_job"} ]) |> Ash.create!() ``` -------------------------------- ### Submit Issue Context to Claude Session Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Send the issue details, including number, summary, root cause, relevant files, and reproduction steps, to the Claude session. Ensure Claude is ready before sending. ```bash cmux send --workspace workspace: --surface surface: "" cmux send-key --workspace workspace: --surface surface: Enter ``` -------------------------------- ### Community Section Template Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/readme-update-guide.md A template for structuring the community section of the README, including contributing guidelines, help resources, and code of conduct. ```markdown ## Community ### Contributing We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details. ### Getting Help - 📚 **Documentation**: Check the [documentation](#documentation) first - 💬 **Community**: Join the [Ash Community](https://elixirforum.com/c/ash-framework/123) for real-time help - 🐛 **Issues**: Report bugs on [GitHub Issues](https://github.com/ash-project/ash_events/issues) - 💡 **Discussions**: Share ideas on [GitHub Discussions](https://github.com/ash-project/ash_events/discussions) ### Code of Conduct This project follows the [Ash Community Code of Conduct](https://github.com/ash-project/ash/blob/main/CODE_OF_CONDUCT.md). ``` -------------------------------- ### Configure Event Tracking for Specific Actions Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Use `only_actions` or `ignore_actions` to control which actions trigger event creation, allowing for fine-grained audit logging. ```elixir events do event_log MyApp.Events.Event # Only track specific actions only_actions [:create, :update, :destroy] # Or ignore specific actions ignore_actions [:internal_update, :system_sync] end ``` -------------------------------- ### Configure Replay Overrides for Event Versions Source: https://github.com/ash-project/ash_events/blob/main/README.md Set up replay overrides to route specific versions of events to different actions. This is useful for handling changes in event structure or logic over time. ```elixir replay_overrides do replay_override MyApp.Accounts.User, :create do versions [1] route_to MyApp.Accounts.User, :old_create_v1 end replay_override MyApp.Accounts.User, :update do versions [1, 2] route_to MyApp.Accounts.User, :update_legacy end end ``` -------------------------------- ### Route Events to Different Resources Based on Version Source: https://github.com/ash-project/ash_events/blob/main/README.md Configure replay overrides to route events to different resources based on their version. This allows for substantial changes in application structure while maintaining event replay compatibility. ```elixir replay_overrides do replay_override MyApp.Accounts.User, :update do versions [1, 2] route_to MyApp.Accounts.UserV2, :update_v2 end end ``` -------------------------------- ### Configure Multiple Actor Types Source: https://github.com/ash-project/ash_events/blob/main/README.md Track different types of actors by specifying their primary key and module. When using multiple actor types, all must have `allow_nil?: true`. ```elixir event_log do persist_actor_primary_key :user_id, MyApp.Accounts.User persist_actor_primary_key :system_actor, MyApp.SystemActor, attribute_type: :string end ``` -------------------------------- ### replay_overrides.replay_override.route_to Source: https://github.com/ash-project/ash_events/blob/main/documentation/dsls/DSL-AshEvents.EventLog.md Routes a matched event to a different resource and action. ```APIDOC ## replay_overrides.replay_override.route_to ### Description Routes the event to a different action. ### Arguments #### Path Parameters - **resource** (atom) - Required - - **action** (atom) - Required - ``` -------------------------------- ### Add Event Tracking Extension to Resource Source: https://github.com/ash-project/ash_events/blob/main/CLAUDE.md Integrates event tracking into an Ash resource using the `AshEvents.Events` extension. Configure event log, action versions, and replay strategies for changed attributes. ```elixir defmodule MyApp.User do use Ash.Resource, extensions: [AshEvents.Events] events do event_log MyApp.Events.Event current_action_versions create: 1, update: 1 # Configure changed attributes replay strategies replay_non_input_attribute_changes [ create: :force_change, # Default: preserve exact state update: :as_arguments # Alternative: :as_arguments ] end end ``` -------------------------------- ### Test Event Creation with Authorization Disabled Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md In tests, use `authorize?: false` when authorization is not the primary focus to simplify assertions and focus on event creation. ```elixir test "creates user with event" do user = User |> Ash.Changeset.for_create(:create, %{name: "Test"}) |> Ash.create!(authorize?: false) # Verify event was created events = MyApp.Events.Event |> Ash.read!(authorize?: false) assert length(events) == 1 end ``` -------------------------------- ### Define an Event Log Resource Source: https://github.com/ash-project/ash_events/blob/main/README.md Define a resource to store events, configuring it with the `AshEvents.EventLog` extension. Specify callbacks for clearing records, primary key types, actor primary keys, and public field visibility. ```elixir defmodule MyApp.Events.Event do use Ash.Resource, extensions: [AshEvents.EventLog] event_log do # Module that implements clear_records! callback clear_records_for_replay MyApp.Events.ClearAllRecords # Optional. Defaults to :integer, Ash.Type.UUIDv7 is the recommended option # if your event log is set up with multitenancy via the attribute-strategy. primary_key_type Ash.Type.UUIDv7 # Optional, defaults to :uuid record_id_type :uuid # Store primary key of actors running the actions persist_actor_primary_key :user_id, MyApp.Accounts.User persist_actor_primary_key :system_actor, MyApp.SystemActor, attribute_type: :string # Optional: Control field visibility for public interfaces public_fields :all # or [:id, :resource, :action, :occurred_at], or [] (default) end # Optional: Configure replay overrides for version handling replay_overrides do replay_override MyApp.Accounts.User, :create do versions [1] route_to MyApp.Accounts.User, :old_create_v1 end end ..... end ``` -------------------------------- ### Test Event Replay Functionality Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Verify that event replay correctly rebuilds the application state by creating data, clearing records, replaying events, and asserting the restored state. ```elixir test "can replay events to rebuild state" do # Create some data user = create_user() update_user(user) # Clear state clear_all_records() # Replay events MyApp.Events.Event |> Ash.ActionInput.for_action(:replay, %{}) |> Ash.run_action!(authorize?: false) # Verify state is restored restored_user = get_user(user.id) assert restored_user.name == user.name end ``` -------------------------------- ### Add Event Tracking to a Resource Source: https://github.com/ash-project/ash_events/blob/main/agent-docs/readme-update-guide.md Enable event tracking for an Ash resource by using the `AshEvents.Events` extension and specifying the event log resource. Configure `current_action_versions` for specific actions. ```elixir defmodule MyApp.User do use Ash.Resource, extensions: [AshEvents.Events] events do event_log MyApp.Events.Event current_action_versions create: 1, update: 1 end end ``` -------------------------------- ### Track Metadata with Actions Source: https://github.com/ash-project/ash_events/blob/main/README.md Include custom metadata with actions by adding `ash_events_metadata` to the changeset context. This allows for tracking details like the source of the request or a request ID. ```elixir User |> Ash.Changeset.for_create(:create, %{ name: "Jane Doe", email: "jane@example.com" }, [ actor: current_user, context: %{ash_events_metadata: %{ source: "api", request_id: request_id }} ]) |> Ash.create(opts) ``` -------------------------------- ### Cloaked Event Log Configuration with Encryption Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md Configure a cloaked event log by specifying a `cloak_vault` to enable encryption for all event data. ```elixir defmodule MyApp.Events.CloakedEvent do use Ash.Resource, extensions: [AshEvents.EventLog] event_log do cloak_vault MyApp.Vault # Enables encryption for all event data end end ``` -------------------------------- ### Implement Idempotent Side Effects with AshEvents Actions Source: https://context7.com/ash-project/ash_events/llms.txt Demonstrates how to encapsulate side effects within separate Ash actions to ensure idempotency, especially when dealing with events that should not be re-sent during replay. This pattern is useful for tasks like sending welcome emails. ```elixir defmodule MyApp.Notifications.WelcomeEmail do use Ash.Resource, extensions: [AshEvents.Events] events do event_log MyApp.Events.Event end attributes do uuid_primary_key :id attribute :recipient_email, :string attribute :status, :string, default: "pending" attribute :sent_at, :utc_datetime end actions do create :send do accept [:recipient_email] change after_action(fn _cs, record, _ctx -> case MyApp.Mailer.deliver_welcome(record.recipient_email) do :ok -> # Creates a separate tracked event — not re-sent during replay {:ok, Ash.update!(record, %{status: "sent", sent_at: DateTime.utc_now()}, authorize?: false)} {:error, _} -> {:ok, Ash.update!(record, %{status: "failed"}, authorize?: false)} end end) end update :mark_sent do accept [:status, :sent_at] end end end # Called from a User create after_action hook: change after_action(fn _cs, user, ctx -> MyApp.Notifications.WelcomeEmail |> Ash.Changeset.for_create(:send, %{recipient_email: user.email}, actor: ctx.actor) |> Ash.create!() {:ok, user} end) ``` -------------------------------- ### Configure Timestamp Tracking for Custom Fields Source: https://github.com/ash-project/ash_events/blob/main/usage-rules.md If your resources use custom timestamp fields for creation or updates, configure AshEvents to track them using `create_timestamp` and `update_timestamp`. ```elixir events do event_log MyApp.Events.Event create_timestamp :inserted_at update_timestamp :updated_at end ``` -------------------------------- ### Define Replay Overrides for Versioned Event Routing Source: https://context7.com/ash-project/ash_events/llms.txt Configure version-based routing for events during replay. This is useful for schema evolution, directing older event versions to legacy actions. ```elixir replay_overrides do # Version-1 user creation events go to the legacy create_v1 action replay_override MyApp.Accounts.User, :create do versions [1] route_to MyApp.Accounts.User, :create_v1 end # Version-1 and version-2 updates fan out to two downstream resources replay_override MyApp.Accounts.User, :update do versions [1, 2] route_to MyApp.Accounts.UserProfile, :update_from_legacy route_to MyApp.Audit.UserChange, :record end end ```