Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Admin Kit Core Laravel Package

ibecsystems/admin-kit-core

Core utilities and abstractions for Laravel admin panels. Provides reusable building blocks for CRUD resources, forms, tables, filters, actions, and navigation, forming the foundation for ibecsystems/admin-kit packages and custom back-office interfaces.

View on GitHub
Deep Wiki
Context7

Getting Started

ibecsystems/admin-kit-core is a Laravel package (MIT, low adoption, ~0 dependents) that provides the shared foundation for the IBEC "Admin-Kit" admin panel line — the core layer that sibling packages and your application-specific admin code build on top of. It is more mature than the star count suggests: the project is on the 3.9.x line with 50+ merged PRs, so treat it as a real, actively maintained codebase rather than a toy — but still one with no tutorial ecosystem. The goal of your first hour is to read the source, not to read docs.

Install and confirm discovery

composer require ibecsystems/admin-kit-core
php artisan package:discover -v      # shows the provider FQCN it registers
php artisan about                    # confirms the package landed in the manifest

Check composer.json in the package first for the extra.laravel.providers entry and the PHP/Laravel constraints — the Laravel range is your compatibility contract, and with a single maintainer it moves.

Where to look first, in order

  1. composer.json — Laravel version range, require/require-dev, whether it hard-depends on another IBEC package.
  2. src/*ServiceProvider.php — register() vs boot(), what it binds into the container, what it publishes, whether it loads routes/views/translations/migrations.
  3. config/*.php — the config key namespace (probably admin-kit) and which arrays are designed to be edited by you (menus, guards, middleware, route prefixes, password policy rules) versus read-only.
  4. src/Http/ and routes/ — middleware stack and route name prefixes. Register the routes then run php artisan route:list --path=admin to see the real surface.
  5. resources/views/ — whether views are publishable and what the override path will be.

Publish config and assets before anything else

php artisan vendor:publish --provider="IbecSystems\AdminKit\AdminKitServiceProvider" --tag=config
php artisan vendor:publish --provider="IbecSystems\AdminKit\AdminKitServiceProvider"

Use --provider rather than guessing --tag values; tag names drift between releases. Re-run publish after upgrades and diff the new config against yours — config keys are added between minor versions (the v3.9.3 password-policy feature is exactly that kind of addition, and an un-republished config may silently fall back to package defaults).

First use case

Build one complete admin screen end-to-end before integrating anything else: a single model with an index table, a create/edit form, and delete — routed through the package's conventions. Include the create-user / reset-password path in that first screen if your app manages users, because since v3.9.3 the package ships its own password policy and you want to see it in action before it surprises you in staging. That one screen tells you how much the package actually does for you (menu registration, form field definitions, CRUD scaffolding, validation rules) versus how much is still your application's job. Everything after that is repetition of a pattern you've already proven.

Implementation Patterns

Compose, don't fork. The core package's value is convention. Keep your admin resources in app/Admin/ (or whatever namespace the package expects) and register them from a dedicated AdminServiceProvider in your app, so a package upgrade doesn't collide with your code.

// app/Providers/AdminServiceProvider.php
public function boot(): void
{
    AdminKit::menu(fn ($menu) => $menu
        ->group('Content', function ($group) {
            $group->add('Articles', route('admin.articles.index'), 'file-text');
        })
    );
}

Adapt the API to whatever the provider actually exposes — the pattern to follow is registration from your app into the package, never editing files under vendor/.

Own the password policy in config, not in controllers. v3.9.3 adds a password policy feature (PR #50). The right integration is a single source of truth: set the rules in the published config/admin-kit.php (or wherever the provider reads them) and let the package's validation rule apply to user creation and password changes. Do not re-implement length/complexity checks in your own FormRequests — you'll end up with two policies that disagree. If the policy surfaces as a validation rule or service, resolve it from the container so you can swap the implementation in tests.

// config/admin-kit.php (shape depends on the provider — inspect src/ first)
'password_policy' => [
    'min_length'      => 12,
    'require_mixed_case' => true,
    'require_numbers' => true,
    'require_symbols' => true,
    'uncompromised'   => false,   // only if the package supports the check
],

Before you ship, audit every path that sets a password: registration, admin-created users, password reset, profile update, seeders, and factories. A new policy that only reaches one of those is a half-migration.

Override views through the vendor path, not by patching. Publish once, then edit resources/views/vendor/admin-kit/.... That keeps the package upgradable and makes your customizations greppable. If a view you need to change isn't published, the package's own loadViewsFrom namespace still lets you drop an identically-named Blade file into the vendor view path.

Register the guard and middleware deliberately. Most admin cores ship their own auth/middleware assumptions. Map them onto your app's guard explicitly in config/auth.php and the package config rather than relying on defaults, then wrap the package's route group with your own auth:admin + rate limiting:

Route::middleware(['web', 'auth:admin', 'throttle:admin'])
    ->prefix(config('admin-kit.route_prefix', 'admin'))
    ->group(function () {
        // package routes or your resources
    });

Keep authorization in policies. If the package provides resource/CRUD abstractions, put per-record checks in Laravel policies and let the package's controllers call $this->authorize(). That way role logic lives in one place and survives a package swap.

Test at the HTTP layer. Feature tests are the cheapest way to pin down behavior you can't find in docs — and the cheapest way to catch a policy change like v3.9.3's before users do:

public function test_admin_can_view_articles_index(): void
{
    $this->actingAs(User::factory()->admin()->create(), 'admin')
        ->get(route('admin.articles.index'))
        ->assertOk()
        ->assertSee('Articles');
}

public function test_weak_password_is_rejected(): void
{
    $this->actingAs(User::factory()->admin()->create(), 'admin')
        ->post(route('admin.users.store'), [
            'name' => 'Weak', 'email' => '[email protected]', 'password' => 'password',
        ])
        ->assertSessionHasErrors('password');
}

Write one of these for every admin route you add. When a package upgrade changes a redirect, a route name, or a validation rule, these fail loudly instead of silently in production.

Build a thin internal layer. Wrap the package's entry points in 2–3 of your own base classes or helpers (a BaseAdminController, a menu() helper, a PasswordPolicy facade if the package's one is awkward). When you eventually replace or upgrade the package, you change the wrapper rather than 40 call sites. With this adoption level, the maintainer's roadmap is not a reliable dependency.

Gotchas and Tips

Docs are the source code. There is effectively no tutorial ecosystem — no Stack Overflow answers, no blog posts. Budget time for grep -rn "function " src/ and reading the provider. Write your findings into the repo (a short docs/admin-kit.md) so the next developer doesn't repeat the archaeology. Feature PRs like v3.9.3's password policy land with no docs at all, so the rule surface must be read out of src/Validation/ or similar.

Patch releases are not always patch-sized. v3.9.3 is versioned as a patch but ships a new user-facing feature (password policy). On a solo-maintained package, semver is a courtesy, not a contract. Read the changelog and the linked PR diff before bumping composer update — especially when the PR touches auth.

Pin the version. Use "ibecsystems/admin-kit-core": "3.9.*" or an exact constraint, committed with the lockfile — not the floating ^3.9 you'd default to. Minor and even patch churn can change behavior in auth-adjacent code. Review the diff before bumping, and re-publish config after each bump to see new keys.

Upgrading to 3.9.3 will break existing test fixtures. If your factories or seeders use password => 'password', an admin-created user flow, or a reset-password feature test, expect validation failures the moment the policy takes effect. Sweep the test suite after the bump and use a User::factory()->withValidPassword() state rather than hardcoding strings in dozens of places.

A password policy can lock people out. If the policy applies on the login or reset path rather than only on set-password, existing users with weak passwords may be forced into a reset flow — decide deliberately whether that's what you want, and check whether the package exposes an "existing users" or "grace" toggle. Test the login of a legacy account before deploying.

Watch for a hard sibling dependency. "Core" packages in a suite usually assume a sibling (theme, UI, generator) is installed. If composer require pulls one in, read its config too — half the behavior you're debugging may live there. The password policy feature, in particular, may be surfaced through sibling UI packages' form components.

Service provider boot order. If the package registers menus, routes, Blade directives, or validation rules in boot(), those run before your app's providers unless you order them. Symptoms: menu items missing, route names undefined in your provider's boot(), custom password rules not overriding the package's. Fix by deferring to booted() or by explicitly listing your provider after the package in bootstrap/providers.php.

Config caching will bite you. Any closure or class-string in the package's config array is fine for config:cache only if it's not a closure. Password-policy config is a prime candidate for "I changed it and nothing happened." After changing config, always php artisan config:clear locally — and remember that a cached config from before an upgrade won't have the new password_policy key at all.

Assets: check which build system it assumes. Look at resources/ and the provider's publishes() calls. If it expects published assets in public/vendor/admin-kit/, add that path to .gitignore and re-publish in your deploy script instead of committing built files.

Locale and translations. If it loads translations, override them via lang/vendor/admin-kit/. New features ship new keys — v3.9.3's password policy almost certainly adds validation messages, so check for untranslated strings after upgrading. Missing keys usually render as the raw key, not an error, so an untranslated label is a silent bug. Grep for __('admin-kit in the views and in src/ for the full key surface.

Debugging checklist when something 404s, renders blank, or validation misfires:

php artisan route:list --path=admin -v     # does the route exist, and with which middleware?
php artisan vendor:publish --list          # what's actually publishable
php artisan config:show admin-kit          # is the new password policy config actually loaded?
php artisan view:clear && php artisan optimize:clear

Then confirm the view namespace resolves (view()->exists('admin-kit::some.view')) and that the layout it extends exists in your app.

Extension points worth looking for. In packages like this the safest customization surfaces are usually: the config arrays, published views, an event or two fired around resource actions, and Blade directives/Blade::if macros. Find them with grep -rn "dispatch\|Blade::\|macro(\|Rule::" src/ and prefer them over subclassing internal classes — particularly for the password policy, where a custom rule registered through Laravel's validator is far more durable than overriding a package controller.

Plan the exit. Despite the healthy version line, assume you may need to extract yourself one day. Two habits make that cheap: keep your admin resources in your own namespace, and never let domain/business logic live in a package controller. Keep your password policy expressed as configuration plus Laravel validation rules so that swapping the package for Password::defaults() is an afternoon, not a rewrite.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons