# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Taiwan NPO (Non-Profit Organization) management platform built with Laravel 10 (PHP 8.1+). Features member lifecycle management, multi-tier financial approval workflows, issue tracking, and document management. UI is in Traditional Chinese. Currency is TWD (NT$). ## Commands ```bash # Development php artisan serve && npm run dev # Start both servers # Testing php artisan test # Run all tests php artisan test --filter=ClassName # Run specific test class php artisan test --filter=test_method_name # Run specific test method php artisan dusk # Run browser tests # Database php artisan migrate:fresh --seed # Reset with all seeders php artisan db:seed --class=TestDataSeeder # Seed test data only php artisan db:seed --class=FinancialWorkflowTestDataSeeder # Finance test data # Code Quality ./vendor/bin/pint # Fix code style (PSR-12) ./vendor/bin/phpstan analyse # Static analysis ``` ## Tech Stack - **Backend**: Laravel 10, PHP 8.1+, Spatie Laravel Permission - **Frontend**: Blade templates, Tailwind CSS 3.1 (`darkMode: 'class'`), Alpine.js 3.4, Vite 5 - **PDF/Excel**: barryvdh/laravel-dompdf, maatwebsite/excel - **QR Codes**: simplesoftwareio/simple-qrcode - **DB**: SQLite (dev), MySQL (production) ## Architecture ### Route Structure Routes split across `routes/web.php` and `routes/auth.php`. Admin routes use group pattern: ```php Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(...) ``` - **Public**: `/register/member`, `/documents` - **Member** (auth only): dashboard, payment submission - **Admin** (auth + admin): `/admin/*` with `admin.{module}.{action}` named routes The `admin` middleware (`EnsureUserIsAdmin`) allows access if user has `admin` role OR any permissions at all. ### Multi-Tier Approval Workflows Tiered approval based on amount thresholds (configurable in `config/accounting.php`): - **Small (<5,000)**: Secretary approval only - **Medium (5,000-50,000)**: Secretary → Chair - **Large (>50,000)**: Secretary → Chair → Board Finance documents follow a 3-stage lifecycle with separate status fields: 1. **Approval Stage** (`status`): Multi-tier approval based on amount 2. **Disbursement Stage** (`disbursement_status`): Dual confirmation (requester + cashier) 3. **Recording Stage** (`recording_status`): Accountant records to ledger ```php $doc->isApprovalComplete() // All required approvals obtained $doc->isDisbursementComplete() // Both parties confirmed $doc->isRecordingComplete() // Ledger entry created $doc->isFullyProcessed() // All 3 stages complete ``` ### Shared Traits - **`HasApprovalWorkflow`**: Multi-tier approval with self-approval prevention (`isSelfApproval()`) - **`HasAccountingEntries`**: Double-entry bookkeeping, auto-generation, balance validation ### Service Layer Complex business logic in `app/Services/`: - `MembershipFeeCalculator`: Fees with disability discount support - `SettingsService`: System-wide settings with caching - `FinanceDocumentApprovalService`: Multi-tier approval orchestration - `PaymentVerificationService`: Payment workflow coordination Global helper: `settings('key')` returns cached setting values (defined in `app/helpers.php`, autoloaded). ### RBAC Structure Uses Spatie Laravel Permission. Core financial roles: - `finance_requester`, `finance_cashier`, `finance_accountant`, `finance_chair`, `finance_board_member` Permission checks: `$user->can('permission-name')` or `@can('permission-name')` in Blade. ### Data Security Patterns - **National ID**: AES-256 encrypted (`national_id_encrypted`), SHA256 hashed for search (`national_id_hash`), virtual accessor `national_id` decrypts on read - **File uploads**: Private disk storage, served via authenticated controller - **Audit logging**: `AuditLogger::log($action, $auditable, $metadata)` — static class, call in controllers ### Member Lifecycle States: `pending` → `active` → `expired` / `suspended` Identity types: `patient`, `parent`, `social`, `other` (病友/家長分類). Members can have `guardian_member_id` for parent-child relationships. ```php $member->hasPaidMembership() // Active with future expiry $member->canSubmitPayment() // Pending with no pending payment $member->getNextFeeType() // entrance_fee or annual_fee ``` ### Conventions - **Status values**: Defined as class constants (e.g., `FinanceDocument::STATUS_PENDING`), not enums or magic strings - **Controller validation**: Uses Form Request classes (`StoreMemberRequest`, etc.) - **DB transactions**: Used in controllers for multi-step operations - **UI text**: Hardcoded Traditional Chinese strings (no `__()` translation layer) - **Dark mode**: Supported throughout — use `dark:` Tailwind prefix for styles ### Custom Artisan Commands - `assign:role` — Manual role assignment - `import:members` / `import:accounting-data` / `import:documents` — Bulk imports - `send:membership-expiry-reminders` — Automated email notifications - `archive:expired-documents` — Document lifecycle cleanup ### Testing Patterns Tests use `RefreshDatabase` trait. Setup commonly includes: ```php protected function setUp(): void { parent::setUp(); $this->artisan('db:seed', ['--class' => 'RoleSeeder']); } ``` Test accounts (password: `password`): - `admin@test.com` - Full access - `requester@test.com` - Submit documents - `cashier@test.com` - Tier 1 approval - `accountant@test.com` - Tier 2 approval - `chair@test.com` - Tier 3 approval ## Key Files - `routes/web.php` — All web routes (admin routes under `/admin` prefix) - `config/accounting.php` — Account codes, amount tier thresholds, currency settings - `app/Models/FinanceDocument.php` — Core financial workflow logic with 27+ status constants - `app/Models/Member.php` — Member lifecycle with encrypted field handling - `app/Traits/HasApprovalWorkflow.php` — Shared multi-tier approval behavior - `app/Traits/HasAccountingEntries.php` — Double-entry bookkeeping behavior - `app/helpers.php` — Global `settings()` helper (autoloaded via composer) - `database/seeders/` — RoleSeeder, ChartOfAccountSeeder, TestDataSeeder - `docs/SYSTEM_SPECIFICATION.md` — Complete system specification