Back to Blog
Backend Development

Invoice Backend: A Laravel REST API for Invoice Management

View Repository on GitHub

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

LayerTechnology
FrameworkLaravel (PHP)
DatabaseSQLite (local) / configurable via DB_CONNECTION
AuthLaravel Sanctum
TestingPHPUnit (phpunit.xml)
BuildVite (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:

  1. User registers → OTP generated and stored (hashed) in the database
  2. OTP emailed via a Mailable class in app/Mail/
  3. User submits OTP → backend validates hash and expiry → marks email as verified
  4. 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.

View on GitHub →