20 KiB
Construction Management ERP — Implementation Plan
Goal
Build a modular Construction Management ERP with 8 nWidart modules, using Laravel 12 + React/Inertia + shadcn-ui. This plan covers the full system from project scaffolding to final verification.
Project Type
WEB — Full-stack Laravel monolith with React SPA via Inertia.js
Tech Stack
| Layer | Technology | Rationale |
|---|---|---|
| Backend | Laravel 12 | Latest LTS, built-in auth scaffolding |
| Frontend | React 19 + Inertia.js | SPA feel without API layer |
| UI Components | shadcn-ui + Tailwind CSS | Accessible, customizable, modern |
| Modules | nWidart/laravel-modules v11+ | Domain-driven code separation |
| RBAC | spatie/laravel-permission | Industry standard for Laravel roles/permissions |
| State Machines | spatie/laravel-model-states | Formal state transitions with guards |
| File Storage | spatie/laravel-medialibrary | Morphable file management with conversions |
| Gantt | frappe-gantt (npm) | Lightweight, drag-and-drop Gantt chart |
| Database | MySQL 8+ | Laragon default, well-suited for ERP |
Architecture Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Module structure | Domain-driven sub-modules | Each module owns one business domain |
| State management | spatie/laravel-model-states | Guards prevent invalid transitions |
| Capitalization | Cached aggregates + events | Fast reads, event-driven updates |
| Material allocation | 1:1 per project | No cross-project material sharing |
| Retention tracking | Debit/credit ledger | Full auditability |
| Gantt dependencies | All 4 types (FS/FF/SS/SF) | Construction scheduling requires this |
| Contractor model | Separate entity (not a user) | Contractors don't log in |
| Equipment deployment | 1 equipment → 1 project | Strict tracking |
| Cert enforcement | Warning only | Don't block, just warn |
| Approval chain | Multi-step, morphable | Reusable across modules |
| Payment terms | Configurable per contractor | Net 15/30/60 per entity |
File Structure
gsb-cons/
├── app/ # Laravel base app (minimal, mostly in modules)
├── Modules/
│ ├── UserManagement/ # Phase 1
│ ├── ProjectManagement/ # Phase 2
│ ├── ApprovalWorkflow/ # Phase 3
│ ├── ContractorManagement/ # Phase 4
│ ├── MaterialLogistics/ # Phase 5
│ ├── FinancialManagement/ # Phase 6
│ ├── DocumentManagement/ # Phase 7
│ └── TimelineScheduling/ # Phase 8
├── resources/js/
│ ├── Components/ # Shared shadcn-ui components
│ ├── Layouts/ # App layout, sidebar, navigation
│ └── Lib/ # Shared utilities
├── docs/
│ └── PLAN-construction-erp.md
└── .agent/
Tasks
Phase 0: Project Foundation
-
T0.1 — Scaffold Laravel 12 with Breeze React+Inertia starter kit
composer create-project laravel/laravel .→composer require laravel/breeze --dev→php artisan breeze:install react --typescript- Verify:
php artisan serveshows login page
-
T0.2 — Install core packages (note: spatie/laravel-model-states incompatible with Laravel 13, replaced with custom HasStateMachine trait)
composer require nwidart/laravel-modules spatie/laravel-permission spatie/laravel-model-states spatie/laravel-medialibraryphp artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"- Verify:
php artisan module:listreturns empty list, Spatie migration exists
-
T0.3 — Install shadcn-ui + configure Tailwind
npx shadcn@latest init→ configurecomponents.json- Add base components: Button, Input, Card, Table, Dialog, Select, Tabs, Badge, Toast
- Verify: Import a shadcn Button in
Welcome.tsx, renders correctly
-
T0.4 — Create shared app layout (sidebar + header) (deferred to Phase 1)
- Layout with sidebar navigation, breadcrumbs, user dropdown
- Mobile-responsive hamburger menu
- Verify: Layout renders on
/dashboardroute
-
T0.5 — Configure module autoloading + Vite aliases
- Update
vite.config.tsto resolve@/Modules/*paths - Update
tsconfig.jsonpath aliases - Verify: Can import from
@/Modules/UserManagement/...in React
- Update
Phase 1: UserManagement Module
Agent: backend-specialist + frontend-specialist
Skills: database-design, clean-code, frontend-design
-
T1.1 — Generate module + create migrations
php artisan module:make UserManagement- Tables:
employee_profiles,customer_profiles - Add
user_typeenum +userable_type/userable_idtouserstable - Verify:
php artisan migratesucceeds
-
T1.2 — Create models with polymorphic relationships
User(adduserable()morphTo),EmployeeProfile,CustomerProfile- Spatie HasRoles trait on User model
- Verify:
User::factory()->create()works with profile
-
T1.3 — Seed roles and permissions
- Roles:
admin,employee,customer - Permissions:
manage-users,view-users,create-users,edit-users,delete-users - Admin seeder creates default admin user
- Verify:
php artisan db:seedcreates admin with correct role
- Roles:
-
T1.4 — Create UserController + UserPolicy
- CRUD endpoints:
index,create,store,show,edit,update,destroy - Policy: admin-only for create/edit/delete, employee can view
- Middleware:
role:adminon write routes - Verify: Unauthorized user gets 403 on POST
/users
- CRUD endpoints:
-
T1.5 — Build React pages (Index, Create, Edit, Show)
Index.tsx— DataTable with search, type filter (Employee/Admin/Customer), status badgesCreate.tsx— Form with shadcn components, dynamic profile fields per user typeEdit.tsx— Pre-filled form with profile sectionShow.tsx— User detail with tabs (Profile, Activity, Permissions)- Verify: Full CRUD flow works in browser
-
T1.6 — Add user status management
- Statuses:
active,inactive,suspended - Toggle action on user list
- Suspended users cannot login (middleware check)
- Verify: Suspending user prevents their login
- Statuses:
Phase 2: ProjectManagement Module
Agent: backend-specialist + frontend-specialist
Skills: database-design, clean-code, frontend-design
-
T2.1 — Generate module + create migrations
php artisan module:make ProjectManagement- Tables:
projects,tasks,project_user(pivot) - Project has cached
total_capitalizationcolumn - Verify:
php artisan migratesucceeds
-
T2.2 — Create models with state machines
Project— states:UnderBidding,Planning,InProgress,OnHold,Completed,ClosedTask— states:Pending,InProgress,Completed,BlockedProjectUserpivot withrolecolumn (pm/engineer/laborer)- Transition guards: can't move to
InProgresswithout assigned PM - Verify: Invalid transition throws
TransitionNotAllowed
-
T2.3 — Create controllers + policies
ProjectController(CRUD + status transitions)TaskController(CRUD + completion tracking)ProjectPersonnelController(assign/remove users to project)- Policy: PM can manage their projects, Admin can manage all
- Verify: Engineer cannot change project status
-
T2.4 — Create events
ProjectCreated,ProjectStatusChanged,TaskCreated,TaskCompleted- Events dispatched from model observers
- Verify: Event listeners fire (check via
Log::info)
-
T2.5 — Build React pages
Projects/Index.tsx— Project cards/table with status filter, budget displayProjects/Create.tsx— Project form with customer selection, location, datesProjects/Show.tsx— Dashboard with tabs: Overview, Tasks, Personnel, BudgetTasks/Index.tsx— Task list per project with drag status updateTasks/Create.tsx— Task form with labor cost, dates, assignment- Verify: Create project → add tasks → assign personnel → status transition works
Phase 3: ApprovalWorkflow Module
Agent: backend-specialist
Skills: database-design, clean-code
-
T3.1 — Generate module + create migrations
php artisan module:make ApprovalWorkflow- Tables:
approval_chains,approval_steps - Both tables use morphable relationships (
approvable_type/approvable_id) - Verify:
php artisan migratesucceeds
-
T3.2 — Create models + approval service
ApprovalChain(morphTo approvable),ApprovalStep(belongsTo chain)ApprovalService:createChain(),approve(),reject(),getNextApprover()- State machine on chain:
pending→in_review→approved/rejected - Verify: Unit test — create chain with 3 steps, approve step by step
-
T3.3 — Create events + notification triggers
ApprovalRequired,StepApproved,StepRejected,ApprovalCompleted- Notify next approver when previous step is approved
- Verify: Approving step 1 notifies step 2 approver
-
T3.4 — Build approval UI components (reusable)
ApprovalTimeline.tsx— Shows chain progress (who approved, when, status)ApprovalActionButtons.tsx— Approve/Reject with notes modalPendingApprovals.tsx— Dashboard widget for logged-in user's pending items- Verify: Render approval timeline for a test chain
Phase 4: ContractorManagement Module
Agent: backend-specialist + frontend-specialist
Skills: database-design, clean-code, frontend-design
-
T4.1 — Generate module + create migrations
php artisan module:make ContractorManagement- Tables:
contractors,contractor_equipment,contractor_certifications,contractor_invoices,contractor_payments,equipment_deployments - Add
project_contractorpivot to ProjectManagement migration - Verify:
php artisan migratesucceeds
-
T4.2 — Create models with relationships
Contractor(hasMany equipment, certs, invoices)ContractorEquipment(states: available/deployed/maintenance)ContractorCertification(computedis_expiring_soonattribute)ContractorInvoice(state machine: Draft → Submitted → Approved → Paid)ContractorPaymentEquipmentDeployment(track on-site)payment_termsfield oncontractorstable (net_15/net_30/net_60)- Verify: Create contractor with equipment + certification via factory
-
T4.3 — Create controllers + integrate approvals
ContractorController(CRUD + project tagging)EquipmentController(CRUD + deployment tracking)CertificationController(CRUD + expiry warnings)ContractorBillingController(invoice submission → triggers ApprovalWorkflow)- Verify: Submit invoice → approval chain created → approve → paid
-
T4.4 — Create events + listeners
ContractorAssignedToProject,ContractorInvoiceSubmitted,ContractorInvoicePaidCertificationExpiring(scheduled check for certs expiring within 30 days)- Listener on
ContractorInvoicePaid→ update project capitalization - Verify: Paying contractor invoice increments project
total_capitalization
-
T4.5 — Build React pages
Contractors/Index.tsx— Directory with search, specialization filter, ratingContractors/Show.tsx— Tabs: Profile, Equipment, Certifications, Invoices, ProjectsContractors/Create.tsx— Form with payment terms selectionEquipment/Index.tsx— Equipment registry with deployment statusBilling/Index.tsx— Invoice list with status badges + payment form- Certification expiry warning badge on contractor cards
- Verify: Full contractor lifecycle works in browser
Phase 5: MaterialLogistics Module
Agent: backend-specialist + frontend-specialist
Skills: database-design, clean-code, frontend-design
-
T5.1 — Generate module + create migrations
php artisan module:make MaterialLogistics- Tables:
materials,project_inventories,material_requirements,material_deployments - Verify:
php artisan migratesucceeds
-
T5.2 — Create models with state machines
Material(master catalog),ProjectInventory(per-project stock)MaterialRequirement(booked to task, withunit_cost_at_booking)MaterialDeployment— states:Requested→PendingDispatch→InTransit→Delivered→Consumed(+Cancelled)- Guard: can't dispatch if
project_inventory.on_hand_qty < deployment.quantity - Verify: Invalid dispatch throws
TransitionNotAllowed
-
T5.3 — Create services + controllers
InventoryService: allocate, consume, return materialsDeploymentService: request, dispatch, receive, consumeMaterialRequested→ triggers ApprovalWorkflow- On
Deliveredstatus → update project capitalization via event - Verify: Full deployment flow from request to consumed
-
T5.4 — Create event listeners
- Listen for
TaskCreated→ auto-create material requirements placeholder - Fire
MaterialDelivered→ FinancialManagement updates capitalization - Verify: Creating a task in ProjectManagement triggers requirement creation in MaterialLogistics
- Listen for
-
T5.5 — Build React pages
Materials/Index.tsx— Material catalog with categories, searchInventory/Index.tsx— Per-project inventory view with quantitiesDeployments/Index.tsx— Deployment tracker with status pipeline visualizationRequirements/Index.tsx— Per-task material requirements with booking form- Verify: Request material → approve → dispatch → receive → consumed flow in UI
Phase 6: FinancialManagement Module
Agent: backend-specialist + frontend-specialist
Skills: database-design, clean-code, frontend-design
-
T6.1 — Generate module + create migrations
php artisan module:make FinancialManagement- Tables:
invoices,invoice_line_items,retention_ledger - Verify:
php artisan migratesucceeds
-
T6.2 — Create models with state machines + retention logic
Invoice— states:Draft→Submitted→Approved→Sent→PartiallyPaid→Paid(+Rejected,Overdue)InvoiceLineItem(description, qty, unit_price, total)RetentionLedger(debit/credit entries per project per invoice)- On invoice approval → auto-create retention debit entry (configurable %)
- On project completion → credit all retention back
- Verify: Creating invoice generates correct retention debit, project completion credits it
-
T6.3 — Create capitalization service
CapitalizationService: recalculate project total from materials + labor + contractor costs- Event listener:
MaterialDelivered,ContractorInvoicePaid,TaskLaborUpdated - Uses
$project->increment()for atomic updates - Verify: Delivering material updates
total_capitalizationcolumn
-
T6.4 — Create progress billing service
ProgressBillingService: generate invoice from project % completion- Formula:
invoice_amount = project_contract_value × (current_% - last_billed_%) - Retention auto-deducted from invoice amount
- Invoice submission → triggers ApprovalWorkflow
- Verify: 25% completion generates correct invoice with retention held
-
T6.5 — Build React pages
Invoices/Index.tsx— Invoice list with status filter, overdue highlightingInvoices/Create.tsx— Progress-based invoice generatorInvoices/Show.tsx— Invoice detail with line items, payment history, approval statusRetention/Index.tsx— Retention ledger per project (debits/credits)Dashboard.tsx— Financial summary: total billings, outstanding, capitalization- Verify: Generate progress invoice → approve → mark partially paid → paid
Phase 7: DocumentManagement Module
Agent: backend-specialist + frontend-specialist
Skills: database-design, clean-code, frontend-design
-
T7.1 — Generate module + create migrations
php artisan module:make DocumentManagement- Tables:
documents,document_versions - Configure Spatie Media Library for S3/local storage
- Verify:
php artisan migratesucceeds
-
T7.2 — Create models with morphable + versioning
Document— morphable (documentable_type: Project, Task, Contractor, Invoice)DocumentVersion— version_number auto-incremented, old versions archived- Categories:
blueprint,site_photo,permit,subcontract,insurance,receipt - Verify: Attach document to Project, update it, verify old version is archived
-
T7.3 — Create controllers + upload handling
DocumentController(CRUD, upload, download, version history)- File validation: PDF, JPEG, PNG, DOCX — max 50MB
- Thumbnail generation for images via Media Library
- Verify: Upload blueprint PDF → download → upload new version → both accessible
-
T7.4 — Build React pages
Documents/Index.tsx— Document gallery with category tabs, searchDocuments/Upload.tsx— Drag-and-drop upload with category selectionDocuments/VersionHistory.tsx— Version timeline with download links- Reusable
DocumentAttachment.tsxcomponent for embedding in Project/Task/Contractor pages - Verify: Upload document to task → view in task detail → view version history
Phase 8: TimelineScheduling Module
Agent: frontend-specialist + backend-specialist
Skills: frontend-design, clean-code
-
T8.1 — Generate module + create migrations
php artisan module:make TimelineScheduling- Tables:
task_dependencies,milestones task_dependencies:dependency_typeenum (FS, FF, SS, SF) +lag_days- Verify:
php artisan migratesucceeds
-
T8.2 — Create models + critical path service
TaskDependency(task_id, predecessor_id, type, lag_days)Milestone(project_id, name, target_date, achieved_date, is_critical)CriticalPathCalculatorservice: forward/backward pass algorithm- Guard: can't start task if FS predecessor is not complete
- Verify: Define 5 tasks with dependencies → calculator identifies critical path
-
T8.3 — Create Gantt data transformer
GanttDataTransformer: convert tasks + dependencies into Frappe Gantt JSON format- API endpoint:
GET /projects/{id}/ganttreturns Gantt-ready data PATCH /projects/{id}/tasks/{taskId}/schedulefor drag-and-drop updates- Verify: API returns correctly formatted Gantt JSON
-
T8.4 — Build Gantt React component
- Install
frappe-ganttnpm package GanttChart.tsxwrapper: renders tasks, dependencies, milestones- Drag-and-drop bar → AJAX PATCH to update dates in backend
- Critical path highlighting (red bars for critical tasks)
- Zoom controls: Day / Week / Month views
MilestonePanel.tsx— Milestone list with progress indicators- Verify: Drag task bar → dates update in DB → refresh shows new dates
- Install
-
T8.5 — Listen to task events
- On
TaskCompleted→ check if milestone is achieved - On
TaskCompleted→ auto-start successor tasks (if all predecessors done) - Verify: Completing predecessor task auto-advances successor
- On
Done When
- All 8 modules generated and migrations pass
- All state machines enforce valid transitions
- Event communication between modules works (cross-module listeners fire)
- Capitalization updates automatically on material delivery + contractor payment
- Approval workflow works for material requests + invoices
- Gantt chart renders with drag-and-drop scheduling
- Full CRUD for all entities works via React UI
- Admin can manage all users (Employee/Admin/Customer)
php artisan migrate:fresh --seedproduces working seeded data
Phase X: Final Verification
npm run build— no TypeScript errorsphp artisan test— all feature tests passpython .agent/skills/vulnerability-scanner/scripts/security_scan.py .— no critical security issuespython .agent/skills/frontend-design/scripts/ux_audit.py .— UX audit passes- Manual smoke test: full project lifecycle (create project → add tasks → deploy materials → generate invoice → complete project)