Free PMO is a Laravel 8.x project management app for freelancers/agencies. Bilingual (English/Indonesian), timezone: Asia/Makassar.
php artisan test --parallel # Run all tests (preferred)
php artisan test # Run tests sequentially
php artisan test --filter=ManageProjectsTest # Single test class
php artisan test --filter=test_name # Single test by method nameTests use SQLite in-memory database (configured in phpunit.xml). No external services needed.
npm run dev # Development build
npm run prod # Production buildcomposer install
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan storage:link
php artisan serve
# Then visit /app-install to complete setupModels live in app/Entities/ (not app/), organized by domain:
app/Entities/Projects/- Project, Job, Task, Issueapp/Entities/Partners/- Customer, Vendorapp/Entities/Payments/- Paymentapp/Entities/Invoices/- Invoiceapp/Entities/Subscriptions/- Subscription
Models use PresentableTrait with corresponding *Presenter classes. Use $guarded (not $fillable).
Routes are split by domain in routes/web/:
routes/web/projects.php,routes/web/payments.php, etc.- Included via
routes/web.php - Admin-only routes use
Route::group(['middleware' => ['role:admin']])
Tests use BrowserKitTesting (not HTTP testing). Key helpers in tests/TestCase.php:
$this->adminUserSigningIn() // Create & auth admin user
$this->userSigningIn() // Create & auth worker user
$this->createUser('admin') // Create user with roleTests use $this->visit(), $this->submitForm(), $this->see() (BrowserKit style).
All tests use RefreshDatabase trait.
- StyleCI with Laravel preset (disabled:
not_operator_with_successor_space) - No PR comments unless asked
- Use
__()helper for translatable strings (lang files inresources/lang/{en,id,de}/)
New CRUD scaffolding available via:
php artisan crud:generate {Model}Config: config/simple-crud.php (base layout: layouts.app, base test class: Tests\TestCase)
app/helpers.php contains: format_no(), format_money(), date_id(), month_id(), flash(), etc.
These use Indonesian formatting by default (dot for thousands separator).
Two roles: admin and worker. Role checks use role:admin middleware.
Users assigned via $user->assignRole('admin').
Single migration files (no alters). For schema changes, update existing migration file directly and document ALTER SQL in commit message.
php artisan test --filter=Feature/ManageProjectsTest
php artisan test --filter="admin_can_input_new_project"- All controllers should call
$this->authorize()for access control - Routes should be wrapped in
authmiddleware group as defense in depth - Example:
$this->authorize('update', $issue)before modifying models - Policies live in
app/Policies/
- Use
gh pr createfor GitHub PR workflow - Branch naming:
fix/descriptionorfeature/description - Run
php artisan testbefore opening PR