PhoenixKitCustomerSupport
Customer support ticketing module for PhoenixKit.
Provides a full ticketing system: create tickets, track status, add comments and attachments, manage agents. Extracted from PhoenixKit core (>= 1.7.104).
Features
- Ticket lifecycle —
open → in_progress → resolved → closedwith full status-history audit trail - Comments — public comments visible to ticket owners, plus agent-only internal notes
- Attachments — file uploads on tickets and comments via
PhoenixKit.Modules.Storage - Assignment — assign tickets to support staff; assignment changes are recorded
- Reopen flow — closed tickets can be reopened by users or agents (configurable)
- Admin and user LiveViews — admin pages under
/admin/customer-support, user-facing pages under/dashboard/customer-support/tickets - PubSub events — per-user, per-ticket, and global topics for real-time updates
- Auto-discovery — implements
PhoenixKit.Module; PhoenixKit finds it at startup with zero config
Installation
Add to the host app's mix.exs:
{:phoenix_kit_customer_support, "~> 0.3"}
Then mix deps.get. The module appears in the admin Modules page and sidebar automatically via PhoenixKit.Module auto-discovery.
Requires PhoenixKit core ~> 2.4. Ticket.changeset/2 calls PhoenixKit.Utils.Slug.put_slug/3, which core added in 2.4.0 (along with V168, which makes ticket slugs unique). Core 2.0.0 squashed the migration chain to a V135 floor and refuses to migrate a database below it — check mix phoenix_kit.status before upgrading, and see core’s 2.0.0 / 2.4.0 CHANGELOGs.
This module owns and versions the future shape of its 4 tables (phoenix_kit_tickets, phoenix_kit_ticket_comments, phoenix_kit_ticket_attachments, phoenix_kit_ticket_status_history) through its own migration chain, PhoenixKitCustomerSupport.Migrations. Core's V135/V168 still CREATE these 4 tables on every install — this chain's V1 adopts that shape and stamps a version marker. It makes exactly one real change: phoenix_kit_ticket_status_history.changed_by_uuid is made NULLABLE (ALTER COLUMN … DROP NOT NULL), because core's baseline declares it NOT NULL while its own FK is ON DELETE SET NULL — a contradiction core's V164 documents but never resolves. Hosts installed from the squashed V135 baseline (core ≥ 2.0.0) carry the NOT NULL and are relaxed by V1; older hosts that reached the current chain historically already have it nullable, so V1 is a no-op there. V1 also replaces any legacy descriptive COMMENT on phoenix_kit_tickets with the version marker. The ~> 2.4 floor above exists because V1 must already include V168 (the unique slug index) for the adopted shape to match.
Module integration
The package registers itself with PhoenixKit's module system. No manual router wiring needed — admin routes are auto-discovered at compile time via route_module/0.
Routes
Admin routes (registered by this package via route_module/0)
| Path | LiveView |
|---|---|
/admin/customer-support |
PhoenixKitCustomerSupport.Web.List |
/admin/customer-support/tickets |
PhoenixKitCustomerSupport.Web.List |
/admin/customer-support/tickets/new |
PhoenixKitCustomerSupport.Web.New |
/admin/customer-support/tickets/:uuid |
PhoenixKitCustomerSupport.Web.Details |
/admin/customer-support/tickets/:uuid/edit |
PhoenixKitCustomerSupport.Web.Edit |
/admin/settings/customer-support |
PhoenixKitCustomerSupport.Web.Settings |
User dashboard routes (wired by PhoenixKit core via Code.ensure_loaded? guards)
| Path | LiveView |
|---|---|
/dashboard/customer-support/tickets |
PhoenixKitCustomerSupport.Web.UserList |
/dashboard/customer-support/tickets/new |
PhoenixKitCustomerSupport.Web.UserNew |
/dashboard/customer-support/tickets/:id |
PhoenixKitCustomerSupport.Web.UserDetails |
User-facing routes are registered by PhoenixKitWeb.Integration in the core library when this package is present — no additional router configuration is required in the host app.
Settings
The following settings keys control this module's behaviour. They are managed via the admin Settings UI (/admin/settings/customer-support) or directly via PhoenixKit.Settings.
| Key | Default | Description |
|---|---|---|
customer_support_enabled |
false |
Enables or disables the customer support module globally. |
customer_support_per_page |
20 |
Number of tickets shown per page in admin and user list views. |
customer_support_comments_enabled |
true |
Allows users and agents to post comments on tickets. |
customer_support_internal_notes_enabled |
true |
Enables internal (agent-only) notes on tickets. |
customer_support_attachments_enabled |
true |
Allows file attachments to be added to tickets and comments. |
customer_support_allow_reopen |
true |
Permits closed tickets to be reopened by users or agents. |
Removing this module
There is deliberately no automated uninstall. PhoenixKitCustomerSupport.Migrations.down/1
never drops any of the 4 phoenix_kit_ticket* tables or a row in them, for
any target version — a host that merely removes this dependency from
mix.exs has not consented to deleting every customer's tickets, comments
(public and internal notes), attachments and status-change audit trail, and
a migration whose result depended on which packages happen to be compiled
in would be nondeterministic. Removing the data is therefore a deliberate,
manual operator step — remove :phoenix_kit_customer_support from mix.exs
first, then run, in FK-safe order (children before parents, substituting
your PhoenixKit schema prefix for public):
-- Only if you actually want every ticket and everything attached to it
-- gone for good.
DROP TABLE public.phoenix_kit_ticket_attachments;
DROP TABLE public.phoenix_kit_ticket_comments;
DROP TABLE public.phoenix_kit_ticket_status_history;
DROP TABLE public.phoenix_kit_tickets;
Dropping phoenix_kit_tickets last also removes the pkcs_schema:<N> version
marker, which is a COMMENT on that table — no separate step is needed.
While core's baseline still creates these tables (it does today), core's
ExpectedSchema manifest lists all 4 as required: mix phoenix_kit.doctor
then reports them missing, and mix phoenix_kit.repair recreates them —
empty. The rows are gone either way; only the empty tables come back.
To keep the rows (e.g. you plan to reinstall the module later), simply leave
the tables alone. The marker is inert once the module is gone, and on
reinstall it correctly reads as already adopted. Clearing it achieves
nothing: while the module is installed, the next mix phoenix_kit.update
re-stamps it.
Development
mix deps.get
mix compile
mix test