Skip to content
Guide

Add a menu destination

Publish a Resource destination and a standalone App page into the App Menu, and verify each appears for the right actor.

Publish a link to an existing App screen in the App Menu. Start with an installed App from Create an App Package and a working screen; menu metadata does not create the screen or authorize its API.

Publish the destination

Implement NavigationContribution in a class under the manifest's contribution locations. Return NavigationItem values from navigationItems(). This is a complete contribution from packages/people/src/Contribution/PeopleWorkNavigation.php, reduced to one existing destination:

Code example
PHP
<?php

namespace Amuzcorp\Nexia\PeopleCore\Contribution;

use Nexia\Navigation\Contracts\NavigationContribution;
use Nexia\Navigation\NavigationItem;

final class PeopleWorkNavigation implements NavigationContribution
{
    public static function navigationItems(): array
    {
        return [NavigationItem::make(
            id: 'people-onboarding',
            route: '/apps/people/onboarding',
            icon: 'list-checks',
            sort: 210,
            labelKey: 'people.onboarding.title',
            appKey: 'people',
            contextId: 'app',
            groupId: 'management',
            permission: 'people.onboarding_case.read',
        )];
    }
}

Use an existing read permission and a locale catalog key. Keep the route's authorization in place: a permission on a destination filters the link, not requests to its endpoint. For a new custom screen, register its component and bind pageElementsExtras() as described in Build an App screen.

Refresh discovery after adding the class:

Code example
Shell
task artisan -- nexia-runtime:generate-app-map
task artisan -- nexia-runtime:refresh-runtime-caches

Confirm the result

With the App operational and the permission assigned, open its menu: Onboarding belongs under Management and opens the existing screen. Switch to an actor without the read permission: the link disappears and the protected API refuses the same read. Search the localized label in the Command Palette to check searchable behavior.

Resource lists and placement

A generated Resource already publishes navigation through ContributesNavigationDestination; change its $navigation declaration instead of adding a second contributor. Create a Resource owns generation. visible: false keeps the Resource routable while removing its menu entry.

PlacementUse
contextId: 'app'Resolves to the owning app:{app_key} context
groupId: nullDirect destination, including the App overview
insights, management, operations, master-data, settingsSupported App groups
subgroupIdSubdivision within a group; requires groupId
permission arrayAny listed permission makes the destination discoverable
searchable: falseExclude this destination from search

The platform owns Shell contexts and group order. Use Add a settings page for configuration and Command Palette for optional agent locate actions. NavigationItem in packages/app-sdk/packages/laravel/src/Navigation/NavigationItem.php defines optional parent, active-pattern, and subject-population fields.

When an entry is missing

A discovered contribution still needs an operational App, an actor with its permission, and a registered destination component. nexia-apps:doctor-package-app diagnoses contribution and page-component wiring; it does not assign permissions. A blank screen usually means the route/component pairing is incomplete. Follow Test an App for the package-level check.

Source of truth: docs/developers/content/en/platform-extensions/add-navigation.md