PHPackages                             opscale-co/nova-service-desk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. opscale-co/nova-service-desk

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

opscale-co/nova-service-desk
============================

Manage tasks

1.2.0(2w ago)0191[2 issues](https://github.com/opscale-co/nova-service-desk/issues)MITPHPPHP ^8.2CI passing

Since Jan 28Pushed 2w agoCompare

[ Source](https://github.com/opscale-co/nova-service-desk)[ Packagist](https://packagist.org/packages/opscale-co/nova-service-desk)[ Docs](https://github.com/opscale-co/nova-service-desk)[ RSS](/packages/opscale-co-nova-service-desk/feed)WikiDiscussions main Synced today

READMEChangelog (10)Dependencies (49)Versions (13)Used By (0)

Support us
----------

[](#support-us)

At Opscale, we're passionate about contributing to the open-source community by providing solutions that help businesses scale efficiently. If you've found our tools helpful, here are a few ways you can show your support:

⭐ **Star this repository** to help others discover our work and be part of our growing community. Every star makes a difference!

💬 **Share your experience** by leaving a review on [Trustpilot](https://www.trustpilot.com/review/opscale.co) or sharing your thoughts on social media. Your feedback helps us improve and grow!

📧 **Send us feedback** on what we can improve at . We value your input to make our tools even better for everyone.

🙏 **Get involved** by actively contributing to our open-source repositories. Your participation benefits the entire community and helps push the boundaries of what's possible.

💼 **Hire us** if you need custom dashboards, admin panels, internal tools or MVPs tailored to your business. With our expertise, we can help you systematize operations or enhance your existing product. Contact us at  to discuss your project needs.

Thanks for helping Opscale continue to scale! 🚀

Description
-----------

[](#description)

Resolve customer requests on time, every time. Service Desk for Laravel Nova gives you a complete ticketing pipeline — intake forms, SLA-driven prioritization, custom workflows with stage guards and a drag-and-drop Kanban board — so your team stays focused on the right work and nothing falls through the cracks.

[![Demo](https://raw.githubusercontent.com/opscale-co/nova-service-desk/refs/heads/main/screenshots/nova-service-desk.gif)](https://raw.githubusercontent.com/opscale-co/nova-service-desk/refs/heads/main/screenshots/nova-service-desk.gif)

Installation
------------

[](#installation)

[![Latest Version on Packagist](https://camo.githubusercontent.com/b0bbea140ad6f4216aeed42f219767f9c358c591c048611f19a40f3f300185c2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6f707363616c652d636f2f6e6f76612d736572766963652d6465736b2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/opscale-co/nova-service-desk)

Install the package in a Laravel app that uses [Nova](https://nova.laravel.com):

```
composer require opscale-co/nova-service-desk
```

Publish and run the migrations:

```
php artisan vendor:publish --tag="nova-service-desk-migrations"
php artisan migrate
```

Optionally publish the configuration file:

```
php artisan vendor:publish --tag="nova-service-desk-config"
```

Register the tool in your `NovaServiceProvider`:

```
// in app/Providers/NovaServiceProvider.php
public function tools()
{
    return [
        // ...
        new \Opscale\NovaServiceDesk\Tool(),
    ];
}
```

The tool's `menu()` method automatically adds a **Service Desk** sidebar section grouped into:

- **Task Board** — the Kanban view, with one entry per workflow
- **Operation** — Tasks and the dynamic Request resources (one per Template)
- **Administration** — SLA Policies, Categories, Accounts, Resolutions, Workflows
- **Configuration** — Templates, base Request resource

Configuration
-------------

[](#configuration)

`config/nova-service-desk.php` exposes a single resolver map keyed by **template key** (the first three uppercase characters of a task `key`):

```
return [

    // Workflow transition rules + custom priority scoring per template
    'workflow_resolvers' => [
        // 'TEC' => \App\Resolvers\TechnicalSupportWorkflowResolver::class,
    ],

];
```

Each resolver implements `Opscale\NovaServiceDesk\Contracts\WorkflowResolver`, which is the single extension point for per-template behavior:

MethodPurpose`allowedTransitions(Task, WorkflowStage)`Returns the stage IDs the task can move to from the given current stage`canTransitionTo(Task, WorkflowStage)`Guard rule executed before applying a transition (e.g. required fields, role checks)`message()`Error message surfaced when `canTransitionTo()` returns `false``priorityScore(Task)`Optional custom priority score. Return `null` to fall back to the default `priority → score` mapping in `CalculatePriority`The package also exposes two strategy contracts and an enum contract:

ContractPurpose`RequiresService`Strategy contract — `servedEntities(): array` returns the entities apt to have tasks placed on them (Customers, Departments, devices…)`ProvidesService`Strategy contract — `servingAgents(): array` returns the agents that deliver the service. `AssignTask` resolves this from the container to populate the assignee dropdown`CanTransition`Implemented by status enums (`TaskStatus`) to declare allowed master-status transitions> `RequiresService` and `ProvidesService` are NOT marker interfaces meant to be inherited by Eloquent models. They are **strategy interfaces with a single implementation per app**. The application binds one resolver class to both contracts in the service container — package code (`AssignTask`, the `Account` Nova resource) then resolves the implementation via `app(ProvidesService::class)` / `app(RequiresService::class)` instead of scanning models.

Worked examples live in `workbench/app/Resolvers/`:

- **`ServiceResolver.php`** — implements BOTH `RequiresService` and `ProvidesService` in a single class. `servedEntities()` returns the workbench `Department` records (entities that need service), `servingAgents()` returns the workbench `User` records (agents). It is wired as a singleton in `WorkbenchServiceProvider::register()`: ```
    $this->app->singleton(ServiceResolver::class);
    $this->app->bind(RequiresService::class, ServiceResolver::class);
    $this->app->bind(ProvidesService::class, ServiceResolver::class);
    ```
- **`TechnicalSupportWorkflowResolver.php`** — `WorkflowResolver` example with a stage map, a guard ("a task must have an assignee before it can be escalated"), and an overdue-aware priority bump.

Usage
-----

[](#usage)

### 1. Bootstrap data

[](#1-bootstrap-data)

Configure the records that drive the service desk via Nova:

1. **Templates** — define the intake form (fields + actions). Used to create dynamic Request resources
2. **Categories / Subcategories** — Categorize requests; subcategories carry the default `impact` and `urgency`
3. **SLA Policies** — One per priority. Each defines `max_contact_time`, `max_resolution_time`, supported channels, service hours and exceptions
4. **Accounts** — Link a customer (`User` or any morphable model) to one or more SLA policies and categories
5. **Workflows** — Optional. Each workflow has a unique `key` (matches the template key prefix), a URL `slug`, and a list of stages. Stages can be created inline with the workflow via the **Stages** repeater field

### 2. Create requests

[](#2-create-requests)

Requests are created from a Template. The Template's URI key (`Str::slug($label)`) becomes the Nova resource — e.g. a "Support Tickets" template lives at `/nova/resources/support-tickets`.

If the template has preset categorization (`account_id`, `category_id`, `subcategory_id`), those fields are hidden in the form. Otherwise the user picks them at intake time.

### 3. Assign tasks

[](#3-assign-tasks)

From a Request's detail page, click **Assign Task**. The action:

1. Generates a sequential task `key` from the subcategory key (`TEC-001-000001`)
2. Calls `CalculatePriority` (impact × urgency matrix → `Critical`/`High`/`Medium`/`Low`/`Planning`)
3. Calls `CalculateDueDate` against the Account's SLA policy for that priority
4. Resolves a workflow — first tries the explicit selection, then falls back to `Workflow::resolveForTemplate($templateKey)`
5. Sets the task to the workflow's first stage (if any) and copies its `maps_to_status` and `name`
6. Creates the task and marks the request as assigned

### 4. Transition tasks

[](#4-transition-tasks)

The unified **Change Status** action handles both modes:

- **Workflow tasks** — shows only the stages reachable from the current stage. If a `WorkflowResolver` is registered for the template key, its `allowedTransitions()` and `canTransitionTo()` decide which stages are valid; otherwise all sibling stages are shown
- **Default tasks** (no workflow) — shows the `TaskStatus` cases reachable via `TaskStatus::allowedTransitions()`

The action surfaces as a toolbar button on task detail pages thanks to `opscale-co/nova-toolbar-actions`.

### 5. Kanban board

[](#5-kanban-board)

Visit `/nova-service-desk` for the Kanban view. The URL accepts a `?workflow=` query string that selects which workflow to render:

- `/nova-service-desk` — default lifecycle (TaskStatus enum, only tasks without a workflow)
- `/nova-service-desk?workflow=technical-support` — the Technical Support workflow with its stages

Drag-and-drop between columns calls the same `ChangeStatus` action under the hood, so workflow guard rules apply identically. Browser back/forward and bookmarks work because the selected workflow is part of the URL.

The Nova menu auto-generates one entry per workflow under **Service Desk → Task Board**.

Architecture
------------

[](#architecture)

The package follows the Opscale conventions:

- **Domain layer** — `src/Models/` — Eloquent models, enums (`TaskStatus`, `SLAPriority`, `SLAPolicyStatus`, `InsightScope`, `ServiceChannel`), repository traits
- **Validation** — Models use the `Opscale\Validations\Validatable` trait with `public static array $validationRules`
- **Business logic** — `src/Services/Actions/` — Opscale Actions (`AssignTask`, `ChangeStatus`, `CalculatePriority`, `CalculateDueDate`, `GetTaskSequence`, `GetSubcategorySequence`, `GetCategorySequence`). Each action implements one business operation and exposes a `parameters()` schema, `handle()` method, and `asNovaAction()` adapter
- **Nova layer** — `src/Nova/` — Resources, Repeatables (`Stage`, `TimeSlot`, `Contact`), Metrics (`TasksByStatus`, `AverageTime`, `TaskActivity`, `OpenRequests`, `RequestActivity`)
- **HTTP** — `src/Http/Controllers/ToolController.php` exposes `GET /workflows`, `GET /tasks?workflow=`, `PUT /tasks/{id}/transition` for the Kanban frontend

Testing
-------

[](#testing)

The package ships three test suites:

```
npm run test           # Unit + Feature (Pest)
npm run test:unit      # Unit only
npm run test:feature   # Feature only
npm run test:web       # Browser (Dusk)
npm run analyse        # PHPStan level 9 with strict-rules
npm run check          # fix → refactor → lint → analyse → test
```

SuiteScope**Unit** (`tests/Unit`)Models, enums, repository helpers, transition rules — in-memory SQLite**Feature** (`tests/Feature`)Opscale Action integration — exercises `CalculatePriority`, `ChangeStatus`, `GetSubcategorySequence`, `GetTaskSequence` end-to-end against the package migrations**Browser** (`tests/Browser`)Dusk tests against Nova via `orchestra/testbench-dusk`. `ConfigurationTest` covers creating Category, Subcategory, SLA Policy and Workflow via the Nova UI; `OperationTest` covers the full operational lifecycle — create request from template, assign task, view task, transition stageBrowser tests require a built workbench:

```
./vendor/bin/testbench workbench:build
./vendor/bin/testbench dusk:chrome-driver $(your-chrome-major-version)
npm run test:web
```

The workbench seeder (`workbench/database/seeders/ServiceDeskSeeder.php`) populates a complete fixture set so you can also run `./vendor/bin/testbench serve` for manual exploration. The workbench's `WorkbenchServiceProvider` registers an example `WorkflowResolver` for the seeded `TEC` template that enforces sane stage transitions.

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](https://github.com/opscale-co/.github/blob/main/CONTRIBUTING.md) for details.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Opscale](https://github.com/opscale-co)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance96

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 68.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~12 days

Recently: every ~28 days

Total

12

Last Release

19d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3722594?v=4)[opscale](/maintainers/opscale)[@opscale](https://github.com/opscale)

---

Top Contributors

[![opscale-development](https://avatars.githubusercontent.com/u/181295122?v=4)](https://github.com/opscale-development "opscale-development (31 commits)")[![semantic-release-bot](https://avatars.githubusercontent.com/u/32174276?v=4)](https://github.com/semantic-release-bot "semantic-release-bot (12 commits)")[![kevin-Oz](https://avatars.githubusercontent.com/u/31225283?v=4)](https://github.com/kevin-Oz "kevin-Oz (2 commits)")

---

Tags

laravelpackagetoolnovaopscale

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

### Embed Badge

![Health badge](/badges/opscale-co-nova-service-desk/health.svg)

```
[![Health](https://phpackages.com/badges/opscale-co-nova-service-desk/health.svg)](https://phpackages.com/packages/opscale-co-nova-service-desk)
```

###  Alternatives

[bakerkretzmar/nova-settings-tool

A Laravel Nova tool to manage application settings.

164227.9k](/packages/bakerkretzmar-nova-settings-tool)[pdmfc/nova-info-card

A Laravel Nova info card.

15103.8k2](/packages/pdmfc-nova-info-card)[cendekia/nova-setting-tool

An app setting manager tool for laravel nova

4010.5k](/packages/cendekia-nova-setting-tool)[demency/nova-gridder

A Laravel Nova Package for resource details grids.

1615.2k](/packages/demency-nova-gridder)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
