mirror of
https://github.com/snipe/snipe-it.git
synced 2026-08-18 03:06:23 +00:00
Migrate old Claude file to guidelines
This commit is contained in:
71
.ai/guidelines/snipe-it-architecture.md
Normal file
71
.ai/guidelines/snipe-it-architecture.md
Normal file
@ -0,0 +1,71 @@
|
||||
# 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.
|
||||
32
.ai/guidelines/snipe-it-stack.md
Normal file
32
.ai/guidelines/snipe-it-stack.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Snipe-IT Stack & Tooling
|
||||
|
||||
## Frontend Is Laravel Mix, Not Vite
|
||||
|
||||
- Assets are built with **Laravel Mix (webpack)** via `webpack.mix.js`. This project has no `vite.config.js` and no Vite manifest.
|
||||
- There is **no `npm run build` script**. Ignore any generic guidance that tells you to run it. Use:
|
||||
- `npm run dev` — development build
|
||||
- `npm run watch` — rebuild on change
|
||||
- `npm run prod` — production build
|
||||
- If the user doesn't see a frontend change, ask them to run `npm run dev` or `npm run watch`.
|
||||
|
||||
## UI Layer
|
||||
|
||||
- **AdminLTE 2 / Bootstrap 3** Blade views. There is no Inertia.
|
||||
- **Livewire v4 is installed** and used for discrete widgets in `app/Livewire` (e.g. `Importer`, `CustomFieldEditor`, `LdapSettings`). It is not the primary UI layer.
|
||||
- Default to a Blade view plus a standard controller. Only reach for Livewire when extending an existing Livewire component or when the user asks for it.
|
||||
|
||||
## Charts
|
||||
|
||||
- **Chart.js v2.9.4**, bundled at `public/js/dist/Chart.min.js`.
|
||||
- Use the **v2 API**, not v3. For example, the chart type is `horizontalBar` (v3 removed it in favor of `indexAxis`).
|
||||
- Use `Helper::defaultChartColors()` for the 10-color palette.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Clear caches after config/route changes
|
||||
php artisan optimize:clear
|
||||
|
||||
# Coverage reports (served by Laravel Herd)
|
||||
herd coverage
|
||||
```
|
||||
11
.ai/guidelines/snipe-it-testing.md
Normal file
11
.ai/guidelines/snipe-it-testing.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Snipe-IT Testing
|
||||
|
||||
- Feature tests live in `tests/Feature/`, organized by entity (e.g. `tests/Feature/Assets/AssetsTest.php`). Unit tests live in `tests/Unit/`.
|
||||
- Feature tests hit the database. The test environment uses `array` drivers for cache, session, and mail.
|
||||
- Always build test data with model factories. Check for an existing custom state before setting attributes by hand.
|
||||
- UI GET routes should have both a "page renders" test and a permission test — follow the naming used by siblings (`testPageRenders`, `testRequiresPermission`).
|
||||
|
||||
```bash
|
||||
php artisan test tests/Feature/Assets/AssetsTest.php # single file
|
||||
php artisan test --filter testSomeMethod # single method
|
||||
```
|
||||
@ -1,110 +0,0 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Stack
|
||||
|
||||
- **PHP 8.2+** / **Laravel 12** (framework), **Laravel Mix** (webpack) for frontend assets
|
||||
- **AdminLTE 2** / **Bootstrap 3** UI — Blade views, no Livewire/Inertia
|
||||
- **Chart.js v2.9.4** — bundled at `public/js/dist/Chart.min.js`; use `horizontalBar` type (v2 API, not v3)
|
||||
|
||||
## Common Commands
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
php artisan test
|
||||
# or
|
||||
vendor/bin/phpunit
|
||||
|
||||
# Run a single test file
|
||||
php artisan test tests/Feature/Assets/AssetsTest.php
|
||||
|
||||
# Run a specific test method
|
||||
php artisan test --filter testSomeMethod
|
||||
|
||||
# Build frontend assets (dev)
|
||||
npm run dev
|
||||
|
||||
# Build for production
|
||||
npm run prod
|
||||
|
||||
# Laravel Mix watch
|
||||
npm run watch
|
||||
|
||||
# Tinker / REPL
|
||||
php artisan tinker
|
||||
|
||||
# Clear caches after config/route changes
|
||||
php artisan optimize:clear
|
||||
```
|
||||
|
||||
Dev server is served via **Laravel Herd** (`herd coverage` for coverage reports).
|
||||
|
||||
## Architecture
|
||||
|
||||
### Controllers
|
||||
|
||||
Two parallel controller trees:
|
||||
- `app/Http/Controllers/` — web/UI controllers (Blade views)
|
||||
- `app/Http/Controllers/Api/` — REST API controllers (JSON, used by datatables + select2)
|
||||
|
||||
Subdirectory groupings: `Assets/`, `Licenses/`, `Users/`, `Accessories/`, `Consumables/`, `Components/`, `Kits/`, `Account/`, `Auth/`
|
||||
|
||||
### API Pattern
|
||||
|
||||
Every API controller returns data via a **Transformer** (`app/Http/Transformers/`). Never return raw model attributes from API controllers — always pass through the transformer. `DatatablesTransformer` wraps paginated results.
|
||||
|
||||
```php
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
|
||||
```
|
||||
|
||||
### Authorization
|
||||
|
||||
All authorization goes through **Policies** (`app/Policies/`). `CheckoutablePermissionsPolicy` is the base for assets/licenses/accessories/consumables — its `checkout()` / `checkin()` methods accept `$item = null` so you can use `@can('checkout', \App\Models\Asset::class)` without an instance.
|
||||
|
||||
### FMCS (Full Multiple Company Support)
|
||||
|
||||
`Setting::getSettings()->full_multiple_companies_support == '1'` gates company-scoped filtering. The select2 API endpoints (`selectlist()` methods) accept a `companyId` query param — apply it like this:
|
||||
|
||||
```php
|
||||
if ((Setting::getSettings()->full_multiple_companies_support == '1') && ($request->filled('companyId'))) {
|
||||
$query->where('table.company_id', $request->input('companyId'));
|
||||
}
|
||||
```
|
||||
|
||||
Pass `data-company-id="{{ $user->company_id }}"` in Blade to wire it to select2.
|
||||
|
||||
### 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.
|
||||
|
||||
### Routes
|
||||
|
||||
All routes are in `routes/web.php` (UI) and `routes/api.php` (API). Breadcrumbs are defined inline using `->breadcrumbs(fn (Trail $trail) => ...)` from `tabuna/breadcrumbs`. Every UI route should have a breadcrumb.
|
||||
|
||||
Note: the `reports/unaccepted_assets` route is named with slashes, not dots — use `route('reports/unaccepted_assets')`.
|
||||
|
||||
### Translations
|
||||
|
||||
String keys live in `resources/lang/en-US/general.php` (and other files in that directory). Always add new UI strings as translation keys rather than hard-coding English.
|
||||
|
||||
### Checkout Redirect Flow
|
||||
|
||||
After checkout, `Helper::getRedirectOption()` reads `$request->redirect_option`. For redirecting back to the assigned user after checkout:
|
||||
- Set `redirect_option=target` in the form
|
||||
- Set `checkout_to_type=user` in the form
|
||||
- Set `assigned_user={{ $user->id }}` in the form
|
||||
|
||||
### Key Helper Methods (`app/Helpers/Helper.php`)
|
||||
|
||||
- `Helper::deployableStatusLabelList()` — status labels for checkout forms
|
||||
- `Helper::defaultChartColors()` — 10-color palette used in charts
|
||||
- `Helper::getRedirectOption($request, $id, $table)` — post-checkout redirect logic
|
||||
|
||||
### Global View Variables
|
||||
|
||||
`$snipeSettings` is injected into all views via a service provider — no need to pass `Setting::getSettings()` from every controller. Use it directly in Blade.
|
||||
|
||||
## Testing
|
||||
|
||||
Tests live in `tests/Feature/` (organized by entity) and `tests/Unit/`. Feature tests hit the database; the test environment uses `array` cache/session/mail drivers. Tests use factories for data setup.
|
||||
Reference in New Issue
Block a user