Skip to content

feat(plugins): fire domain hooks from ticket + assignment services#97

Merged
mpge merged 1 commit into
masterfrom
feat/plugins-domain-hooks
Jul 1, 2026
Merged

feat(plugins): fire domain hooks from ticket + assignment services#97
mpge merged 1 commit into
masterfrom
feat/plugins-domain-hooks

Conversation

@mpge

@mpge mpge commented Jul 1, 2026

Copy link
Copy Markdown
Member

Follow-up to #96. That PR landed the plugin hook dispatch mechanism and the activation lifecycle hooks; this one wires the dispatch into the core ticket write paths so registered plugins actually fire end-to-end during real ticket operations.

Actions dispatched

From Escalated.Services.TicketService:

  • ticket_created — on create
  • ticket_replied / internal_note_added — on reply (by is_internal)
  • ticket_status_changed, plus ticket_resolved / ticket_closed / ticket_reopened — on status transition
  • ticket_priority_changed — on priority change

From Escalated.Services.AssignmentService:

  • ticket_assigned / ticket_unassigned

Filters applied

In TicketService.list/1:

  • ticket_list_query — the Ecto query before execution
  • ticket_list_data — the loaded ticket list

Hook names mirror the Laravel HookRegistry (unprefixed here, since the Escalated.Plugins namespace already scopes them). Dispatch runs after each write commits and is failure-isolated — a raising plugin is logged and skipped, never breaking a ticket operation.

Notes

  • Adds an integration test (ticket_service_hooks_test.exs) that activates a capturing plugin and asserts the real service calls fire ticket_created, ticket_status_changed + ticket_resolved, ticket_replied / internal_note_added, and that a ticket_list_data filter transforms list/1 output.
  • Reflows a few pre-existing over-length lines that mix format rewraps now the files are touched, and alphabetizes one alias group (both surfaced by CI's PR-scoped format/credo checks).
  • The Escalated.Plugins.Hooks moduledoc now lists the hooks the core services dispatch.

Verification

Ran the exact CI toolchain (Elixir 1.15 / OTP 26) in a container: mix format --check-formatted clean, mix credo --strict no issues, mix test 548 tests, 0 failures.

Wires the plugin hook dispatch into the core write paths so registered
plugins are actually exercised end-to-end (the prior PR landed the
mechanism + lifecycle hooks only).

Actions dispatched:
  * ticket_created (TicketService.create)
  * ticket_replied / internal_note_added (TicketService.reply)
  * ticket_status_changed + ticket_resolved/closed/reopened
    (TicketService.transition_status)
  * ticket_priority_changed (TicketService.change_priority)
  * ticket_assigned / ticket_unassigned (AssignmentService)

Filters applied in TicketService.list: ticket_list_query (the Ecto query
before execution) and ticket_list_data (the loaded list). Hook names
mirror the Laravel HookRegistry (unprefixed, since the Escalated.Plugins
namespace already scopes them).

Also reflows a few pre-existing over-length lines that mix format
rewraps now the files are touched, and reorders one alias group.

Verified in the CI toolchain (Elixir 1.15/OTP 26): mix format, credo
--strict, mix test (548 tests, 0 failures).
@mpge mpge merged commit 4e9c301 into master Jul 1, 2026
2 checks passed
@mpge mpge deleted the feat/plugins-domain-hooks branch July 1, 2026 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant