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. When updating an existing module, bump catalogmodules.versionviaDefaultModuleRegistrar::bumpVersionusing PATCH / MINOR / MAJOR semver (no breaking changes; platform-wide code + catalog label; entitlement unchanged). See Developer Guide — catalog versioning. - 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.
- One workspace timezone — all current and future modules use Settings → General → Timezone for wall clocks, “today”, due dates, schedules, digests, and office hours. Store absolute datetimes as UTC (
UtcDateTime/UtcIso); display/edit via SPAdatetime.ts. No per-module timezone. See Workspace timezone convention.
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. - Realtime rooms — Team Chat adds a private Reverb conversation channel
tenant.{tid}.conversation.{id}(membership-gated) beside the existingtenant.{tid}.user.{uid}notification channel. See Module Development Guide — in-app notifications. - 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 (list + dedicated create/view/edit pages; hybrid list
EntityRecordSheet/ModuleRecordSheetfor quick create/peek withrenderOverviewfield summary — billing docs view-peek only; forms, tables, filters, loading/empty/error states; dialogs only for secondary flows) - [ ] Module list
PageHeaderwirestourIdwith steps undersrc/tours/{slug}.ts(Module Tours) - [ ] 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
- [ ] Date/time behavior follows the Workspace timezone convention (workspace TZ wall clocks; UTC storage for absolute instants; no module-scoped timezone)
- [ ] Pest tests pass (CRUD, authz, validation, tenant isolation, module gate) — include non-UTC timezone coverage when the module schedules or gates by clock
- [ ] Playwright suite passes (
test:e2e:{slug}) - [ ] Manual browser QA passes
- [ ] Developer / User / Production guides updated in the same PR (Documentation Governance) — state that times use Settings → General → Timezone
- [ ] API + database docs updated
- [ ] CHANGELOG updated
- [ ] No console errors; no failed network requests; build passes
- [ ] No platform refactor required before the next module