Skip to content

Latest commit

 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Laravel API Boilerplate

A strictly-typed, production-ready Laravel 13 API starter.
Domain-driven structure · Actions + Repositories · Auth, RBAC, Stripe, OAuth & OTP — batteries included.

PHP 8.4 Laravel 13 110 tests passing PHPStan level max Laravel Pint MIT License


A clean foundation for building serious JSON APIs with Laravel. It is API-only (no Blade, no sessions), organized into self-contained domains, and wired so that controllers stay thin: validation lives in form requests, business logic in single-purpose actions, and every database touch goes through a repository interface. Static analysis runs at Larastan level max with zero errors, and the whole thing is covered by 110 passing tests.

✨ Highlights

Authentication & Access

  • Sanctum token authentication (register, login, logout, device tokens)
  • Spatie RBAC — roles & granular permissions, admin/user out of the box
  • OAuth 2.0 social login (Google & Apple) via Socialite
  • Email verification with signed URLs + email OTP flow for verifying/changing an email
  • Password reset with a frontend-friendly reset URL

Product features

  • Admin API — user CRUD with search, role filter, sort & pagination; role & permission management
  • Stripe subscriptions via Cashier — plans, Checkout, billing portal, cancel/resume, webhooks
  • Audit trail — every authenticated request is logged via Activitylog
  • Health check (database + cache) for uptime monitoring
  • Auto-generated OpenAPI docs via Scramble at /docs/api

Engineering

  • PHP 8.4 with declare(strict_types=1) everywhere, final classes, constructor promotion
  • Actions + Repositories + DTOs with a uniform ApiResponse JSON envelope
  • PHPStan / Larastan at level max, Pint for style, Rector for automated refactors
  • Pest test suite · Octane-ready · Docker Compose (Nginx + PHP + Postgres)
  • GitHub Actions CI (lint + test matrix)

🏗 Architecture

The app is organized by domain folders under app/ instead of Laravel's default Http/Models/... layout. Each domain owns its controllers, requests, DTOs, actions, resources, models, and repositories. A request flows in one direction:

