PHPackages                             faran/pulsar - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. faran/pulsar

ActiveLibrary[Admin Panels](/categories/admin)

faran/pulsar
============

An opinionated Laravel architecture for building modular, domain-driven applications at scale

v0.4.1(1w ago)174MITPHPPHP ^8.3CI passing

Since Feb 4Pushed 1w agoCompare

[ Source](https://github.com/FaranAli9/laravel-pulsar)[ Packagist](https://packagist.org/packages/faran/pulsar)[ Docs](https://github.com/faran/pulsar)[ RSS](/packages/faran-pulsar/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (10)Versions (12)Used By (0)

Pulsar
======

[](#pulsar)

> An opinionated Laravel architecture for building modular, domain-driven applications at scale.

**Pulsar is an opinionated architecture tool.** It provides a strict and explicit approach to organizing Laravel applications using clean architecture, domain-driven design, and service-oriented patterns. This architecture works well for medium-to-large scale applications, multi-tenant SaaS platforms, and teams that benefit from enforced boundaries between business logic and delivery mechanisms. If you prefer Laravel's default structure or flexible, ad-hoc patterns, Pulsar may not be the right fit.

This README is intentionally **concise**. It defines the **architectural contract**, not a tutorial. For the reasoning behind these rules — the design rationale and the decisions on record — see [ARCHITECTURE.md](ARCHITECTURE.md).

---

Table of Contents
-----------------

[](#table-of-contents)

- [Installation &amp; wiring](#installation--wiring)
- [Upgrading](#upgrading)
- [Architecture Overview](#architecture-overview)
- [Architecture Rules](#architecture-rules)
- [File Types](#file-types)
- [Commands Reference](#commands-reference)
- [Complete Example](#complete-example)
- [Contributing](#contributing)

---

Installation &amp; wiring
-------------------------

[](#installation--wiring)

Pulsar requires PHP 8.3 or newer.

```
composer require faran/pulsar --dev
pulsar install
```

`pulsar install` generates `app/Providers/PulsarServiceProvider.php`, registers it in `bootstrap/providers.php`, and re-establishes the Laravel conventions that move outside their stock paths under `app/Pulsar`: policy resolution, event-listener discovery, and Artisan command discovery. Command-directory globs are expanded before being passed to Laravel because `withCommands()` accepts concrete directories and classes.

The installer is idempotent. It backs up `bootstrap/app.php` before writing, `--dry-run` prints the complete diff without changing files, and `--force` restores the generated provider without duplicating existing wiring. If a customized `Application::configure()` chain cannot be parsed safely, Pulsar changes nothing and prints the two manual wiring calls.

The generated provider is the single place for Contract-to-adapter bindings, contextual audience bindings, request/tenant-scoped services, non-resource gates, global authorization hooks, and optional observers. Once wired, Laravel's `event:cache` and `optimize` commands remain compatible with the explicit discovery paths and provider registration.

Then generate your first service and register the provider class printed by the command in `bootstrap/providers.php`:

```
pulsar make:service Admin
```

Add `--web` when the Service also needs session-backed browser routes:

```
pulsar make:service Admin --web
```

---

Upgrading
---------

[](#upgrading)

Upgrading an existing application to v0.4.1 restores the uniform Controller-to-UseCase contract; v0.4.0 added the opt-in browser route surface. Follow the ordered migration recipes in [UPGRADING.md](UPGRADING.md). Release details are recorded in [CHANGELOG.md](CHANGELOG.md).

---

Architecture Overview
---------------------

[](#architecture-overview)

Pulsar organizes your Laravel application into **three complementary layers**.

- **Service Layer** — delivery and orchestration
- **Domain Layer** — business logic
- **Infrastructure Layer** — outbound adapters that implement Domain Contracts

Pulsar places its generated architecture under `app/Pulsar` so the application's architectural boundary is explicit. Everything inside this directory follows Pulsar's placement, dependency, and transaction rules; everything outside it remains available for ordinary Laravel code that is not governed by Pulsar. Stock Laravel directories may coexist with `app/Pulsar` indefinitely; adoption can proceed route-by-route and module-by-module.

A type belongs inside `app/Pulsar` when it calls, is called by, or implements another Pulsar type. Pure framework bootstrap and configuration that Laravel owns by convention—migrations, factories, seeders, `bootstrap/app.php`, `config/`, and `routes/`—stay in their stock Laravel locations.

---

### Service Layer

[](#service-layer)

**Purpose:** Inbound delivery and application orchestration, scoped by consumer audience (Admin, Client, Internal).

Services live in `app/Pulsar/Services` because they are part of the Pulsar delivery layer. This keeps audience-specific HTTP, CLI, queue, and scheduler entrypoints with their use cases and reusable operations. Machine-driven entrypoints normally belong to an `Internal` service.

```
app/Pulsar/Services/{Service}/
├── Providers/
│   ├── {Service}ServiceProvider.php
│   └── RouteServiceProvider.php
├── Routes/
│   ├── api.php
│   └── web.php       # generated with --web
└── Modules/{Module}/
    ├── Controllers/
    ├── Requests/
    ├── Resources/
    ├── UseCases/
    ├── Operations/
    ├── Jobs/
    └── Commands/

```

**A Service is:**

- A delivery boundary (Admin browser, Admin API, Client API)
- Scoped to a consumer audience
- A logical separation inside a single Laravel application

**A Service is NOT:**

- A microservice
- A bounded context
- A deployment unit
- An isolated database or schema

Services may share the same database, Domain layer, and deployment.

---

### Domain Layer

[](#domain-layer)

**Purpose:** Business logic independent of delivery concerns (HTTP, controllers).

Domains live in `app/Pulsar/Domain` because they represent business capabilities shared by all services. The Domain layer is reusable across delivery boundaries while remaining inside Laravel's autoloaded application namespace.

```
app/Pulsar/Domain/{Domain}/
├── Contracts/
├── Models/
├── Actions/
├── Queries/
├── DTOs/
├── ValueObjects/
├── Policies/
├── Events/
├── Listeners/
├── Notifications/
├── Mail/
├── Enums/
└── Exceptions/

```

The Domain layer is **Laravel-first**:

- Uses Eloquent models
- Uses Laravel events
- Uses Laravel authorization
- Has zero dependency on Services

It is independent of HTTP, **not** independent of Laravel.

---

### Infrastructure Layer

[](#infrastructure-layer)

**Purpose:** Concrete outbound adapters for volatile framework and vendor concerns.

```
app/Pulsar/Infrastructure/{Area}/
└── {Adapter}.php

```

Areas group capabilities such as `Payments`, `Search`, `Storage`, `Messaging`, and `Time`. Infrastructure adapters implement Domain Contracts and may depend on the framework or third-party SDKs. They never import Services, UseCases, Actions, or Operations. Domain and Services depend on the Contract; Laravel's container supplies the adapter.

The dependency rule is:

> Delivery points inward to Domain. Infrastructure points inward to Domain Contracts. Domain points at itself and its own Contracts. Nothing points at Delivery.

The consumer owns the port: when Billing needs a payment capability, Billing defines `Domain/Billing/Contracts/PaymentGateway`; a concrete implementation such as `Infrastructure/Payments/StripePaymentGateway` satisfies it.

---

Architecture Rules
------------------

[](#architecture-rules)

### Shared Vocabulary

[](#shared-vocabulary)

TermMeaning**Service**Delivery boundary for a consumer audience**Module**Feature slice within a Service**Domain**Business capability (Order, Catalog)**UseCase**Application workflow**Operation**Reusable workflow fragment for UseCases**Action**Atomic domain operation**Job**Queued workflow entrypoint in a Service module**Command**CLI/scheduler workflow entrypoint in a Service module**Listener**Domain reaction; queued listeners may enter one UseCase**Contract**Domain-owned capability boundary**Adapter**Infrastructure implementation of a Contract---

### Inbound Adapter Rule and Call Graphs

[](#inbound-adapter-rule-and-call-graphs)

Every inbound adapter is thin. It may validate, authorize, establish actor/tenant/correlation context, and call its single application entrypoint. It owns no transaction and contains no branching business logic. Apply these rules:

1. Every Controller method calls exactly one UseCase. Controllers never call Queries directly.
2. Jobs and Commands call exactly one UseCase.
3. A read-only UseCase may call one or more Queries and does not need a transaction.
4. After the UseCase returns, an HTTP Controller may perform delivery-only response assembly.

The rule applies uniformly to mutations, reads, and pages without Domain data. Extra UseCase scaffolding is deliberate: Pulsar favors one mechanically enforceable call graph so agents do not classify endpoint complexity or choose between application entrypoint types.

Jobs carry IDs, DTOs, or Value Objects, never Eloquent models, and retryable handlers are idempotent.

```
HTTP:      Request   → Controller → UseCase → {Actions, Operations, Queries, Events}
Artisan:   Console   → Command    → UseCase → ...
Queue:     Worker    → Job        → UseCase → ...
Scheduler: Schedule  → Command|Job → UseCase → ...
Event:     UseCase   → Event → Listener → {Contract side effect | Notification/Job | (queued) UseCase}

```

Synchronous Listeners never call a UseCase. A queued Listener implements `ShouldQueue` and `ShouldQueueAfterCommit`, may call one UseCase, and must be idempotent with a reentrancy guard. Only UseCases call Operations; multiple UseCases may reuse an Operation.

---

### Operations

[](#operations)

Operations are reusable workflow fragments shared across UseCases. They may include sequencing and conditional branching decisions. They must never own transactions or emit domain events.

### Cross-Domain Logic

[](#cross-domain-logic)

Cross-domain coordination belongs in **UseCases**, never in Actions.

---

### Transactions

[](#transactions)

**UseCases own all transaction boundaries.**

Actions and Operations must never manage transactions.

### Event Delivery Guarantees

[](#event-delivery-guarantees)

UseCases create and dispatch immutable domain events. The four tiers are deliberately distinct:

TierMechanismGuaranteeUse when1. Sync in-processPlain `event()`Immediate; fires before commit if dispatched inside a transactionPure in-memory reactions only2. After-commitEvent implements `ShouldDispatchAfterCommit`Discarded on rollback; can be lost if the process crashes after commitDefault for domain events3. Queued after-commitListener uses `ShouldQueue` + `ShouldQueueAfterCommit`, or Job uses `afterCommit()`Worker delivery is at-least-once; idempotency required; enqueue is not atomic with the writeExternal calls, expensive reactions, cross-aggregate work4. Outbox/inboxOutbox row written in the business transaction and relayedDurable across crashes; inbox/idempotency provides effectively-once effectsIntegration events needing guaranteed external delivery### Generated Method Conventions

[](#generated-method-conventions)

TypePublic workflow methodAction`execute`Operation`execute`Query`execute`UseCase`execute`---

### Return Types

[](#return-types)

Actions, Queries, and UseCases may return delivery-neutral domain models, collections, DTOs, Value Objects, primitives, arrays, or void. They must never return HTTP Resources, Inertia prop wrappers, redirects, or framework response objects. The Controller owns top-level response assembly; a Service Resource owns reusable field-level shaping.

### Contracts and Adapters

[](#contracts-and-adapters)

Contracts use capability names without a `Contract` or `Interface` suffix, such as `PaymentGateway` or `Clock`. A Contract signature may passively reference DTOs, Enums, Value Objects, Models, Events, other Contracts, or Laravel contracts. It must not behaviorally invoke a UseCase, Action, or Operation, and it must never import Services or concrete Infrastructure.

Concrete adapters live under `Infrastructure/{Area}` and translate vendor or framework errors into Domain exceptions at that boundary. Bind each Contract to its adapter in `PulsarServiceProvider::register()`. Use `scoped()` instead of `singleton()` when an adapter holds request- or tenant-lifetime state, and make retryable side effects idempotent.

### Optional Architecture Preset

[](#optional-architecture-preset)

Pulsar ships a recommended, opt-in Pest architecture test. It keeps Domain independent of Services, Infrastructure outside workflows and delivery, and Controllers limited to delivery types, Domain value types, and UseCases:

```
mkdir -p tests/Arch
cp vendor/faran/pulsar/presets/PulsarArchitectureTest.php tests/Arch/PulsarArchitectureTest.php
```

The preset is not installed automatically and is not required when an application already enforces equivalent dependency rules.

---

### Anti-Patterns

[](#anti-patterns)

- Fat Controllers containing business logic
- Controllers calling Queries directly
- Controllers calling Operations directly
- Actions calling other Actions
- Actions calling Queries (the UseCase or Operation passes in the data)
- Events emitted outside UseCases; Actions and Operations never emit events
- Transactions inside Actions or Operations
- Operations calling other Operations
- UseCases calling other UseCases

If you feel tempted to do any of the above, the architecture is being violated.

---

### Why Pulsar Exists

[](#why-pulsar-exists)

Pulsar optimizes for:

- Team-scale clarity
- Predictable code placement
- Easier PR reviews
- Safer refactors
- Fewer "where does this logic go?" debates

Flexibility is traded for consistency — deliberately.

---

### Browser Routes and Inertia

[](#browser-routes-and-inertia)

`make:service {name} --web` generates the existing prefixed API routes plus an unprefixed `Routes/web.php` loaded through Laravel's `web` middleware group. The unprefixed surface lets an existing Laravel route keep its URL and route name during incremental migration. Put any desired browser prefix or name scope inside that Service's `web.php`.

Pulsar does not install or require Inertia. In an Inertia application, keep the root view, client adapter, and `HandleInertiaRequests` middleware in their normal application-owned locations. Controllers choose the component and top-level props, redirects, and lazy/deferred/optional prop wrappers. Service Resources may shape reusable prop values, and `HandleInertiaRequests` owns sparse cross-page shared data. Domain types and application entrypoints remain unaware of Inertia.

Invalid Inertia form submissions use Laravel's normal redirect-and-flash validation flow. A Form Request validates and authorizes before the Controller; the Controller converts validated data to a Domain DTO, calls one UseCase, and normally returns `to_route()` after a successful mutation. Do not return a manual `422` response or override `failedValidation()` for a browser page route.

For an existing Service, browser support can be adopted manually: add `Routes/web.php`, load it with `Route::middleware('web')` from the Service's `RouteServiceProvider`, and confirm the Service provider is listed in `bootstrap/providers.php`.

---

File Types
----------

[](#file-types)

### Service Layer

[](#service-layer-1)

TypePurposeServiceBootstrap a delivery boundaryControllerHTTP handling onlyRequestValidation and authorizationResourceHTTP response shaping from Models, DTOs, and Value ObjectsUseCaseWorkflow orchestrationOperationReusable workflow fragment across UseCases (branching allowed; no transactions/events)JobIdempotent queued adapter that calls one UseCaseCommandAuthorized CLI/scheduler adapter that calls one UseCase### Domain Layer

[](#domain-layer-1)

TypePurposeModelDomain entity (Eloquent)ActionAtomic business operationDTOData transferPolicyModel-aware authorization with default-deny methodsEventImmutable, versioned domain fact dispatched after commit by defaultListenerSynchronous side effect or queued, idempotent workflow reactionNotificationDomain outbound notification carrying DTO/VO dataMailableDomain outbound mail representation carrying DTO/VO dataEnumDomain stateValue ObjectImmutable validated domain primitiveExceptionBusiness rule violationQueryRead-only domain queryContractDomain-owned port for a stable capability### Infrastructure Layer

[](#infrastructure-layer-1)

TypePurposeAdapterConcrete framework/vendor implementation of a Domain Contract---

Commands Reference
------------------

[](#commands-reference)

CommandArguments and options`install``[--dry-run] [--force]``make:service``{name} [--web]``make:controller``{name} {module} {service} [--resource]``make:request``{name} {module} {service}``make:resource``{name} {module} {service} [--collection]``make:use-case``{name} {module} {service}``make:operation``{name} {module} {service}``make:job``{name} {module} {service}``make:command``{name} {module} {service} [--signature={signature}]``make:domain``{name}``make:contract``{name} {domain}``make:model``{name} {domain}``make:action``{name} {domain}``make:dto``{name} {domain}``make:policy``{name} {domain} [--model={model}]``make:event``{name} {domain}``make:listener``{name} {domain} [--event={event}] [--queued]``make:notification``{name} {domain}``make:mailable``{name} {domain}``make:enum``{name} {domain}``make:value-object``{name} {domain}``make:exception``{name} {domain}``make:query``{name} {domain}``make:adapter``{name} {area} [--contract={FQCN|name}] [--domain={domain}]``publish:context``[--force] [--path={path}]``publish:skill``[--force] [--path={path}]``ping`—---

Complete Example
----------------

[](#complete-example)

Run `pulsar publish:context` to generate `PULSAR.md` — a complete annotated reference with end-to-end examples across the Domain and Service layers.

---

Contributing
------------

[](#contributing)

Contributions are welcome. Please follow the architecture rules and existing conventions.

---

License
-------

[](#license)

MIT License.

---

Credits
-------

[](#credits)

Built with ❤️ by Faran Ali

Inspired by:

- Lucid Architecture
- Clean Architecture
- Domain-Driven Design

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance98

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~18 days

Recently: every ~4 days

Total

11

Last Release

12d ago

PHP version history (2 changes)v0.1.0PHP ^8.2

v0.3.0PHP ^8.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/7772571?v=4)[Faran Ali](/maintainers/FaranAli9)[@FaranAli9](https://github.com/FaranAli9)

---

Top Contributors

[![FaranAli9](https://avatars.githubusercontent.com/u/7772571?v=4)](https://github.com/FaranAli9 "FaranAli9 (104 commits)")

---

Tags

phplaravellaravel 12scaffoldingcode generatorartisanarchitecturecrudDomain Driven Designenterprisedddservice layersaasmulti-tenantscalableclean architecturelaravel-architecturemodular-architecturevertical-slicelaravel-13medium-scale

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/faran-pulsar/health.svg)

```
[![Health](https://phpackages.com/badges/faran-pulsar/health.svg)](https://phpackages.com/packages/faran-pulsar)
```

###  Alternatives

[dykyi-roman/awesome-claude-code

Claude Code extension for PHP: audits (architecture, DDD, security, performance, PSR, design patterns, Docker, CI/CD, tests, docs), 3-level code review, automated bug fix, generators (DDD, CQRS, GoF patterns, PSR, tests, documentation, Docker, CI/CD), code explanation, refactoring. 26 commands, 62 agents, 259 skills.

931.4k](/packages/dykyi-roman-awesome-claude-code)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
