PhoenixKitLocations
Locations module for PhoenixKit — manage physical locations with custom types, multilingual fields, and a full admin interface.
Features
- Location management — addresses, contact info, admin notes, active/inactive status
- Custom location types — user-defined categories (e.g. Showroom, Storage, Office) with many-to-many assignments
- Translatable fields — name, description, and public notes via PhoenixKit's Multilang system
- Feature flags — track amenities like wheelchair access, parking, wifi, and more
- Duplicate detection — warns when entering addresses that match existing locations
- Admin dashboard — LiveView pages for managing locations and types, auto-discovered by PhoenixKit
Installation
Add phoenix_kit_locations to your list of dependencies in mix.exs:
def deps do
[
{:phoenix_kit_locations, "~> 0.1"}
]
endThe module is auto-discovered by PhoenixKit — no manual router configuration needed. Run the PhoenixKit migrations to create the required database tables.
Usage
Admin Interface
Once installed, the admin dashboard adds a Locations tab with two subtabs:
- Locations — list, create, and edit locations
- Types — manage location types that can be assigned to locations
Routes are registered automatically:
| Path | Description |
|---|---|
/admin/locations | Locations list |
/admin/locations/new | Create location |
/admin/locations/:uuid/edit | Edit location |
/admin/locations/types | Types list |
/admin/locations/types/new | Create type |
/admin/locations/types/:uuid/edit | Edit type |
Programmatic Access
All business logic lives in the PhoenixKitLocations.Locations context:
alias PhoenixKitLocations.Locations
# Locations
Locations.list_locations()
Locations.create_location(%{name: "HQ", city: "Berlin", country: "DE"})
Locations.list_locations(status: "active", type_uuid: some_uuid)
# Location types
Locations.list_location_types()
Locations.create_location_type(%{name: "Office"})
# Type assignments (take location_uuid, not the struct)
Locations.sync_location_types(location.uuid, [type_uuid_1, type_uuid_2])
Locations.has_type?(location.uuid, type_uuid)Error Handling
Non-changeset errors returned by PhoenixKitLocations.Locations are atoms (:location_not_found, :type_assignment_failed, …). At the UI boundary, LiveViews translate them via PhoenixKitLocations.Errors.message/1, which wraps each mapping in gettext so flashes render in the user's locale.
case Locations.delete_location(loc, actor_uuid: user.uuid) do
{:ok, _} -> :ok
{:error, _changeset} -> {:error, PhoenixKitLocations.Errors.message(:location_delete_failed)}
endActivity Logging
Every mutating context function logs a business-level activity to PhoenixKit.Activity when an actor_uuid: opt is passed. Logging is fire-and-forget — failures (e.g. host hasn't run core's V90 migration) never crash the primary operation. The action format is "resource.verb": location.created, location.updated, location.deleted, location.types_synced, location_type.created, etc.
Location Features
Locations support a set of boolean feature flags stored as a JSONB map:
wheelchair_accessible, elevator, parking, public_transport, loading_dock, air_conditioning, wifi, restrooms, security, cctv
Locations.create_location(%{
name: "Warehouse",
features: %{"loading_dock" => true, "parking" => true, "cctv" => true}
})Database Schemas
All schemas use UUIDv7 primary keys. Tables are created by PhoenixKit migrations.
| Table | Description |
|---|---|
phoenix_kit_locations | Locations with address, contact, features, and multilang data |
phoenix_kit_location_types | User-defined location categories |
phoenix_kit_location_type_assignments | Many-to-many join table |
Development
mix deps.get # Install dependencies
mix test # Run tests
mix precommit # compile + format + credo + dialyzer
mix quality # format + credo + dialyzer
mix quality.ci # format --check-formatted + credo + dialyzerLicense
MIT — see LICENSE for details.