Skip to content

The app/Pulsar architecture boundary

app/Pulsar is the boundary Pulsar governs. Types inside follow Pulsar's placement, dependency, and transaction rules; Laravel-owned seams and unrelated application code remain outside and may coexist indefinitely.

Classify the type, not its parent directory

The deciding question is whether the exact type participates in a Pulsar dependency edge. New or deliberately migrated audience delivery, business capabilities, and outbound Adapters belong inside the boundary. Bootstrap, configuration, database support files, tests, and ordinary or legacy types with no such edge keep their stock Laravel homes.

A type that participates in a Pulsar dependency edge belongs inside app/Pulsar as audience delivery, a business capability, or an outbound Adapter. Laravel-owned seams and ordinary code with no Pulsar dependency edge remain outside in stock application locations.
Decide whether a type belongs inside app/Pulsar. Participation in Pulsar architecture—not a desire to reorganize every Laravel file—sets the boundary.

Interpretation. A participation edge moves the bounded type inside app/Pulsar; Laravel-owned seams and unrelated application code remain outside. The question applies to the type, not its whole parent directory.

This is an additive boundary. An existing Controller can remain in app/Http/Controllers while a new feature lives in a Service Module. Moving one Model into a Domain does not require moving every Model, its parent directory, or unrelated callers.

Use the placement boundary

Type or concernInside or outside app/PulsarBoundary reason
Service and ModuleInside app/Pulsar/Services/{Service}/Modules/{Module}The Service names an audience; the Module groups a related delivery and workflow slice.
New delivery typesInside the owning Service ModuleA Controller, Request, Resource, Job, or Command that participates in the Pulsar slice is governed delivery.
Service routes and providerInside the ServiceThey assemble the audience boundary; Laravel registration seams remain outside.
Domain capabilityInside app/Pulsar/Domain/{Domain}Shared business capability belongs to the Domain.
Eloquent ModelInside when it is new or deliberately migrated for a Pulsar edgeExisting App\Models types may remain legacy until that exact type moves with parity evidence.
Domain Event, Listener, or PolicyInside the owning DomainThey participate in the capability; detailed delivery and authorization rules belong to later architecture pages.
Contract and AdapterInside the Domain contract area and an Infrastructure areaThe Domain owns the Contract and Infrastructure holds the concrete outbound Adapter; the complete dependency rules come later.
Existing routesOutside by defaultStock route files can keep existing behavior and explicitly enter new Service routes.
Migrations, factories, and seedersOutside under database/Laravel owns these application data seams.
ConfigurationOutside under config/Configuration remains a Laravel-owned seam.
TestsOutside under tests/Tests verify the application without becoming governed production types.
bootstrap/app.php and bootstrap/providers.phpOutsideLaravel owns application bootstrap and provider registration.
app/Providers/PulsarServiceProvider.phpOutsideIt is the application-wide Laravel registration seam for Pulsar.
Existing Controller, Request, or ModelOutside by defaultMove only the exact bounded type after a deliberate parity migration, not its parent or callers automatically.

This table sets the philosophy boundary, not the complete placement and dependency matrix. Architecture owns the detailed rules as those pages are published.

See what stays outside Pulsar

Laravel bootstrap, configuration, migrations, factories, seeders, tests, and provider registration stay outside because Laravel owns those seams. Ordinary application code with no Pulsar dependency edge can also remain in stock locations forever. Pulsar adoption does not require a repository-wide reorganization.

Code outside the boundary may call a deliberately exposed Pulsar entry point. That call does not automatically move the caller, its siblings, or its directory. Conversely, putting an unrelated type under app/Pulsar merely for visual consistency would subject it to rules it does not need.

For a migration procedure with behavior protection and reversible checkpoints, use Adopt Pulsar in an existing application. That guide owns the operational sequence; this page owns the stable classification principle.

Defer the detailed edge rules

The next architecture PRDs define the full placement matrix, behavioral versus passive dependencies, transaction ownership, Event delivery, authorization, tenancy, discovery, bindings, stable identifiers, long-lived workers, and anti-patterns. This page intentionally does not pre-publish those rule sets.

Continue to the audience-based Services explanation for the vocabulary inside the boundary, or Trade-offs and non-goals to decide whether the boundary is worth its cost.