From 5cd631fe9d813721c5974197b59912b106a68839 Mon Sep 17 00:00:00 2001 From: chrisbaner <48162172+ChrisAbner@users.noreply.github.com> Date: Tue, 27 Oct 2026 23:32:42 -0500 Subject: [PATCH] Add case studies on Bagisto, Advising App and LaravelEcomm Cordon ran on three open source Laravel apps, one per supported module structure: Bagisto (namespaces), Advising App (InterNACHI/modular) and LaravelEcomm (nwidart/laravel-modules). All 2,858 internal_access reports were checked by machine (the line contains the class, the class is declared in the reported module) and sampled by hand. No false positives. Each page gives the commit analysed, the numbers with the default config and with the public API the app already uses declared, the configuration, and the coupling that remains, with code. Bagisto's purchase-flow diagram is rendered from cordon:docs output. --- CHANGELOG.md | 3 + README.md | 2 + docs-site/.vitepress/config.mts | 10 ++ docs-site/case-studies/advisingapp.md | 51 +++++++ docs-site/case-studies/bagisto.md | 126 ++++++++++++++++++ docs-site/case-studies/index.md | 45 +++++++ docs-site/case-studies/laravelecomm.md | 72 ++++++++++ .../public/case-studies/bagisto-checkout.png | Bin 0 -> 31424 bytes 8 files changed, 309 insertions(+) create mode 100644 docs-site/case-studies/advisingapp.md create mode 100644 docs-site/case-studies/bagisto.md create mode 100644 docs-site/case-studies/index.md create mode 100644 docs-site/case-studies/laravelecomm.md create mode 100644 docs-site/public/case-studies/bagisto-checkout.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f45868..fdbdc59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to Cordon Modulith are documented here. The project follows ## [Unreleased] +### Added +- Case studies in the documentation: Cordon run on Bagisto (namespaces), Advising App (InterNACHI/modular) and LaravelEcomm (nwidart/laravel-modules), with the configuration used for each and what remained after declaring their public API. + ### Changed - When more modules are tangled than the reported cycle shows, the `cycles` message now says so ("are tangled in dependency cycles, such as A -> B -> A") instead of reading as a single cycle. In real apps the group often spans 25 to 30 modules while the example cycle has two. The violation's target, and so existing baselines, are unchanged. diff --git a/README.md b/README.md index a6e5171..df2be39 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ x [cycles] 2 boundary violations. ``` +**Tried on real apps:** on [Bagisto](https://github.com/bagisto/bagisto) (42 packages, 2,000 files) Cordon found 158 internal accesses and 30 packages tangled in dependency cycles, in 6 seconds and with no false positives. See the [case studies](https://chrisabner.github.io/Cordon-Modulith/case-studies/). + ## Requirements - PHP 8.3+ diff --git a/docs-site/.vitepress/config.mts b/docs-site/.vitepress/config.mts index 60fbd76..d798f64 100644 --- a/docs-site/.vitepress/config.mts +++ b/docs-site/.vitepress/config.mts @@ -10,6 +10,7 @@ export default defineConfig({ nav: [ { text: 'Guide', link: '/guide/introduction' }, { text: 'Recipes', link: '/recipes/expose-a-service' }, + { text: 'Case studies', link: '/case-studies/' }, { text: 'Comparison', link: '/comparison' }, { text: 'Changelog', link: 'https://github.com/ChrisAbner/Cordon-Modulith/blob/main/CHANGELOG.md' }, ], @@ -54,6 +55,15 @@ export default defineConfig({ { text: 'Replace a cross-module Eloquent relation', link: '/recipes/cross-module-relations' }, ], }, + { + text: 'Case studies', + items: [ + { text: 'Overview', link: '/case-studies/' }, + { text: 'Bagisto', link: '/case-studies/bagisto' }, + { text: 'Advising App', link: '/case-studies/advisingapp' }, + { text: 'LaravelEcomm', link: '/case-studies/laravelecomm' }, + ], + }, { text: 'More', items: [ diff --git a/docs-site/case-studies/advisingapp.md b/docs-site/case-studies/advisingapp.md new file mode 100644 index 0000000..6814af9 --- /dev/null +++ b/docs-site/case-studies/advisingapp.md @@ -0,0 +1,51 @@ +# Advising App + +[Advising App](https://github.com/canyongbs/advisingapp) by Canyon GBS is a student advising and CRM platform for colleges, built with Laravel and Filament. It is organised with [InterNACHI/modular](https://github.com/InterNACHI/modular): 37 modules under `app-modules/`, from `prospect` and `student-data-model` to `ai`, `workflow` and several integrations. + +**Analysed:** commit [`0ced55f`](https://github.com/canyongbs/advisingapp/tree/0ced55f96e13d65ba21a3845fb2736522fdbca3b), October 2026, Laravel 13.39, InterNACHI/modular 3.0.2, PHP 8.4. Cordon detected the modules on its own; no resolver configuration was needed. + +## Results + +| | Default config | Public API declared | +|---|---|---| +| Modules | 37 | 37 | +| Files analysed | 2,463 | 2,463 | +| Cross-module references | 2,774 | 2,774 | +| `internal_access` | 1,162 | 1,154 | +| `cycles` | 1 group of 29 modules | 1 group of 29 modules | +| Time / memory | 3.8 s / 152 MB | 4.5 s / 152 MB | + +The only addition was `DataTransferObjects` as a public namespace (8 reports). Unlike the other two apps, Advising App has no shared kernel, and the default public namespaces already match how it is organised: its contracts live in `Contracts` folders (14 of them, in 8 modules), which Cordon treats as public at any depth. + +```php +'public_namespaces' => ['Contracts', 'Events', 'Data', 'Enums', 'Exceptions', 'DataTransferObjects'], +``` + +## Two models carry the product + +28% of the reports point at just two classes: + +| Class | References | From modules | +|---|---|---| +| `StudentDataModel\Models\Student` | 162 | 21 | +| `Prospect\Models\Prospect` | 162 | 20 | +| `Audit\Models\Concerns\Auditable` | 61 | 16 | +| `Team\Models\Department` | 23 | 7 | + +Students and prospects are what the product is about, so it is no surprise that reports, engagements, forms, alerts and workflows all reach for them. What is interesting is that the app already has the abstraction: `StudentDataModel\Models\Contracts\Educatable`, implemented by both models and public under Cordon's defaults. Much of the code still names the concrete classes: + +```php +// app-modules/student-data-model/src/Actions/ResolveEducatableFromEmail.php +public function __invoke(?string $email, bool $includingArchived = false): Student | Prospect | null + +// app-modules/engagement/src/Filament/Pages/ViewEngagementResponse.php +if (($this->record->sender instanceof Prospect || $this->record->sender instanceof Student) && ... +``` + +Cordon gives the team a list of exactly where to move from `Student | Prospect` to `Educatable`, module by module. + +`Auditable` is a trait that 16 modules use on their models. That is a deliberate shared mechanism, and declaring it (`'audit' => ['public' => ['Models\\Concerns\\Auditable']]`) would be a one-line decision. + +## Cycles + +29 of the 37 modules belong to one group of mutually dependent modules, with 54 direct back-and-forth pairs, for example `ai` and `assistant`. The heaviest dependencies all go towards `student-data-model` and `prospect`: `report` (51 references), `engagement` (41) and `form` (36 and 39). Those two modules also depend back on most of their users: `student-data-model` on 16 of them and `prospect` on 15, from `engagement` and `task` to `timeline` and `notification`. That is what ties the group together. A module everyone depends on stays stable only if it depends on almost nothing itself. diff --git a/docs-site/case-studies/bagisto.md b/docs-site/case-studies/bagisto.md new file mode 100644 index 0000000..a9aaec9 --- /dev/null +++ b/docs-site/case-studies/bagisto.md @@ -0,0 +1,126 @@ +# Bagisto + +[Bagisto](https://github.com/bagisto/bagisto) is an open source e-commerce platform on Laravel, with about 28,000 stars on GitHub. Its features live in 42 packages under `packages/Webkul`, each with its own namespace (`Webkul\Sales`, `Webkul\Checkout`, ...), service provider and models. Packages are wired together with [Concord](https://konekt.dev/concord), which also provides model proxies so packages can refer to each other's models. + +**Analysed:** commit [`7e4b38a`](https://github.com/bagisto/bagisto/tree/7e4b38a894d4f46ab3b691cf301b0908a60f9c4b), October 2026, Laravel 13.39, PHP 8.4. + +## Results + +| | Default config | Public API declared | +|---|---|---| +| Modules | 42 | 42 | +| Files analysed | 1,997 | 1,997 | +| Cross-module references | 1,497 | 1,497 | +| `internal_access` | 919 | 158 | +| `cycles` | 1 group of 30 modules | 1 group of 30 modules | +| Time / memory | 5.7 s / 113 MB | 6.1 s / 113 MB | + +No parse errors and no false positives: every report points at a real reference (see [how we checked](./#what-we-found)). + +## From 919 to 158 + +Most of the first report came from things Bagisto shares on purpose: + +| What we declared | Why | Reports removed | +|---|---|---| +| `Core` and `DataGrid` as `open` | Every package extends their base classes: `Repository`, `TranslatableModel`, `CoreModuleServiceProvider`, `DataGrid`. They are a shared kernel. | 340 | +| `Repositories` as a public namespace | Packages read and write each other's data through repositories; the codebase is built around them as the access layer. | 323 | +| `Facades` as a public namespace | Facades such as `Cart` and `MagicAI` are the entry points packages offer each other. | 46 | +| 17 Concord proxies (`OrderProxy`, `CustomerProxy`, ...) | Proxies exist so that packages can refer to each other's models without depending on them. | 52 | + +```php +// config/cordon.php +'resolver' => 'namespace', + +'resolvers' => [ + 'namespace' => ['path' => 'packages/Webkul', 'namespace' => 'Webkul'], +], + +'public_namespaces' => ['Contracts', 'Events', 'Data', 'Enums', 'Exceptions', 'Repositories', 'Facades'], + +'modules' => [ + 'Core' => ['open' => true], + 'DataGrid' => ['open' => true], + 'Sales' => ['public' => ['Models\\OrderProxy', 'Models\\OrderItemProxy', 'Models\\InvoiceProxy']], + 'Customer' => ['public' => ['Models\\CustomerProxy', 'Models\\CustomerGroupProxy']], + // ... one entry per package that exposes proxies (10 packages) +], +``` + +Proxies sit in the same `Models` namespace as the models they hide, so they have to be listed one by one. Apps built on Concord (Bagisto, Krayin, UnoPim) would benefit from a pattern such as `Models\*Proxy`. If that is your case, tell us in an issue. + +## What remains + +The remaining 158 reports are concentrated in a few places. Four patterns stand out. + +### Order statuses are read from the model + +`Webkul\Sales\Models\Order` is used directly by 7 other packages, and all 15 references read a status constant: + +```php +// packages/Webkul/Paypal/src/Helpers/Ipn.php +$this->order = $this->orderRepository->update(['status' => Order::STATUS_PROCESSING], $this->order->id); + +// packages/Webkul/Admin/src/Config/system.php +'value' => Order::STATUS_PENDING, +``` + +Every package that needs a status now depends on the whole Eloquent model. An `OrderStatus` enum in `Webkul\Sales\Enums` would be public by default and remove all 15 reports. + +### Every payment gateway builds orders with a Sales transformer + +The six payment gateways (PayPal, Stripe, Razorpay, PayU, PhonePe and PayGlocal), plus `Shop` and `Admin`, create an order from a cart the same way: + +```php +// packages/Webkul/Stripe/src/Http/Controllers/StripeController.php +$data = (new OrderResource($cart))->jsonSerialize(); +``` + +`OrderResource` lives in `Webkul\Sales\Transformers`, an internal namespace. "Create an order from this cart" is a real capability of `Sales`, used by 8 packages, and it deserves a published contract. + +### The base payment class is an extension point + +```php +// packages/Webkul/PhonePe/src/Payment/PhonePe.php +class PhonePe extends Payment +``` + +Six gateways extend `Webkul\Payment\Payment\Payment`. That is intended, so the right fix is to declare it: `'Payment' => ['public' => ['Payment\\Payment']]` or `#[PublicApi]` on the class. Cordon makes the decision explicit instead of leaving it implied. + +### Domain code depends on the storefront + +```php +// packages/Webkul/Sales/src/Traits/InvoiceReminder.php +use Webkul\Shop\Mail\Customer\InvoiceOverdueReminder; +``` + +`Sales` sends a mail class that lives in `Shop`, the storefront package, while `Shop` uses 11 classes from `Sales`. Each depends on the other. + +## Cycles in the purchase flow + +30 of the 42 packages belong to one group of mutually dependent modules. Even the four packages at the heart of a purchase form two cycles: + +![Dependencies between Shop, Sales, Product and Checkout in Bagisto. Shop and Sales depend on each other, and so do Product and Checkout.](/case-studies/bagisto-checkout.png) + +`Checkout`'s cart item asks `Product` for its type (`AbstractType`), while every product type validates a `Checkout` cart item: + +```php +// packages/Webkul/Checkout/src/Models/CartItem.php +public function getTypeInstance(): AbstractType + +// packages/Webkul/Product/src/Type/AbstractType.php +public function validateCartItem(CartItem $item): CartItemValidationResult +``` + +Neither package can change or be tested without the other. The [break a cycle](../recipes/break-a-cycle) recipe shows the usual way out: one side publishes a contract or an event and the other depends only on that. + +## Adopting it + +With the configuration above, Bagisto could adopt Cordon today without touching its code: + +```bash +php artisan cordon:verify --generate-baseline # records the 159 current violations +php artisan cordon:verify # passes +``` + +From then on, a new controller in `Shop` that reads `Webkul\Sales\Models\Order` fails the build, while the 159 recorded ones are paid down over time. See [adopting in an existing project](../guide/baseline). diff --git a/docs-site/case-studies/index.md b/docs-site/case-studies/index.md new file mode 100644 index 0000000..4145324 --- /dev/null +++ b/docs-site/case-studies/index.md @@ -0,0 +1,45 @@ +# Case studies + +We ran Cordon Modulith on three open source Laravel applications, one for each kind of module structure it supports. The goal was to check that it works on real code, find false positives, and see what kind of coupling grows in real modular monoliths. + +| Application | Structure | Modules | Files | Violations (default config) | Violations (public API declared) | Time | +|---|---|---|---|---|---|---| +| [Bagisto](./bagisto) | Namespaces (`packages/Webkul/*`) | 42 | 1,997 | 920 | 159 | 6.1 s | +| [Advising App](./advisingapp) | InterNACHI/modular | 37 | 2,463 | 1,163 | 1,155 | 4.5 s | +| [LaravelEcomm](./laravelecomm) | nwidart/laravel-modules | 29 | 1,098 | 778 | 396 | 2.7 s | + +All three were analysed in October 2026 on Laravel 13 and PHP 8.4. Each page lists the exact commit. + +## What we found + +- **No false positives.** We checked every one of the 2,858 `internal_access` reports by machine: the reported line contains the class (or its import alias), and the class is declared in the module Cordon named. We then read a sample of each kind by hand. Every report pointed at a real reference: inheritance, constructor injection, static calls, Eloquent relations or `instanceof`. +- **Most of the first report is configuration, not coupling.** Out of the box, Cordon only treats `Contracts`, `Events`, `Data`, `Enums` and `Exceptions` as public. Real apps share more on purpose: a `Core` module every other module extends, repositories meant as the access layer, facades. Declaring those removed 83% of Bagisto's report and half of LaravelEcomm's. See [what we declared and why](#how-we-declared-the-public-api). +- **What remains is real.** A handful of models used by almost every module (`User` in 25 of 29 modules in LaravelEcomm, `Student` in 21 of 37 in Advising App), order status constants read straight from the `Order` model, and storefront code reaching into sales internals. +- **Cycles are the norm.** In all three apps, most modules belong to one large group that depends on itself: 30 of 42 modules in Bagisto, 29 of 37 in Advising App, 25 of 29 in LaravelEcomm. Counting direct back-and-forth pairs (`A` uses `B` and `B` uses `A`): 26, 54 and 34. +- **Fast enough for CI.** Between 3 and 6 seconds and under 160 MB of memory for 1,000 to 2,500 files, on a developer machine (8 cores, Docker on WSL2). + +These are snapshots of how the code is organised, not judgments. Many of these dependencies are deliberate trade-offs, and none of these projects claims to enforce module boundaries. They show what happens when boundaries are only a folder convention. + +## How we declared the public API + +For each app we read the code and declared as public only what is clearly meant to be shared: + +- an `open` shared kernel when every module extends its base classes ([configuration](../guide/configuration)), +- extra `public_namespaces` for layers the app uses as its cross-module API (repositories, facades, DTOs), +- individual classes through the per-module `public` list. + +This is our reading of each codebase, not a statement from its maintainers. Both numbers are on each page, so you can judge the difference yourself. + +## Reproducing + +Every run used the same steps: + +```bash +git clone --depth 1 https://github.com//.git && cd +composer install +composer require --dev chrisabner/cordon-modulith +php artisan cordon:modules +php artisan cordon:verify --no-baseline --format=json > report.json +``` + +The configuration used for each app is on its page. diff --git a/docs-site/case-studies/laravelecomm.md b/docs-site/case-studies/laravelecomm.md new file mode 100644 index 0000000..d3b4c72 --- /dev/null +++ b/docs-site/case-studies/laravelecomm.md @@ -0,0 +1,72 @@ +# LaravelEcomm + +[LaravelEcomm](https://github.com/KalimeroMK/LaravelEcomm) is an open source e-commerce application built with [nwidart/laravel-modules](https://github.com/nWidart/laravel-modules). Its 29 modules under `Modules/` cover the catalogue (`Product`, `Category`, `Brand`, `Attribute`), sales (`Cart`, `Order`, `Billing`, `Coupon`, `Shipping`), content (`Post`, `Page`, `Banner`) and a `Front` module for the storefront. + +**Analysed:** commit [`02d48b8`](https://github.com/KalimeroMK/LaravelEcomm/tree/02d48b8170a91a86b01d486b776fc679057d2112), October 2026, Laravel 13.39, nwidart/laravel-modules 13.0, PHP 8.4. Cordon read the modules from their `module.json` files; no resolver configuration was needed. + +## Results + +| | Default config | Public API declared | +|---|---|---| +| Modules | 29 | 29 | +| Files analysed | 1,098 | 1,098 | +| Cross-module references | 1,142 | 1,142 | +| `internal_access` | 777 | 395 | +| `cycles` | 1 group of 25 modules | 1 group of 25 modules | +| Time / memory | 2.6 s / 94 MB | 2.7 s / 92 MB | + +## A shared kernel called Core + +Almost half of the first report (379 of 777) pointed at one module. `Core` holds the base classes every module builds on: + +| Class | References | +|---|---| +| `Core\Http\Requests\CoreRequest` | 51 | +| `Core\Http\Controllers\Api\CoreController` | 44 | +| `Core\Http\Requests\Api\CoreRequest` | 44 | +| `Core\Models\Core` | 43 | +| `Core\Http\Controllers\CoreController` | 30 | +| `Core\Repositories\EloquentRepository` | 28 | + +That is a shared kernel, and Cordon expects it to be declared: + +```php +'public_namespaces' => ['Contracts', 'Events', 'Data', 'Enums', 'Exceptions', 'Interfaces', 'DTOs'], + +'modules' => [ + 'Core' => ['open' => true], +], +``` + +Marking `Core` as `open` removed 379 reports and `DTOs` another 3. (`Interfaces` made no difference here: all of them live in `Core`.) + +## What remains + +The remaining 395 reports are mostly models used across modules: + +| Class | References | From modules | +|---|---|---| +| `User\Models\User` | 87 | 25 | +| `Product\Models\Product` | 54 | 15 | +| `Order\Models\Order` | 25 | 11 | +| `Category\Models\Category` | 18 | 9 | + +`User` is a special case: 25 of its 87 references are policies, because Laravel passes the authenticated user to every policy method, and 11 are factories. Many teams would declare the user model public, or depend on `Illuminate\Contracts\Auth\Authenticatable` instead. + +The storefront is the biggest consumer: `Front` uses `Product` internals 30 times, plus `Category`, `Brand` and `Post`. A storefront that reads every catalogue model directly is hard to change without touching the catalogue, which is where a small read API per module pays off (see [expose a service](../recipes/expose-a-service)). + +27 reports come from or point at model factories (`Database/Factories`). Factories only support tests and seeders, so adding `Factories` to `exclude` is a reasonable choice for this app. + +## Cycles through Eloquent relations + +25 of the 29 modules belong to one group of mutually dependent modules, with 34 direct back-and-forth pairs. Many of them are Eloquent relations declared on both sides: + +```php +// Modules/Product/Models/Product.php +return $this->hasMany(Cart::class); + +// Modules/Cart/Models/Cart.php +return $this->belongsTo(Product::class); +``` + +`Product` knows about `Cart`, and `Cart` knows about `Product`. Relations are the most natural way to create a cycle in Laravel without noticing; the [cross-module relations](../recipes/cross-module-relations) recipe shows how to keep only one direction. diff --git a/docs-site/public/case-studies/bagisto-checkout.png b/docs-site/public/case-studies/bagisto-checkout.png new file mode 100644 index 0000000000000000000000000000000000000000..c8236092bfa66c2102669db76d067053e85d5547 GIT binary patch literal 31424 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 literal 0 HcmV?d00001