Module Development Standard
Every business capability on this platform is a module. Modules are licensed via the marketplace catalog and authorized via Spatie permissions. They are not PHP packages or plugins.
Reference implementation: Leads
Guides
| Audience | Document |
|---|---|
| Engineers | module-development-developer.md |
| Production / ops | module-development-production.md |
| Documentation | documentation-governance.md |
| Architecture freeze | ../architecture/platform-freeze.md |
| Module architecture | module-architecture.md |
| Module dependencies | module-dependencies.md |
| Module licensing | module-licensing.md |
| Notification contracts | notification-architecture-contract.md |
Principles
- Consistency over abstraction — flat Laravel layout; register through existing catalog, permissions, middleware, nav, and settings.
- Licensing ≠ authorization —
module:{slug}thencan:{slug}.{action}. - Mirror Leads — Tasks, Calendar, Communication Templates, Invoices, Inventory, Purchases, HR, Payroll, Accounting, Assets, Projects must follow the same licensing + permission + UI structure (Communication Templates is additionally a cross-cutting consumer pattern).
- No shortcuts — every module ships backend, frontend, tests, docs, and CHANGELOG in the same delivery (Documentation Governance).
- Migrate-only production — new default modules and permissions ship as data migrations; never production
db:seedfor catalog/RBAC. - Self-contained modules — each module owns its migrations, models, services, routes, UI, permissions, settings, docs, and tests; communicate through contracts/services only. See Module Architecture.
- Declare dependencies — required vs optional; free vs billable. See Module Dependencies.
- Independent licensing — design every module so it can be included, free, or billable. See Module Licensing.
Cross-cutting patterns (Sprint 2+)
- Dashboard widgets — register via
DashboardWidgetServiceonGET /dashboard; gate by module entitlement, permission, and assignee scope (see Calendarcalendarwidget as the latest example). - Notifications — Follow the frozen Notification Architecture Contract: versioned payload, route descriptors, NotificationBatch aggregation, Reverb/Echo realtime, modular SPA registry. Due/overdue work uses
crm:send-due-notifications. Retention:notifications:prune. - Assignee scoping — reuse
ScopesToAssigneeso users without{slug}.assignonly see their own records.
Definition of Done
A module is complete only when:
- [ ] Backend implementation complete (models, migrations, services, controllers, requests, resources, policies, events, notifications)
- [ ] Frontend complete (pages, forms, tables, filters, dialogs/drawers, loading/empty/error states)
- [ ] Permissions enforced (Spatie + UI gates)
- [ ] Module licensing enforced (
module:middleware + SPA nav) - [ ] Tenant isolation verified
- [ ] Audit logging (
PlatformAuditService) implemented - [ ] Activity logging (Spatie
LogsActivity+ domain timeline where applicable) - [ ] Notifications implemented where applicable
- [ ] Pest tests pass (CRUD, authz, validation, tenant isolation, module gate)
- [ ] Playwright suite passes (
test:e2e:{slug}) - [ ] Manual browser QA passes
- [ ] Developer / User / Production guides updated in the same PR (Documentation Governance)
- [ ] API + database docs updated
- [ ] CHANGELOG updated
- [ ] No console errors; no failed network requests; build passes
- [ ] No platform refactor required before the next module