Add mandatory Service pattern guidelines: all business logic in Services, thin controllers, clean models. Document TDD approach with feature tests for routes and unit tests for services. Add role definitions (super admin vs owner) to AGENTS.md.
4.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
InvoiceShelf is an open-source invoicing and expense tracking application built with Laravel 13 (PHP 8.4) and Vue 3. It supports multi-company tenancy, customer portals, recurring invoices, and PDF generation.
Common Commands
Development
composer run dev # Starts PHP server, queue listener, log tail, and Vite dev server concurrently
npm run dev # Vite dev server only
npm run build # Production frontend build
Testing
php artisan test --compact # Run all tests
php artisan test --compact --filter=testName # Run specific test
./vendor/bin/pest --stop-on-failure # Run via Pest directly
make test # Makefile shortcut
Tests use SQLite in-memory DB, configured in phpunit.xml. Tests seed via DatabaseSeeder + DemoSeeder in beforeEach. Authenticate with Sanctum::actingAs() and set the company header.
Code Style
vendor/bin/pint --dirty --format agent # Fix style on modified PHP files
vendor/bin/pint --test # Check style without fixing (CI uses this)
Artisan Generators
Always use php artisan make:* with --no-interaction to create new files (models, controllers, migrations, tests, etc.).
Architecture
Multi-Tenancy
Every major model has a company_id foreign key. The CompanyMiddleware sets the active company from the company request header. Bouncer authorization is scoped to the company level via DefaultScope (app/Bouncer/Scopes/DefaultScope.php).
Authentication
Three guards: web (session), api (Sanctum tokens for /api/v1/), customer (session for customer portal). API routes use auth:sanctum middleware; customer portal uses auth:customer.
Routing
- API: All endpoints under
/api/v1/inroutes/api.php, grouped withauth:sanctum,company, andbouncermiddleware - Web:
routes/web.phpserves PDF endpoints, auth pages, and catch-all SPA routes (/admin/{vue?},/{company:slug}/customer/{vue?})
Frontend
- Entry point:
resources/scripts/main.js - Vue Router:
resources/scripts/admin/admin-router.js(admin),resources/scripts/customer/customer-router.js(customer portal) - State: Pinia stores in
resources/scripts/admin/stores/ - Path aliases:
@=resources/,$fonts,$imagesfor static assets - Vite dev server expects
invoiceshelf.testhostname
Backend Patterns
- Authorization: Silber/Bouncer with policies in
app/Policies/. Controllers use$this->authorize(). - Validation: Form Request classes, never inline validation
- API responses: Eloquent API Resources in
app/Http/Resources/ - PDF generation: DomPDF (
GeneratesPdfTrait) or Gotenberg - Email: Mailable classes with
EmailLogtracking - File storage: Spatie MediaLibrary, supports local/S3/Dropbox
- Serial numbers:
SerialNumberServiceservice - Company settings:
CompanySettingmodel (key-value per company)
Database
Supports MySQL, PostgreSQL, and SQLite. Prefer Eloquent over raw queries. Use Model::query() instead of DB::. Use eager loading to prevent N+1 queries.
Service Pattern
All business logic must live in Service classes (app/Services/), not in Models or Controllers. Controllers are thin — they authorize, call the service, and return a response. Models only contain relationships, scopes, accessors, mutators, and constants. Services are injected via constructor injection.
Testing (TDD)
InvoiceShelf follows TDD development style:
- Feature tests (
tests/Feature/) — test API routes end-to-end (HTTP requests, responses, database assertions) - Unit tests (
tests/Unit/) — test service classes and business logic in isolation - Write tests before or alongside implementation. Every new feature or bug fix must have tests.
Code Conventions
- PHP: snake_case, constructor property promotion, explicit return types, PHPDoc blocks over inline comments
- JS: camelCase
- Always check sibling files for patterns before creating new ones
- Use
config()helper, neverenv()outside config files - Every change must have tests
- Run
vendor/bin/pint --dirty --format agentafter modifying PHP files
CI Pipeline
GitHub Actions (check.yaml): runs Pint style check, then builds frontend and runs Pest tests on PHP 8.4.