---
title: "Installation — Tickets for Laravel | Roundly"
description: "Install via Composer, run tickets:install and migrate, settle key types, make your user an assignee, define the abilities and schedule the sweeps."
url: https://roundly-consulting.com/open-source/docs/tickets-for-laravel/installation
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Tickets for Laravel](https://roundly-consulting.com/open-source/docs/tickets-for-laravel.md)

# Installation

Require the package, run its installer, then migrate. The service provider and the global Tickets facade alias are auto-discovered, together with the providers of the Roundly packages it builds on:

```bash
composer require roundly-consulting/tickets-for-laravel
php artisan tickets:install
php artisan migrate
```

tickets:install publishes tickets-config, then the migrations of every package tickets builds on (media-, likes-, reports-, approvals-, comments-, lifecycle- and attributes-migrations) and finally tickets-migrations. Each package’s migrations keep their own order and none references another package’s tables. Running it again is safe: a published file is kept unless you pass --force, and a republished migration lands on the file it landed on before. It then prints the key types of the installation and the next steps.

## 1\. Settle the key types before migrating

The migrations read the key types to pick their column types. With bigint user ids the defaults fit. With UUID or ULID keys, set them before php artisan migrate:

```bash
TICKETS_PRIMARY_KEY_TYPE=uuid   # tickets and guests (= lifecycle, attributes, comments key types)
TICKETS_KEY_TYPE=uuid           # requester, assignee, project, watcher, actor morphs (= your users)
LIFECYCLE_KEY_TYPE=uuid
LIFECYCLE_ACTOR_KEY_TYPE=uuid
COMMENTS_KEY_TYPE=uuid
ATTRIBUTES_KEY_TYPE=uuid
```

comments.key\_type keys both the comment author (a user) and the commentable (a ticket), so the whole installation runs on one key type — mixed key types are not supported, and tickets:doctor reports every mismatch (see Models, keys and references).

## 2\. Make your user model an assignee

Agents take tickets, and only a model that implements Contracts\\Assignee can hold one: claim(), assign() and an assignee given at creation throw InvalidAssigneeException for anything else (a category’s default assignee that isn’t one is skipped). Add the contract and its default implementation:

```php
use RoundlyConsulting\Tickets\Concerns\IsTicketAssignee;
use RoundlyConsulting\Tickets\Contracts\Assignee;

class User extends Authenticatable implements Assignee
{
    use IsTicketAssignee;
}
```

IsTicketAssignee names the assignee by its name attribute, notifies the user itself and makes a user eligible for a ticket when it is an agent for it (the agent ability, narrowed by the agent scope). Override any of its three methods — ticketAssigneeName(), ticketNotifiables(), isEligibleTicketAssignee() — to change that.

## 3\. Define the abilities

The package asks the Gate but defines no ability itself, and an undefined ability denies:

```php
// AppServiceProvider::boot()
use Illuminate\Support\Facades\Gate;

Gate::define('tickets.agent', fn ($user) => $user->is_support);      // who is an agent (also merge by default)
Gate::define('tickets.assign', fn ($user) => $user->is_team_lead);   // assign tickets to others
Gate::define('tickets.manage', fn ($user) => $user->is_admin);       // delete/restore tickets, run categories, fields, tags
```

is\_support, is\_team\_lead and is\_admin stand for your own flags — a column or a role check; a stock users table has none of them. A permissions package that grants abilities through Gate::before (permissions-for-laravel does) works too, and the ability names are configurable under tickets.authorization.abilities.\*.

## 4\. Schedule the sweeps

```php
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('tickets:sweep')->everyFiveMinutes();  // overdue and due-soon flags
Schedule::command('lifecycle:sweep')->everyMinute();     // closes resolved tickets after 7 days
```

Nothing is registered on the scheduler for you. Without tickets:sweep no ticket is ever flagged overdue; without lifecycle:sweep resolved tickets never close by themselves.

## 5\. Check the installation

```bash
php artisan tickets:doctor
```

A fresh install exits 1 until it is configured: guest notifications are on by default, and the default guest-link generator needs the guest routes, which ship off. Settle it one of three ways — serve the API with guest access, bind your own Contracts\\GuestLinkGenerator (a separate frontend, see Guests and guest links), or stop guest mail:

```bash
# Serve the API with guest access (guests are on by default)
TICKETS_ROUTES=on

# …or stop guest mail
TICKETS_NOTIFY_GUESTS=off
```

## Optional steps

| Want | Do |
| --- | --- |
| The JSON API | TICKETS\_ROUTES=on; with Sanctum, publish the config and use auth:sanctum in tickets.routes.middleware (see JSON API). |
| To change a route | php artisan vendor:publish --tag=tickets-routes — the published routes/tickets.php replaces the package’s for good. |
| To change a string | php artisan vendor:publish --tag=tickets-translations (en and sk ship). |
| Validation messages in another language | Tickets names the inputs itself (tickets::validation.attributes, guest\_fields; en and sk ship); Laravel’s message sentences come from your lang/<locale>/validation.php — Laravel ships English only, so add e.g. lang/sk/validation.php (php artisan lang:publish gives you the English one to translate). |
| Mentions to notify | Set comments.mention\_resolver (comments-for-laravel). |
| Database notifications | Your app’s notifications table, and database in tickets.notifications.channels. |
| Team assignees | A team model implementing Contracts\\Assignee (teams-for-laravel works). |

## Publish tags

| Tag | Publishes |
| --- | --- |
| `tickets-config` | `config/tickets.php` |
| `tickets-migrations` | ten migrations, timestamped on publish |
| `tickets-translations` | `lang/vendor/tickets/{en,sk}/{enums,messages,notifications,validation}.php` |
| `tickets-routes` | `routes/tickets.php` |

```bash
php artisan vendor:publish --tag=tickets-config
php artisan vendor:publish --tag=tickets-migrations
php artisan vendor:publish --tag=tickets-translations
php artisan vendor:publish --tag=tickets-routes
```

The migrations are publish-only: the provider loads none of them, so php artisan migrate runs exactly the files you published. A published routes/tickets.php replaces the package’s routes for good, which is why the installer never publishes it.

## Translations

Every user-facing string goes through the tickets:: namespace, in English (en) and Slovak (sk) with identical keys: enums.php (one label map per enum), messages.php (exception and command text), notifications.php (the mails) and validation.php (the display name of every API input, plus guest\_fields). Publish them with --tag=tickets-translations to change a line, or add lang/vendor/tickets/<locale>/… for another language — a missing key falls back to Laravel’s fallback locale. Exception messages, the doctor, the installer, enum labels and the mails all follow the current locale (a notifiable’s preferredLocale() for mail).

## php artisan about

The Tickets section shows the primary key type, key type, lifecycle class, priority enum, reference prefix, activity on/off, routes on/off, guest access on/off, the auto-close duration and notifications with their channels. A broken setting renders INVALID instead of failing the command, and no guest data or secret is ever shown.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/tickets-for-laravel.md)
