Skip to content

Production-grade Laravel REST API | Service Bus + Repository done right | Result Type pattern | 95.5% test coverage | Clean architecture reference

Notifications You must be signed in to change notification settings

mmtaheridev/clean-api-boilerplate

Repository files navigation

Senior PHP Backend Developer — Coding Assessment

Thank you for taking the time to complete this assessment.
The goal is to demonstrate how you approach architecture, testing, and backend engineering best practices.


📖 Project: Collaborative Task Management API

Objective

Build a REST API for managing projects, tasks, comments, and notifications.
We value clean architecture, thoughtful design, and code quality over speed or feature quantity.


✅ Requirements

Core Features

  • Authentication: User registration & login (JWT or Laravel Sanctum).
  • Projects: CRUD operations. Each project belongs to a user.
  • Tasks:
    • CRUD operations.
    • Fields: title, description, status (todo/in-progress/done), due_date.
    • Filtering: by status, due date, full-text search.
    • Pagination for listing.
  • Comments: CRUD operations. Each comment belongs to a task.
  • Notifications:
    • Triggered when a task is assigned or updated.
    • Delivered asynchronously (e.g., queue).
    • Endpoint for fetching unseen notifications.

Non-Functional

  • Use a layered architecture (controllers, services, repositories, domain models).
  • Apply at least two meaningful design patterns (e.g., Repository, Strategy, Observer).
  • Database migrations must be included.
  • Cache task listings (e.g., Redis).
  • Add rate limiting for sensitive endpoints.
  • Standardized error handling and responses.

Testing

  • Unit tests for core services and repositories.
  • Integration tests for API endpoints.
  • Minimum 70% test coverage.

DevOps

  • Dockerfile + docker-compose.yml for local setup.
  • CI pipeline runs automatically (tests, static analysis, linting, security).
  • Compatible with PHP 8.2+.

Documentation

  • Update this README.md to include:
    • Setup instructions.
    • Example API requests (curl/Postman).
    • Explanation of your architectural decisions and trade-offs.
    • Which design patterns you applied, and why.

🎯 Acceptance Criteria

Your submission will be evaluated on:

  • Architecture & Patterns: Separation of concerns, justified design patterns.
  • Code Quality & Standards: PSR-12 compliance, maintainability.
  • Feature Completeness: Requirements implemented.
  • Testing: Coverage, meaningful cases, edge-case handling.
  • Documentation: Clear and professional.
  • DevOps: CI/CD awareness, Docker setup.

📝 Commit Guidelines

We value not only the final code but also how you structure your work.
Please use meaningful, structured commit messages throughout your development.

  • Follow Conventional Commits style when possible:

    • feat: — for new features
    • fix: — for bug fixes
    • chore: — for setup, configuration, or maintenance
    • test: — for adding or improving tests
    • docs: — for documentation changes
  • Examples:

    • chore: initial commit (Laravel project setup)
    • feat: add task CRUD endpoints
    • fix: correct due date validation logic

Your commit history will be reviewed as part of the assessment to understand how you approach iteration, problem-solving, and communication through code.


📌 Implementation Overview

This project demonstrates production-grade Laravel architecture, addressing common anti-patterns in the ecosystem. Published as a reference implementation following a technical assessment.

Note: Company identifiers removed for confidentiality.


🏗️ Architecture & Design Philosophy

The Service Pattern Problem

The Service Pattern is widely adopted in Laravel but frequently misimplemented. Most codebases bloat services with mixed concerns:

// ❌ Anti-pattern: Monolithic service
class TaskService {
    public function createTask($data) {
        // Validation, business logic, persistence,
        // caching, events—all coupled together
    }
}

This violates SRP, hinders testing, and creates maintenance debt.

Solution: Service Bus + Repository Abstraction

// ✅ Single-purpose orchestration
class CreateTaskService {
    public function __construct(
        private TaskRepositoryInterface $tasks,
        private ProjectRepositoryInterface $projects,
    ) {}
    
    public function execute(CreateTaskDTO $dto): Result {
        // Pure orchestration—no implementation details
    }
}

Architecture Flow
Request → Controller → Service → Repository → Model → Result → Response

Core Patterns

  • Repository: Database-agnostic persistence layer
  • Service Bus: Single-action orchestrators (no data access logic)
  • Result Type: Functional error handling (Rust/Go inspired)—explicit success/failure states eliminate exception-driven flow
  • Observer: Event-driven cache invalidation and notifications
  • Single-Action Controllers: __invoke pattern for focused HTTP handlers

Benefits

  • Services remain thin and testable
  • Swappable data layers (testing, multi-database)
  • Clear abstraction boundaries
  • Type-safe data flow with DTOs/VOs

📊 Implementation Highlights

Infrastructure

  • Stack: PHP 8.3-FPM, PostgreSQL 17, Redis, Nginx
  • CI/CD: GitHub Actions (tests, PHPStan max, PSR-12, security)
  • Testing: PestPHP—446 tests, 1,754 assertions, 95.5% coverage

API Surface (18 Endpoints)

Auth: Registration, login, logout, profile
Projects: Full CRUD
Tasks: CRUD + filtering (status, due date, search) with pagination
Comments: CRUD scoped to tasks
Notifications: Fetch unseen, mark as read

Performance & Security

  • Caching: Redis-backed task listings with event-driven invalidation
  • Queues: Async notification delivery
  • Rate Limiting: Applied to sensitive endpoints
  • Validation: Request DTOs with type safety

🚀 Quick Start

cp .env.example .env
./docker-helper.sh setup
./docker-helper.sh test

# API: http://localhost:86

📚 Documentation

Postman Collection: docs/Task-Management-API.postman_collection.json

  • All 18 endpoints with request/response examples
  • Error scenarios (validation, auth, business logic)
  • Rate limiting demonstrations

Setup: Import into Postman, configure:

  • base_url: http://localhost:86
  • auth_token: (from login response)

Standards

  • PHP 8.3 strict types
  • PSR-12 compliance
  • PHPStan level max
  • Conventional Commits

💭 Architectural Trade-offs

Decision Rationale Trade-off Verdict
Service Bus over fat services Respects SRP, maximizes testability More files/indirection vs rapid prototyping Essential for long-term maintainability
Result Type over exceptions Explicit error handling, predictable flow Less familiar to community, more verbosity Worth it for consistency and debugging
Modular Structure (domain-focused) Clear boundaries, avoids bloated modules More directories vs flat structure Scales better as codebase grows
Repository + DTOs Type-safe data flow, no opaque arrays More classes vs simple arrays Eliminates entire categories of bugs

Key Principle: Modules contain only business logic—no HTTP, no infrastructure. Application and delivery layers remain separate.


📄 Purpose

Demonstrates correct usage of Service Pattern, Repository Pattern, and modular architecture in Laravel. Not an endorsement of these patterns universally, but guidance on proper implementation when adopted.

Author: Mohammadmahdi Taheri
License: Open reference implementation

About

Production-grade Laravel REST API | Service Bus + Repository done right | Result Type pattern | 95.5% test coverage | Clean architecture reference

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages