Files
InvoiceShelf/CLAUDE.md
Darko Gjorgjijoski c3ad718799 Document Service pattern and TDD requirements in CLAUDE.md and AGENTS.md
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.
2026-04-03 22:38:53 +02:00

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/ in routes/api.php, grouped with auth:sanctum, company, and bouncer middleware
  • Web: routes/web.php serves 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, $images for static assets
  • Vite dev server expects invoiceshelf.test hostname

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 EmailLog tracking
  • File storage: Spatie MediaLibrary, supports local/S3/Dropbox
  • Serial numbers: SerialNumberService service
  • Company settings: CompanySetting model (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, never env() outside config files
  • Every change must have tests
  • Run vendor/bin/pint --dirty --format agent after modifying PHP files

CI Pipeline

GitHub Actions (check.yaml): runs Pint style check, then builds frontend and runs Pest tests on PHP 8.4.