badaso/core
Badaso is an open-source headless CMS and admin dashboard for Laravel built with Vue.js. This core package provides CRUD generators, media management, API-first content delivery, roles and permissions, and customizable modules for rapid backend and app development.
Badaso is a Laravel package that bolts an admin panel, a JWT-authenticated REST API, a CRUD/schema generator, a media manager, a menu builder, and a role/permission system onto a fresh Laravel app. Mentally model it as "Nova's admin + a low-code entity builder + an API layer you can extend," not as a library you call into from your own code.
Minimal path:
composer.json of the release you pin — 2025 releases track current Laravel majors).composer require badaso/corephp artisan badaso:setup. This publishes config/badaso.php, runs the package migrations, seeds roles/permissions/menus/configurations, and creates the first admin user. If the command isn't present in your version, the manual equivalent is: publish config + migrations, php artisan migrate, then seed the Badaso seeders.php artisan storage:link, and set the JWT secret in .env (Badaso uses tymon/jwt-auth, not Sanctum)./badaso (prefix lives in config/badaso.php) with the seeded admin, and change the credentials and JWT secret before anything else.2.9.13+) in config/badaso.php — it controls whether the public registration endpoint is open, closed, or restricted. Decide this before exposing the API./api/v1/.... Hit one with the JWT from the login endpoint to confirm the loop end to end.Where to look first, in order:
config/badaso.php — dashboard prefix, API prefix, guards/providers, media disk, module registration, and (from 2.9.13) the registration mode.badaso_* tables (badaso_users, badaso_roles, badaso_permissions, badaso_configurations, badaso_menus, badaso_media, badaso_activity_logs) — this is the actual data model of the platform.vendor/uasoft-indonesia/badaso/core/src — Routes/, Helpers/ApiResponse.php, and the module directory structure. Read the routes file once; it tells you what you'd otherwise guess.php artisan route:list --path=api/v1 to see exactly what surface you got — including the auth/registration endpoints, which change behavior with the registration mode setting.Use it as the control plane, not the app. Keep your business logic in App\ controllers/models and let Badaso own auth, RBAC, media, settings, and admin UI. The moment you write domain logic inside the dashboard's CRUD entities, you've coupled your product to a UI generator.
Generated CRUD is scaffolding, not the contract. Generate the entity, then treat the produced migration/model as a starting point you own. Add indexes, casts, relationships, and validation in code — the generator gives you columns and endpoints, not domain rules.
Reuse the response envelope. Badaso controllers return a wrapped payload via its ApiResponse helper (success/failed). If you add your own endpoints and return raw response()->json(), any client or dashboard page built against the Badaso shape breaks. Match the envelope in every custom controller.
One module per bounded context. Badaso's module system is a mini-package: routes, migrations, controllers, config, registered in config/badaso.php. Put each business domain in its own module, never edit vendor/. That's also the only sane way to ship dashboard pages — a module with its own routes and menu entry, registered through the menu manager.
Auth flow. Login → JWT access token → store it client-side → refresh on a schedule shorter than the TTL. Badaso authenticates against badaso_users with its own guard/provider, so treat it as a separate identity store from Laravel's default users table unless you deliberately unify them.
Registration is a policy decision, not a default. Since 2.9.13 the registration mode is configurable. Set it explicitly per environment: closed for internal admin panels, open only where you actually want self-service signup, and restricted where new accounts need approval or role assignment. Anyone who lands in badaso_users inherits whatever your default role grants, so pair the mode with a deliberately minimal default role. If you need invite-only or domain-restricted signup, override the registration handler in your own module rather than forking the vendor route.
Permissions as the single source of truth. Seed permissions per entity/action, attach to roles in the dashboard, and guard both your API routes and your own controllers with the same permission names. This keeps the admin UI and the API in agreement about who can do what.
Settings table as feature flags. Read configurable values from badaso_configurations instead of hardcoding, so ops can change limits, keys, and toggles from the UI without a deploy. Wrap reads in a small cached accessor — the table is not meant to be hit on every request.
Media through the manager. Upload via Badaso's media endpoints and store the returned path/id, not a raw file. You get dashboard-browsable assets, thumbnails, and a consistent disk config for free; hand-rolled uploads end up invisible to the admin UI.
Deploy script reality. Every environment needs the publish + migrate + storage:link steps, plus a cache clear. Add php artisan migrate --force and the publish step to your pipeline, and re-check published files after each version bump.
vendor/. Published config, migrations, and custom modules are the extension points. Vendor edits vanish on composer update and are the most common way people get stuck on an old version.2.9.13 lands in the vendor copy of config/badaso.php; an app that published its config on 2.9.12 won't have the key, and the package falls back to the vendor default. Diff your published config against the new vendor copy and merge the new key explicitly — otherwise you're on an implicit default you never chose.config/badaso.php. Changing BADASO_* env values, the dashboard prefix, or the registration mode does nothing until php artisan config:clear. Symptom: "I changed the setting and it's still behaving the old way."badaso_users for unexpected rows./api/v1. Badaso owns a large slice of that namespace. Run route:list before adding routes, and put your own endpoints under a distinct segment rather than fighting for the same prefix.Auth::user() may not be what you expect. On the default web guard it's a plain Laravel user; Badaso users live behind its own provider. Permission checks written against the wrong guard silently return false — a classic "403 that looks like a bug."APP_URL. Media paths are stored relative to the configured disk; a mismatched APP_URL, a missing storage:link, or a different FILESYSTEM_DISK per environment produces 404s that look like upload failures.upload_max_filesize/post_max_size alongside the package's own validation rules.badaso_permissions rows manually.storage/logs/laravel.log, and check badaso_activity_logs to see what the admin actually did.2.9.13 still add config surface. Lock the version, upgrade deliberately, and diff your published config/migrations against the new vendor copies — that diff is your migration checklist./badaso on a separate host or behind auth/IP rules so it never loads in customer sessions.config/badaso.php (prefix, guards, modules, media disk, registration mode) → module service providers and route files → the ApiResponse helper for payload consistency → the menu manager for dashboard navigation → custom middleware registered in a module's config.How can I help you explore Laravel packages today?