Skip to content

Advising App ​

Advising App by Canyon GBS is a student advising and CRM platform for colleges, built with Laravel and Filament. It is organised with InterNACHI/modular: 37 modules under app-modules/, from prospect and student-data-model to ai, workflow and several integrations.

Analysed: commit 0ced55f, 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 configPublic API declared
Modules3737
Files analysed2,4632,463
Cross-module references2,7742,774
internal_access1,1621,154
cycles201 dependencies in 1 group of 29 modules201 dependencies in 1 group of 29 modules
Time / memory3.8 s / 152 MB4.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:

ClassReferencesFrom modules
StudentDataModel\Models\Student16221
Prospect\Models\Prospect16220
Audit\Models\Concerns\Auditable6116
Team\Models\Department237

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's report lists, module by module, every place that names the concrete classes, which is where a move to Educatable would start.

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.

MIT licensed. A community project, not affiliated with or endorsed by Laravel or Spring.