opscale-co/nova-service-desk

Manage tasks

Maintainers

Package info

github.com/opscale-co/nova-service-desk

pkg:composer/opscale-co/nova-service-desk

Statistics

Installs: 12

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 2

1.1.0 2026-04-13 11:23 UTC

This package is auto-updated.

Last update: 2026-04-13 11:25:21 UTC


README

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 or sharing your thoughts on social media. Your feedback helps us improve and grow!

πŸ“§ Send us feedback on what we can improve at feedback@opscale.co. 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 hire@opscale.co to discuss your project needs.

Thanks for helping Opscale continue to scale! πŸš€

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

Installation

Latest Version on Packagist

Install the package in a Laravel app that uses Nova:

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

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:

Method Purpose
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:

Contract Purpose
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

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

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

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

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

Visit /nova-service-desk for the Kanban view. The URL accepts a ?workflow=<slug> 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

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=<slug>, PUT /tasks/{id}/transition for the Kanban frontend

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
Suite Scope
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 stage

Browser 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

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

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

Credits

License

The MIT License (MIT). Please see License File for more information.