Back to Snipe It

Snipe-IT Architecture

.ai/guidelines/snipe-it-architecture.md

8.7.03.3 KB
Original Source

Snipe-IT Architecture

Controllers

Two parallel controller trees:

  • app/Http/Controllers/ — web/UI controllers returning Blade views.
  • app/Http/Controllers/Api/ — REST API controllers returning JSON, consumed by datatables and select2.

Both trees use the same subdirectory groupings: Assets/, Licenses/, Users/, Accessories/, Consumables/, Components/, Kits/, Account/, Auth/.

API Transformers

Every API controller returns data through a Transformer in app/Http/Transformers/. Never return raw model attributes from an API controller. DatatablesTransformer wraps paginated results.

php
return (new AssetsTransformer)->transformAssets($assets, $assets->count());

This supersedes the generic advice to reach for Eloquent API Resources — follow the existing transformer convention.

Authorization

  • All authorization goes through Policies in app/Policies/.
  • CheckoutablePermissionsPolicy is the base for assets, licenses, accessories, and consumables.
  • Its checkout() / checkin() methods accept $item = null, so @can('checkout', \App\Models\Asset::class) works without an instance.

Routes

  • UI routes live in routes/web.php and in the per-entity files under routes/web/ (hardware.php, users.php, licenses.php, accessories.php, components.php, consumables.php, kits.php, models.php, fields.php, locations.php). Check both when adding or locating a UI route.
  • API routes are in routes/api.php.
  • Breadcrumbs are defined inline with ->breadcrumbs(fn (Trail $trail) => ...) from tabuna/breadcrumbs. Every UI route should have a breadcrumb.
  • Some route names contain slashes rather than dots. For example, use route('reports/unaccepted_assets').

Full Multiple Company Support (FMCS)

Setting::getSettings()->full_multiple_companies_support == '1' gates company-scoped filtering. The select2 endpoints (selectlist() methods) accept a companyId query param:

php
if ((Setting::getSettings()->full_multiple_companies_support == '1') && ($request->filled('companyId'))) {
    $query->where('table.company_id', $request->input('companyId'));
}

Wire it up from Blade with data-company-id="{{ $user->company_id }}".

Select2 AJAX Dropdowns

Use class="js-data-ajax" with data-endpoint="hardware|licenses|consumables|...". snipeit.js auto-initializes these, forwarding data-company-id as companyId and data-asset-status-type as statusType to the API.

Checkout Redirect Flow

After checkout, Helper::getRedirectOption() reads $request->redirect_option. To redirect back to the assigned user, the form must set:

  • redirect_option=target
  • checkout_to_type=user
  • assigned_user={{ $user->id }}

Translations

UI strings are translation keys in resources/lang/en-US/general.php and its sibling files. Always add a new key rather than hard-coding English in a view.

Global View Variables

$snipeSettings is shared with every view by SettingsServiceProvider. Use it directly in Blade — do not pass Setting::getSettings() from the controller.

Key Helper Methods (app/Helpers/Helper.php)

  • Helper::deployableStatusLabelList() — status labels for checkout forms.
  • Helper::defaultChartColors(int $index = 0) — 10-color chart palette.
  • Helper::getRedirectOption($request, $id, $table, $item_id = null) — post-checkout redirect logic.