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

Acacia Laravel Package

savannabits/acacia

Acacia by Savannabits is a Laravel admin panel and CRUD toolkit that scaffolds controllers, models, and Inertia/Vue screens, with built-in authentication, roles, and permissions—helping teams ship polished management interfaces quickly without rewriting the same boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Verify the stack before you install anything. Acacia targets Laravel 9.2 with Vue 3 / Tailwind 3, and the last release is v1.4.0 (May 2022). On Laravel 10/11 or PHP 8.3, assume it will not boot cleanly. Read the package's composer.json for the real constraints on php, laravel/framework, spatie/laravel-permission, and any Inertia/Vite packages, then diff them against your composer.lock.

git checkout -b spike/acacia
composer require savannabits/acacia:1.4.0 --with-all-dependencies
php artisan list | grep -i acacia     # discover real command names on this version

Publish first, read second. The vendor code is mostly plumbing; the publishable config, stubs, views, and migrations are the product. Get them into your repo and under change control immediately, because the generated output is what you will actually own:

php artisan vendor:publish --provider="Savannabits\Acacia\AcaciaServiceProvider"
git add config/ resources/ database/ stubs/ && git commit -m "chore: publish acacia artifacts (baseline)"

Where to look first, in order:

  1. config/acacia.php — layout, navigation, generator paths, admin credentials.
  2. The stubs directory — these are the contract for every resource you will ever generate. Skim each file before generating.
  3. The service provider — what it registers, what routes/middleware it loads, whether it boots a module structure (Acacia borrows from nwidart/laravel-modules, so expect a Modules/ or app/Modules convention).
  4. Migrations and seeders — users, roles, permissions land here. Check ordering against any existing users table.
  5. Only then, run one generation command and inspect what it actually writes (Blade vs. Inertia Vue pages).

First use case: the most boring model you have. A Category or Project with name, status, and one foreign key. The goal isn't a feature — it's a measurement: how many hours from artisan to a working, sortable, searchable, permission-guarded index screen you've actually reviewed and customized. Time-box it to a day and write the number down. Compare to the 2–4 hours a competent Laravel dev spends hand-building the same CRUD. That number decides whether you keep going.

Implementation Patterns

Treat generation as one-shot codegen, not a runtime framework. The moment a file lands in app/ or resources/, it is yours. There is no upstream to re-pull from — plan to regenerate only into a clean branch where you're willing to re-apply diffs, and mostly plan not to regenerate at all.

Fix the stubs before you scale out. This is the highest-leverage habit with this package. Generate one resource, review the output end-to-end, then edit the stub so the next twenty get the fix for free:

  • Replace naive search with scoped, index-aware ->when($request->q, ...) filtering instead of wide LIKE '%term%' across every column.
  • Force ->paginate(25)->withQueryString() so filter state survives pagination links.
  • Move authorization out of per-route can: middleware into authorizeResource() / a policy generated alongside the model.
  • Default the sort to an indexed column (created_at, id) rather than an unindexed display field.
  • Add a consistent #[Middleware]/route-prefix block so every module inherits the same auth + permission stack.

One afternoon on stubs beats hand-editing twenty controllers.

Drive navigation and dashboard from config, not layout Blade. Add each generated resource to the nav config in the same commit that generates it, so the menu never drifts from route:list:

// config/acacia.php — shape approximate, match your published file
'navigation' => [
    ['label' => 'Projects', 'route' => 'acacia.projects.index', 'icon' => 'folder'],
    ['label' => 'Users',    'route' => 'acacia.users.index',    'icon' => 'users'],
],

If you start hand-editing layout templates per module, the accelerator has stopped accelerating.

Wire RBAC at the seam. Acacia ships permission-ready via spatie/laravel-permission. Register permissions in an idempotent seeder (firstOrCreate), check them through policies or route middleware — never through if (auth()->user()->hasRole(...)) scattered across generated controllers. Because generated controllers are yours, you can enforce this uniformly in the stub once and forget it.

Front-end integration depends on what the generator actually writes — check before estimating. If it emits Inertia/Vue pages, you must reconcile Vite resolve.alias, the page resolver glob, and Tailwind content entries. If it emits Blade views, publish them and make sure Tailwind's content includes resources/views/vendor/acacia/**. Either way, add the package's view/component paths to tailwind.config.js by hand — omitted purges are the classic "works in dev, unstyled in prod build."

Run the daily loop, not a project. Pick a model → generate → review the diff → customize the 3–4 files that need it → add nav entry → add policy + permission seeder entry → one feature test hitting index with a filter → commit as a single reviewable unit. After the first resource that's ~30–60 minutes each, which is the realistic pitch.

Keep it on internal surfaces. Content moderation queues, support lookups, ops dashboards, user admin. The generated screens are functional, not designed — do not let a generated view leak into a customer-facing route.

Gotchas and Tips

The default admin seeder is the first thing to fix. v1.4.0's only change was adding a default admin to the Users Seeder. Read that file before running it anywhere outside local. Env-source the credentials, hash them, use firstOrCreate, and gate on environment:

$email = config('acacia.admin.email', env('ACACIA_ADMIN_EMAIL'));
$password = config('acacia.admin.password', env('ACACIA_ADMIN_PASSWORD'));

if (!$email || !$password || (app()->environment('production') && !config('acacia.allow_prod_seed'))) {
    $this->command->warn('Acacia admin seeding skipped.');
    return;
}

User::firstOrCreate(['email' => $email], [
    'name' => 'Admin', 'password' => Hash::make($password), 'email_verified_at' => now(),
]);

firstOrCreate also keeps RefreshDatabase from exploding on duplicate emails in CI.

Regeneration will clobber your work. Assume it, don't test it. Commit before generating anything; git diff is your undo. If you need a new column on a generated resource, edit the files — don't re-run the generator.

Permission cache staleness masquerades as a bug. "Admin can't see the menu after deploy" is almost always spatie's cache. Put php artisan permission:cache-reset in the deploy script and in TestCase::setUp() if you seed permissions in tests.

Generated search/sort hits unindexed columns. Fine on a 500-row admin table, a timeout on a 500k-row orders. Pair every generated resource with a two-minute index review and add composites for the columns you actually filter on.

Migration ordering against your existing users table. Acacia's auth/RBAC migrations may assume a fresh users table. On a brownfield app, run them on the spike branch and read the diffs before touching staging.

Never edit vendor/. Publish or fork. If you need a behavior change in package code, copy the class into app/Support, bind it in a provider, and note it in the runbook.

Pin the version exactly and name the fork owner. "savannabits/acacia": "1.4.0", not ^1.4. There is no upstream, so every Laravel major is a fork-and-patch task. Write down who owns it; an unowned fork rots within two majors.

Debug in this order when a screen doesn't render:

  1. php artisan route:list | grep acacia — do routes exist, what middleware stack?
  2. Published output vs. your committed resources — did something land in the wrong path?
  3. Tailwind content globs for the generated view/component directory.
  4. permission:cache-reset.
  5. composer show savannabits/acacia + PHP/Laravel versions — incompatible installs fail silently, not loudly.

Exit test before adopting. If the package vanished tomorrow, the app should still ship: published config, stubs, views, migrations, and every generated resource live in your repo; only the generator command and provider come from vendor/. Protect that property deliberately — commit every generated file, never .gitignore the output.

Safe extension points: config (navigation, layout, admin creds), stubs (all future codegen), policies + permission seeders, and your own provider wrapping generated routes with middleware. Those survive an upgrade or a fork. Monkey-patching vendor classes and loosening composer.json constraints do not.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route