Invoice Backend: A Laravel REST API for Invoice Management
What Is Invoice Backend?
invoice-backend is the Laravel REST API that serves the invoice-frontend React application. It handles authentication (including OTP email verification), client and invoice CRUD, payment tracking, and data exports.
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Laravel (PHP) |
| Database | SQLite (local) / configurable via DB_CONNECTION |
| Auth | Laravel Sanctum |
| Testing | PHPUnit (phpunit.xml) |
| Build | Vite (vite.config.js for asset bundling) |
Application Structure
Laravel's app/ directory reflects the full domain complexity of an invoicing system:
app/
├── Console/ # Artisan commands (scheduled tasks, etc.)
├── Enums/ # PHP 8.1 backed enums (invoice statuses, etc.)
├── Exports/ # Excel/CSV export classes
├── Http/
│ ├── Controllers/
│ ├── Middleware/
│ └── Requests/ # Form request validation
├── Mail/ # Mailable classes (OTP, invoice delivery)
├── Models/ # Eloquent models
├── Policies/ # Authorization policies (per-user resource access)
├── Providers/ # Service providers
└── Services/ # Business logic service classes
OTP Email Verification
The backend includes OTP-based email verification — evidenced by the app/Mail/ directory and test_otp.php script at the root. On registration (or re-verification), a time-limited one-time passcode is emailed to the user. The flow:
- User registers → OTP generated and stored (hashed) in the database
- OTP emailed via a
Mailableclass inapp/Mail/ - User submits OTP → backend validates hash and expiry → marks email as verified
- Laravel Sanctum token issued only after verification is complete
Authorization with Policies
app/Policies/ contains Laravel Policy classes that enforce ownership rules. In an invoicing context, a user should only be able to view, edit, or delete their own invoices and clients. Policies are registered in AppServiceProvider and automatically resolved by Laravel's Gate.
class InvoicePolicy
{
public function view(User $user, Invoice $invoice): bool
{
return $user->id === $invoice->user_id;
}
public function update(User $user, Invoice $invoice): bool
{
return $user->id === $invoice->user_id
&& $invoice->status !== InvoiceStatus::Paid;
}
}
Service Classes
Business logic is extracted into app/Services/ rather than living in controllers. This keeps controllers thin and the logic testable in isolation.
A typical service might handle invoice numbering (auto-incrementing, padded: INV-00042), total calculation with tax, or PDF generation — all without touching the HTTP layer.
Data Exports
app/Exports/ contains export classes, likely using maatwebsite/excel (a common Laravel Excel library). This allows clients to export their invoice history to Excel or CSV directly from the application.
PHP Enums
The app/Enums/ directory uses PHP 8.1 backed enums for type-safe status fields:
enum InvoiceStatus: string
{
case Draft = 'draft';
case Sent = 'sent';
case Paid = 'paid';
case Overdue = 'overdue';
}
Using enums over plain strings means the compiler catches invalid status values and IDE auto-completion works correctly throughout the codebase.
Testing
PHPUnit is configured via phpunit.xml with a SQLite in-memory database for tests — ensuring the test suite runs fast and never touches real data.