HTTP request
  → routes/api/*.php             versioned under /api/v1, grouped by access level
  → {Domain}\Requests\*Request   validation + authorization
  → {Domain}\Controllers\*       thin — no business logic
  → {Domain}\Data\*Data (DTO)    immutable, built from validated input
  → {Domain}\Actions\*Action     one public execute(); the business logic
  → {Domain}\Repositories\*      interface + Eloquent impl; all DB access
  → {Domain}\Resources\*Resource response shaping
  → Support\Http\ApiResponse     uniform JSON envelope: { data, message, meta? }

Repository interfaces are bound to their Eloquent implementations in RepositoryServiceProvider, so domains depend on contracts, not Eloquent. Untyped input (validated arrays, query criteria) is read through the typed Support\Data\Input helper rather than raw casts — which is part of how the codebase stays clean at PHPStan level max.

Full guide: ARCHITECTURE.md · Quick map for tools & agents: docs/PROJECT_MAP.md

🧰 Tech stack

Area Choice
Language / Framework PHP 8.4 · Laravel 13
Auth Sanctum · Socialite (Google, Apple)
Authorization Spatie laravel-permission
Billing Laravel Cashier (Stripe)
Audit Spatie laravel-activitylog
API docs Scramble (OpenAPI)
Runtime Laravel Octane-ready
Testing Pest · PHPUnit
Quality Larastan (level max) · Pint · Rector
Database SQLite (dev) · PostgreSQL (prod)

🚀 Quick start

git clone <repo-url> && cd laravel_api_only_boilerplate
composer install
cp .env.example .env
php artisan key:generate
touch database/database.sqlite
php artisan migrate --seed   # roles & permissions (+ demo users in non-prod)
php artisan test

Serve it: php artisan serve (or php artisan octane:start). API docs at http://localhost:8000/docs/api.

Default dev login (seeded only outside production): admin@example.com / password (admin) and test@example.com / password (user).

With Docker

docker compose up -d

App available at http://localhost:8080 (Nginx → PHP, with PostgreSQL).

🚢 Production deployment

The repo ships with development defaults. Each app built from it must set the following before going live — none of this is done for you:

  • APP_ENV=production and APP_DEBUG=falseAPP_DEBUG=true leaks stack traces & secrets.
  • A real MAIL_MAILER (SMTP/SES) — the example uses log, so verification / reset / OTP mail never actually leaves the server otherwise.
  • Run a queue worker (php artisan queue:work) — verification and OTP notifications are queued, so without a worker they never send. The Docker image already runs one via Supervisor.
  • Fill the real secrets in .env: STRIPE_*, GOOGLE_* / APPLE_*, and lock CORS_ALLOWED_ORIGINS (or FRONTEND_URL) to your real domain — never *.
  • Deploy steps: php artisan migrate --force, then config:cache + route:cache.

Demo accounts are never seeded when APP_ENV=production; provision your first admin through a dedicated flow instead.

📡 API reference

All endpoints are prefixed with /api/v1. Interactive docs are generated by Scramble at /docs/api. Auth column: public · Sanctum token · admin requires the admin role.

Authentication

Method Endpoint Description Auth
POST /register Create a new account
POST /login Obtain a Sanctum token
POST /logout Revoke the current token
POST /forgot-password Request a password reset link
POST /reset-password Complete a password reset

Email verification & OTP

Method Endpoint Description Auth
GET /email/verify/{id}/{hash} Verify email via signed URL
POST /email/verification-notification Re-send the verification email
POST /user/email/send-otp Send an OTP to set/change the email
POST /user/email/verify-otp Verify the OTP and apply the email

OAuth

Method Endpoint Description Auth
GET /auth/{provider}/redirect Get the provider redirect URL
GET /auth/{provider}/callback Handle the OAuth callback (stateless)

{provider} is google or apple.

User profile

Method Endpoint Description Auth
GET /user Retrieve the authenticated user
PUT /user Update profile (name, email)

Subscriptions

Method Endpoint Description Auth
GET /subscriptions/plans List available plans
GET /subscriptions/current Current subscription status
POST /subscriptions/checkout Create a Stripe Checkout session
POST /subscriptions/portal Get the Stripe billing portal URL
POST /subscriptions/cancel Cancel the active subscription
POST /subscriptions/resume Resume a subscription on grace period
POST /stripe/webhook Stripe webhook handler

Admin (requires admin role)

Method Endpoint Description
GET /admin/health Database + cache connectivity check
GET /admin/users Paginated list (search, role filter, sort)
GET /admin/users/{id} Show a user
POST /admin/users Create a user (optional role)
PUT /admin/users/{id} Update a user
DELETE /admin/users/{id} Delete a user (self-deletion blocked)
GET /admin/roles List roles with permissions
POST /admin/roles Create a role (optional permissions)
PUT /admin/roles/{id} Update name / sync permissions
DELETE /admin/roles/{id} Delete a role (admin protected)
GET /admin/permissions List all permissions

Run php artisan route:list --except-vendor for the full, authoritative list.

📁 Project structure

app/
├── Auth/           # Register, login, password reset, email verification
├── User/           # Profile, email OTP, the User model & policy
├── Admin/          # Admin CRUD for users, roles, permissions
├── OAuth/          # Social login (Google, Apple) via Socialite
├── Subscription/   # Stripe checkout, portal, cancel/resume, plans, webhook
├── Health/         # Health check endpoint
├── Http/           # Base controller + middleware (ForceJson, request logging)
├── Providers/      # App + repository-binding service providers
└── Support/        # ApiResponse envelope · Data\Input typed reader

Each domain holds its own Actions/, Controllers/, Data/, Models/, Requests/, Resources/, and Repositories/ as needed.

🧪 Testing & quality

composer test          # lint → refactor → types → unit  (the full gate)
composer test:unit     # Pest only
composer test:coverage # Pest with coverage (min 90%)
composer analyse       # PHPStan / Larastan (level max)
composer lint          # auto-format with Pint
composer refactor      # apply Rector
Command What it checks
test:lint Pint code style (dry-run)
test:refactor Rector (dry-run)
test:types PHPStan / Larastan at level max
test:unit Pest suite — 110 passing

🔄 CI

.github/workflows/ci.yml runs on every push / PR to main:

  • lint — Laravel Pint on PHP 8.4
  • test — Pest suite (PHP version matrix)

📄 License

Released under the MIT License.

About

A strictly-typed, production-ready Laravel 13 API starter.

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages