ninjaportal / portal
A Laravel Like Apigee DevPortal
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.2
- illuminate/contracts: ^11.0||^12.0
- lordjoo/laraapigee: ^0.1
- nesbot/carbon: ^3.0
- spatie/laravel-package-tools: ^1.16.3
- spatie/laravel-permission: ^6.9
Requires (Dev)
- laravel/pint: ^1.20
- orchestra/testbench: ^9.0||^10.0
- phpstan/phpstan: ^1.12||^2.0
- phpunit/phpunit: ^11.5
This package is auto-updated.
Last update: 2026-03-02 02:40:17 UTC
README
Core domain package for NinjaPortal.
It provides:
- Portal data models (users, categories, API products, audiences, menus, settings)
- Repository + service abstractions
- Translatable model support
- Apigee-backed developer app + credential services
- Core events/policies/RBAC seeding
ninjaportal/portal intentionally keeps API authentication concerns out of the core
package. JWT-aware user/admin models are provided by ninjaportal/portal-api.
Install
From the Laravel app (backend):
php artisan portal:install
Safer install options:
php artisan portal:install --force-provider-overwrite php artisan portal:install --delete-default-users-migration
Notes:
- The installer does not overwrite
App\Providers\NinjaPortalServiceProviderunless you pass--force-provider-overwrite. - The installer does not delete Laravel's default users migration unless you pass
--delete-default-users-migration.
Seeding
php artisan portal:seed --all php artisan portal:seed --settings --rbac php artisan portal:seed --demo
RBAC And Policies
The package now standardizes model-policy permissions using:
portal.{model}.{ability}
Examples:
portal.user.view_anyportal.user.updateportal.api_product.createportal.setting_group.delete
Route/API level permissions remain:
portal.admin.accessportal.rbac.manageportal.admins.manageportal.activities.view
The RbacSeeder seeds both route-level permissions and model-policy permissions.
Service Implementation Standards
1. Eloquent-backed domain services
Use this pattern:
- Extend
BaseService - Implement a
...ServiceInterface - Use
CrudOperationsTrait - Inject a repository interface in the constructor
- Keep business-specific methods small and focused
Examples:
src/Services/UserService.phpsrc/Services/ApiProductService.phpsrc/Services/SettingService.php
2. External/Apigee-backed services
Use this pattern:
- Implement a dedicated interface (not
ServiceInterface) - Wrap LaraApigee service calls
- Use consistent error logging via
ReportsServiceFailuresTrait - Emit portal domain events after successful mutations
Examples:
src/Services/UserAppService.phpsrc/Services/UserAppCredentialService.php
Event Naming Standard
Preferred event naming is:
{DomainThing}{Action}Event
Examples:
UserCreatedEventApiProductUpdatedEventUserAppCredentialCreatedEvent
Publishing policy:
...Eventis the canonical and only supported class name- do not add no-suffix event classes
FireEventsTrait dispatches the ...Event class only.
Credential-related events may include credentialKey when the operation targets a
specific credential (approve/revoke/delete/product mutations). Generated-key events
include it when the upstream Apigee client returns the created key.
App-Level Wiring (Listeners / Observers)
The package publishes an app provider stub:
App\Providers\NinjaPortalServiceProvider
Use it to wire project-specific listeners/observers (for example syncing users to Apigee on create/update).
Testing And Static Checks (Package)
After installing package dev dependencies:
composer install
composer test
composer analyse
composer format
Known Tradeoffs (Current)
- Migration rollback safety is not guaranteed for every migration path.
- Demo seeders are intended for one-time/demo environments and are not guaranteed to be re-runnable.
restore()is only supported for models using EloquentSoftDeletes; other models will throw a clear exception ifrestore()is called.