+ {pkg.status === 'draft'
+ ? 'Review the package, then publish it to invite contractors.'
+ : pkg.status === 'open'
+ ? 'The package is accepting submissions.'
+ : `This package is ${statusLabel(pkg.status).toLowerCase()}.`}
+
- {can('edit', 'tasks') && (
+ {canManageTaskStatus && (
<>
{detailsTask.status === 'pending' && (
<>
@@ -502,6 +484,11 @@ export default function Tasks({ project, employees, availableMaterials, delayRea
>
)}
+ {detailsTask.status === 'closed' && (
+
+ This task is closed and cannot be moved.
+
+ )}
diff --git a/Modules/UserManagement/routes/web.php b/Modules/UserManagement/routes/web.php
index 7430377..9c41e98 100644
--- a/Modules/UserManagement/routes/web.php
+++ b/Modules/UserManagement/routes/web.php
@@ -3,7 +3,9 @@
use Illuminate\Support\Facades\Route;
use Modules\UserManagement\Http\Controllers\UserController;
-Route::middleware(['auth', 'verified', 'permission:users.access'])->group(function () {
+// Platform users may use the module-level permission, while contractor
+// administrators use the domain permission assigned to their role.
+Route::middleware(['auth', 'verified', 'permission:users.access|manage users'])->group(function () {
Route::resource('users', UserController::class);
Route::patch('users/{user}/toggle-status', [UserController::class, 'toggleStatus'])->name('users.toggle-status');
Route::patch('users/{user}/link-contractor', [UserController::class, 'linkContractor'])->name('users.link-contractor');
diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index d6f4534..024de08 100644
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -6,10 +6,10 @@ use Inertia\Inertia;
use Illuminate\Http\Request;
use Modules\ProjectManagement\Models\Project;
use Modules\ProjectManagement\Models\Task;
+use Modules\DailyReports\Models\DailyReportLabor;
use Modules\ProjectManagement\Models\TaskActivity;
use Modules\ProjectManagement\Models\TaskDelay;
use Modules\DailyReports\Models\DailyReport;
-use Modules\DailyReports\Models\DailyReportLabor;
use Modules\DailyReports\Models\DailyReportEquipment;
use Modules\DailyReports\Models\DailyReportIssue;
use App\Services\WeatherService;
@@ -274,7 +274,7 @@ class DashboardController extends Controller
}
/**
- * Compile resource logs (Labor & Equipment) from latest Daily Reports.
+ * Compile deployed labor and current equipment from active project data.
*/
private function getResourcesData(?Project $project): array
{
@@ -286,31 +286,35 @@ class DashboardController extends Controller
$equipmentIdle = 0;
$equipmentList = [];
- // Resolve which projects we care about
- $projectIds = $project ? [$project->id] : Project::pluck('id')->toArray();
+ // Global resource roll-ups should represent active execution only.
+ // A selected project intentionally narrows the dashboard to that project.
+ $projectIds = $project
+ ? [$project->id]
+ : Project::whereIn('status', ['active', 'planning', 'in_progress'])
+ ->pluck('id')
+ ->toArray();
- // Fetch latest reports for the selected project or across all active projects
- $latestReports = DailyReport::whereIn('project_id', $projectIds)
- ->whereIn('id', function ($query) use ($projectIds) {
- $query->selectRaw('MAX(id)')
- ->from('daily_reports')
- ->whereIn('project_id', $projectIds)
- ->groupBy('project_id');
- })
+ // Labor totals come from every Daily Report labor entry for the active
+ // project set. This intentionally includes all stored report records.
+ $laborLogs = DailyReportLabor::whereHas('dailyReport', function ($query) use ($projectIds) {
+ $query->whereIn('project_id', $projectIds);
+ })->get();
+
+ foreach ($laborLogs as $log) {
+ $laborActual += (int) $log->workers_count;
+ $tradeName = $log->trade ?? 'General Labor';
+ $trades[$tradeName] = ($trades[$tradeName] ?? 0) + (int) $log->workers_count;
+ }
+
+ // Read equipment entries from every daily report in the project set.
+ // ResourceSummary must represent all stored daily-report records, not
+ // only the latest report for each project.
+ $reports = DailyReport::whereIn('project_id', $projectIds)
+ ->with('equipment')
->get();
- foreach ($latestReports as $report) {
- // Compile Labor
- $laborLogs = DailyReportLabor::where('daily_report_id', $report->id)->get();
- foreach ($laborLogs as $log) {
- $laborActual += (int) $log->workers_count;
- $tradeName = $log->trade ?? 'General Labor';
- $trades[$tradeName] = ($trades[$tradeName] ?? 0) + (int) $log->workers_count;
- }
-
- // Compile Equipment
- $equipLogs = DailyReportEquipment::where('daily_report_id', $report->id)->get();
- foreach ($equipLogs as $log) {
+ foreach ($reports as $report) {
+ foreach ($report->equipment as $log) {
$status = strtolower($log->status ?? 'active');
if (str_contains($status, 'active') || str_contains($status, 'use') || str_contains($status, 'operat')) {
$equipmentActive++;
@@ -330,9 +334,8 @@ class DashboardController extends Controller
}
}
- // Expected labor calculation: calculate expected labor from project allocation if present, otherwise dynamically from actual logs
if ($laborActual > 0) {
- $laborExpected = max($laborActual, (int)ceil($laborActual * 1.15));
+ $laborExpected = max($laborActual, (int) ceil($laborActual * 1.15));
}
return [
@@ -345,7 +348,7 @@ class DashboardController extends Controller
'active' => $equipmentActive,
'maintenance' => $equipmentMaintenance,
'idle' => $equipmentIdle,
- 'list' => array_slice($equipmentList, 0, 5) // Cap list at 5
+ 'list' => $equipmentList
]
];
}
@@ -374,8 +377,14 @@ class DashboardController extends Controller
$totalRetention = (float) $invoicesQuery->sum('retention_amount');
$pendingApprovalsCount = \Modules\ApprovalWorkflow\Models\ApprovalChain::where('status', 'in_review')->count();
- $totalProjectsCount = Project::count();
- $activeProjectsCount = Project::where('status', 'active')->count();
+ $projectsAnalyticsQuery = Project::query();
+ if ($project) {
+ $projectsAnalyticsQuery->whereKey($project->id);
+ }
+ $totalProjectsCount = (clone $projectsAnalyticsQuery)->count();
+ $activeProjectsCount = (clone $projectsAnalyticsQuery)
+ ->whereIn('status', ['planning', 'in_progress'])
+ ->count();
// 2. PM Milestone & Progress Analytics
$milestonesQuery = \Modules\TimelineScheduling\Models\Milestone::query();
@@ -402,6 +411,7 @@ class DashboardController extends Controller
return [
'role' => $roleName,
+ 'roles' => $user?->getRoleNames()->values()->all() ?? [],
'user_type' => $userType,
'financials' => [
'total_billed' => $totalBilled,
diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php
index e7b7b0b..e5924d5 100644
--- a/app/Http/Middleware/HandleInertiaRequests.php
+++ b/app/Http/Middleware/HandleInertiaRequests.php
@@ -8,6 +8,7 @@ use Modules\ApprovalWorkflow\Models\ApprovalChain;
use Modules\ContractorManagement\Models\Contractor;
use Modules\MaterialLogistics\Models\MaterialRequisition;
use Modules\MaterialLogistics\Models\PurchaseOrder;
+use Modules\ProjectManagement\Models\Project;
class HandleInertiaRequests extends Middleware
{
@@ -44,12 +45,46 @@ class HandleInertiaRequests extends Middleware
'success' => $request->session()->get('success'),
'error' => $request->session()->get('error'),
],
- 'sidebarBadges' => fn () => $request->user() ? [
- 'pending_requisitions' => MaterialRequisition::where('status', 'draft')->count(),
- 'pending_purchase_orders' => PurchaseOrder::where('status', 'draft')->count(),
- 'pending_approvals' => ApprovalChain::where('status', 'pending')->count(),
- ] : null,
+ 'sidebarBadges' => fn () => $request->user() ? (function () use ($request) {
+ $user = $request->user();
+
+ // Drafts belong to their creator. Submitted requests are
+ // relevant only when the current user is an assigned approver.
+ $ownDraftRequisitions = MaterialRequisition::where('status', 'draft')
+ ->where('requested_by', $user->id)
+ ->count();
+
+ $assignedRequisitionApprovals = ApprovalChain::where('status', 'pending')
+ ->where('type', 'material_requisition')
+ ->whereHas('steps', function ($query) use ($user) {
+ $query->where('approver_id', $user->id)
+ ->where('status', 'pending');
+ })
+ ->count();
+
+ $ownDraftPurchaseOrders = PurchaseOrder::where('status', 'draft')
+ ->where('requested_by', $user->id)
+ ->count();
+
+ $assignedApprovals = ApprovalChain::where('status', 'pending')
+ ->whereHas('steps', function ($query) use ($user) {
+ $query->where('approver_id', $user->id)
+ ->where('status', 'pending');
+ })
+ ->count();
+
+ return [
+ 'pending_requisitions' => $ownDraftRequisitions + $assignedRequisitionApprovals,
+ 'pending_purchase_orders' => $ownDraftPurchaseOrders,
+ 'pending_approvals' => $assignedApprovals,
+ ];
+ })() : null,
+ 'projectOptions' => fn () => $request->user()
+ ? Project::where('current_wizard_step', '>=', 7)
+ ->whereHas('bidPackages')
+ ->with('parentProject:id,ulid,name,code')
+ ->get(['id', 'ulid', 'name', 'code', 'project_type', 'parent_project_id', 'status'])
+ : [],
];
}
}
-
diff --git a/app/Scopes/TenantScope.php b/app/Scopes/TenantScope.php
index 085dd6a..ad4bff8 100644
--- a/app/Scopes/TenantScope.php
+++ b/app/Scopes/TenantScope.php
@@ -37,6 +37,35 @@ class TenantScope implements Scope
return;
}
+ if ($model instanceof \Modules\ProjectManagement\Models\Project && $this->isSiteOperationsUser($user)) {
+ if ($user->contractor_id) {
+ $allowedIds = $this->resolveAllowedContractorIds($user->contractor_id);
+
+ $builder->where(function ($query) use ($user, $allowedIds, $model) {
+ $query->whereIn($model->getTable() . '.contractor_id', $allowedIds)
+ ->orWhereHas('contractors', function ($contractorQuery) use ($allowedIds) {
+ $contractorQuery->whereIn('contractors.id', $allowedIds);
+ })
+ ->orWhereHas('personnel', function ($personnelQuery) use ($user) {
+ $personnelQuery->where('users.id', $user->id);
+ });
+ });
+ } else {
+ $builder->whereHas('personnel', function ($query) use ($user) {
+ $query->where('users.id', $user->id);
+ });
+ }
+
+ return;
+ }
+
+ // Platform roles always have global visibility. Some existing
+ // Super Admin/admin accounts were created with a contractor_id;
+ // the role must take precedence over that stale tenant link.
+ if ($this->isPlatformUser($user)) {
+ return;
+ }
+
// Platform owners/admins have no contractor_id — full access
if (is_null($user->contractor_id)) {
return;
@@ -59,7 +88,16 @@ class TenantScope implements Scope
$builder->whereIn($model->getTable() . '.contractor_id', $allowedIds);
}
} else {
- $builder->whereIn($model->getTable() . '.contractor_id', $allowedIds);
+ if ($model instanceof \Modules\ProjectManagement\Models\Project) {
+ $builder->where(function ($query) use ($model, $allowedIds) {
+ $query->whereIn($model->getTable() . '.contractor_id', $allowedIds)
+ ->orWhereHas('contractors', function ($contractorQuery) use ($allowedIds) {
+ $contractorQuery->whereIn('contractors.id', $allowedIds);
+ });
+ });
+ } else {
+ $builder->whereIn($model->getTable() . '.contractor_id', $allowedIds);
+ }
}
} finally {
self::$resolvingAuth = false;
@@ -83,4 +121,20 @@ class TenantScope implements Scope
return array_merge([$contractorId], $childIds);
}
+
+ private function isSiteOperationsUser($user): bool
+ {
+ return $user->hasAnyRole([
+ 'Site Technical',
+ 'Construction Supervisor',
+ 'Site Operations',
+ 'Site Engineer',
+ 'Site Supervisor',
+ ]);
+ }
+
+ private function isPlatformUser($user): bool
+ {
+ return $user->hasAnyRole(['Super Admin', 'admin']);
+ }
}
diff --git a/contractor-onboarding-fix.md b/contractor-onboarding-fix.md
new file mode 100644
index 0000000..291b275
--- /dev/null
+++ b/contractor-onboarding-fix.md
@@ -0,0 +1,54 @@
+# Contractor Onboarding Registration Fix Plan
+
+## Goal
+
+Make guest contractor registration succeed on a fresh database, preserve the intended `Main Contractor Admin` role, and prevent regressions in contractor onboarding.
+
+## Confirmed Failure
+
+`tests/Feature/ContractorOnboardingTest.php::test_guest_can_register_as_contractor` currently receives HTTP 500 because `ContractorOnboardingController::register()` calls:
+
+```php
+$role->givePermissionTo('users.access');
+```
+
+before the `users.access` permission exists.
+
+The same test also expects the legacy `Contractor` role, while the current controller intentionally assigns `Main Contractor Admin`.
+
+## Tasks
+
+- [ ] Establish the permission contract: ensure `users.access` is available before onboarding role assignment. Prefer a centralized role/permission provisioning path; if registration must work independently of seed execution, make the onboarding service safely create or resolve the permission before assigning it.
+ - Verify: registration on a fresh test database no longer throws `PermissionDoesNotExist`.
+
+- [ ] Align the onboarding role contract with the current role policy.
+ - Expected role: `Main Contractor Admin` for a self-registered main contractor.
+ - Verify: the created inactive user has `Main Contractor Admin`, `users.access`, the correct `contractor_id`, and no unintended legacy role.
+
+- [ ] Update the contractor onboarding test fixture so it explicitly provisions the permission/role prerequisites instead of relying on unrelated seeders.
+ - Verify: the test is isolated and passes with `RefreshDatabase`.
+
+- [ ] Add regression coverage for a clean-database registration where no permissions have been pre-created.
+ - Verify: the transaction creates the pending contractor and inactive admin, or rolls back cleanly with a controlled error; it never returns HTTP 500 from a missing permission.
+
+- [ ] Re-run the complete onboarding test file.
+ - Verify: all contractor onboarding tests pass, including inactive-login blocking, platform approval, rejection, and non-platform access denial.
+
+- [ ] Re-run the feature suite and then the whole test suite.
+ - Verify: no new failures; record remaining failures separately rather than changing unrelated workflows.
+
+- [ ] Run frontend and backend validation after implementation.
+ - Commands: `php -l` on changed PHP files, `npx tsc --noEmit`, `npm run build`, and `php artisan test`.
+
+## Done When
+
+- Contractor registration returns the login redirect and success message.
+- Contractor and inactive admin records are committed together.
+- The new admin is assigned `Main Contractor Admin` and `users.access`.
+- Failed provisioning rolls back the transaction.
+- Onboarding tests pass on a clean database.
+- The full-suite result is recorded with no unclassified failures.
+
+## Scope Guard
+
+Do not change dashboard role routing, tenant visibility, bidding rules, approval rules, or unrelated UI while fixing this defect. Those are separate workflows and should be addressed only if a regression test identifies them.
diff --git a/docs/SYSTEM_WORKFLOW_TEST_CASES.md b/docs/SYSTEM_WORKFLOW_TEST_CASES.md
new file mode 100644
index 0000000..24e9789
--- /dev/null
+++ b/docs/SYSTEM_WORKFLOW_TEST_CASES.md
@@ -0,0 +1,308 @@
+# GSB Construction ERP — End-to-End System Workflow Test Cases
+
+## 1. Purpose
+
+This document defines the complete business-workflow test plan for the GSB Construction ERP. It covers authentication, contractor tenancy, roles, projects, bidding, project execution, materials, finance, approvals, dashboards, and cross-role visibility.
+
+This is a test specification. Discovered defects must be recorded in the defect log and must not be fixed during the test run.
+
+## 2. Test Rules
+
+- Use a disposable or staging database only.
+- Use the same test records across a workflow so each state transition can be verified.
+- Follow Arrange → Act → Assert for every case.
+- Record the user, role, contractor, project, route, request payload, response, database state, and screenshot for failures.
+- A workflow passes only when the UI result, server response, authorization rule, and database state agree.
+- Do not mark a case passed because a page loads; verify the action and resulting data.
+
+## 3. Test Environment
+
+| Item | Requirement |
+|---|---|
+| Backend | Laravel application with migrations loaded |
+| Frontend | Vite development build or compiled production assets |
+| Database | Disposable database with seed data plus test fixtures |
+| Browser | Chromium/Chrome, desktop width, responsive width |
+| Browser checks | Console free of uncaught exceptions; network requests return expected status |
+| Build checks | `npx tsc --noEmit`, `npm run build`, `php artisan test` |
+| Date/time | Confirm expected timezone and date formatting before testing reports and deadlines |
+
+## 4. Required Test Accounts and Data
+
+Create these accounts before execution. Replace the placeholder emails with unique test emails.
+
+| ID | Account | Role | Contractor |
+|---|---|---|---|
+| U-01 | Platform owner | Super Admin | None |
+| U-02 | Platform administrator | admin | None |
+| U-03 | Project manager | Project Manager | None |
+| U-04 | Main contractor administrator | Main Contractor Admin | C-01 |
+| U-05 | Main contractor user | Main Contractor User | C-01 |
+| U-06 | Site technical user | Site Technical | C-01 |
+| U-07 | Construction supervisor | Construction Supervisor | C-01 |
+| U-08 | Site operations user | Site Operations | C-01 |
+| U-09 | Subcontractor administrator | Sub Contractor Admin | C-02, child of C-01 |
+| U-10 | Unrelated contractor user | Contractor User | C-03 |
+
+Create at least:
+
+| ID | Fixture | Required state |
+|---|---|---|
+| C-01 | Great SwissMetal Builders Corporation | Active main contractor |
+| C-02 | C-01 subcontractor | Active child contractor |
+| C-03 | Unrelated contractor | Active separate tenant |
+| P-01 | Main construction project | Draft, then initialized at wizard step 7 |
+| P-02 | C-01 active project | `planning` or `in_progress` |
+| P-03 | C-03 project | Must never appear to C-01 users |
+| M-01 | Material catalog item | Active, with unit and cost |
+| L-01 | Labor record | Active labor/trade |
+| E-01 | Equipment record | Active equipment |
+
+## 5. Role and Tenant Access Matrix
+
+Run the matrix against every protected module. “Own tenant” means the user’s contractor and permitted contractor hierarchy. “Related project” means a project directly owned by, linked to, or assigned to that contractor according to the application rule.
+
+| Area | Super Admin/admin | Project Manager | Contractor Admin | Site Technical/Supervisor/Operations | Unrelated contractor |
+|---|---:|---:|---:|---:|---:|
+| Dashboard | Global | Assigned/allowed scope | Contractor dashboard | Related project scope | Own scope only |
+| Users | Global administration | According to permission | Own contractor users | No administration unless explicitly granted | Own contractor only |
+| Projects | Global | Project scope | Own contractor scope | Related project scope | Own contractor scope |
+| Bid package management | Yes | Yes | According to configured role rule | No | No |
+| Bid submissions | Yes | Yes | Yes for invited contractor | No | Only invited packages |
+| Material requisitions | Global | Create/approve as assigned | Own contractor/project | Create on related project | Own scope |
+| Purchase orders | Global | Create/approve as assigned | Own contractor/project | Operate related project | Own scope |
+| Cash advances | Global approver | Approve other users’ requests | Own contractor rules | Create, not self-approve | Own scope |
+| Invoice/retention approvals | Global | As configured | As configured | No approval unless configured | Own scope |
+| Documents/daily reports/tasks | Global | Assigned/managed projects | Own contractor projects | Related projects only | Own scope |
+
+Any deviation must be logged as a defect, including both unexpected access and missing access.
+
+## 6. End-to-End Workflow Cases
+
+### WF-01 — Authentication and account lifecycle
+
+| Field | Test |
+|---|---|
+| Preconditions | U-01 through U-10 exist; active and inactive accounts are available |
+| Steps | Log in with valid credentials; log out; attempt invalid password; attempt inactive account; reset password; complete forced password change |
+| Expected | Valid users reach the correct dashboard; invalid users receive a safe error; inactive users are blocked; password reset and forced password change complete successfully |
+| Security | No password or sensitive token appears in the UI, URL, response, or logs |
+
+### WF-02 — Contractor onboarding and tenant assignment
+
+| Field | Test |
+|---|---|
+| Actor | U-01 or U-02 |
+| Steps | Create C-01 with administrator; verify administrator is linked to C-01; create C-02 as child contractor; create U-05/U-06/U-07 under C-01; create U-09 under C-02 |
+| Expected | Contractor records, user records, roles, profile records, and contractor IDs are consistent; users created by a contractor admin inherit that contractor |
+| Negative | Attempt to assign a contractor user to C-03 from a C-01 admin account; request is rejected and no cross-tenant change is saved |
+
+### WF-03 — User management and role enforcement
+
+| Field | Test |
+|---|---|
+| Actor | U-01, U-04, U-09 |
+| Steps | List users; create user; edit user; assign each supported role; deactivate user; attempt to view/edit a user from another contractor |
+| Expected | Platform users see global users; contractor admins see only their permitted contractor tree; role names and permissions persist; deactivated users cannot log in |
+| Negative | Site technical and supervisor accounts cannot access user-management actions unless explicitly permitted |
+
+### WF-04 — Project creation and initialization wizard
+
+| Field | Test |
+|---|---|
+| Actor | U-02, U-03, U-04 |
+| Steps | Create P-01; enter project information; add milestones; add tasks; add materials; add labor; add equipment; review financial submission; submit final initialization |
+| Expected | Each step saves; back/next navigation preserves data; validation rejects incomplete required data; step number advances correctly; initialized project is visible to permitted users |
+| Database assertions | `projects.current_wizard_step`, project status, contractor ID, milestones, tasks, estimates, labor, equipment, and personnel links are correct |
+| Negative | A draft project is not treated as an initialized execution project; an unrelated contractor cannot open P-01 |
+
+### WF-05 — Project visibility and cross-role reflection
+
+| Field | Test |
+|---|---|
+| Actor | U-04 creates/updates; U-05/U-06/U-07/U-08 verify |
+| Steps | U-04 initializes or updates P-01; sign in as every C-01 role; inspect Projects, project details, tasks, daily reports, documents, inventory, finance, and dashboard |
+| Expected | All permitted C-01 roles see the same contractor-related project state; restricted actions remain hidden or forbidden; C-03 users never see P-01 |
+| Important | Verify both a fresh login and navigation from an already-open session. Record whether updates require manual refresh according to the intended product behavior |
+
+### WF-06 — Bid package lifecycle
+
+| Field | Test |
+|---|---|
+| Actor | U-03 or authorized contractor project-management role |
+| Steps | Create package for initialized P-01; verify initial draft; add scope, criteria, dates, and documents; invite C-01/C-02/C-03 as appropriate; publish; edit while allowed; close/cancel; award |
+| Expected | Package remains draft until published; draft cannot accept submissions; published package is visible only to invited contractors; status transitions follow allowed rules; awarded package records winner |
+| Negative | Contractor User, Site Operations, Site Technical, and Supervisor cannot create/manage packages unless policy explicitly grants it; a draft package must not be displayed as an open bid |
+
+### WF-07 — Contractor bid submission and evaluation
+
+| Field | Test |
+|---|---|
+| Actor | Invited contractor user/admin and U-03 |
+| Steps | Open invitation; submit proposal and price; edit before closing; attempt duplicate submission; evaluate using simple mode; evaluate using scored criteria; award/reject |
+| Expected | Only invited contractor can submit; required fields validate; duplicate and late submissions are handled correctly; scores and totals are persisted; award updates package and submission status |
+| Database assertions | Invitations, submissions, evaluation criteria, scores, total score, award fields, and timestamps match the UI |
+
+### WF-08 — Tasks, milestones, and progress
+
+| Field | Test |
+|---|---|
+| Actor | U-03, U-06, U-07 |
+| Steps | Create task under milestone; move Pending → In Progress → Completed; test Blocked and Closed; open information modal; add materials, labor, and equipment; assign user; record activity |
+| Expected | Only valid transitions are available; transition buttons appear in the information modal; blocked/closed rules work; costs and progress recalculate; activity log records actor and time |
+| Negative | Invalid transitions and unauthorized updates return a controlled error and preserve the previous state |
+
+### WF-09 — Daily reports and resource roll-up
+
+| Field | Test |
+|---|---|
+| Actor | U-06/U-07 |
+| Steps | Create multiple daily reports for P-01 on different dates; add multiple labor rows, trades, equipment rows, materials, activities, and issues; edit one report; inspect dashboard ResourceSummary |
+| Expected | Dashboard labor totals use all intended daily-report labor records; trade totals aggregate correctly; equipment counts follow the documented aggregation rule; blockers and activity feed show permitted reports |
+| Negative | Reports from P-03 or unrelated contractors never affect C-01 dashboard totals |
+
+### WF-10 — Material requisition approval workflow
+
+| Field | Test |
+|---|---|
+| Actor | Site role creates; Project Manager/executive role approves |
+| Steps | Create draft requisition; add materials; save; submit; inspect approver availability; approve; reject a second request; inspect sidebar badge for each role |
+| Expected | Draft is visible to its creator; submitted request is visible to the correct approvers; Project Manager and executive approver rules work; approval changes status and audit history; unrelated roles do not receive irrelevant alerts |
+| Negative | No-approver condition is reported clearly and does not create a falsely submitted request |
+
+### WF-11 — Purchase order workflow
+
+| Field | Test |
+|---|---|
+| Actor | Authorized logistics user; Project Manager/executive approver |
+| Steps | Create PO from requisition or manually; add supplier/items; submit; approve/reject; mark delivered; upload receipt; mark paid; inspect list/detail pages |
+| Expected | PO status transitions are valid; approver list follows configured roles; delivery and payment buttons appear only when applicable; receipt and payment data persist; tenant restrictions hold |
+| Negative | Site roles cannot approve or update finance-sensitive states without permission; null project/supplier relations do not crash the page |
+
+### WF-12 — Inventory, warehouse, movements, and transfers
+
+| Field | Test |
+|---|---|
+| Steps | Receive delivered PO; verify warehouse stock; create movement; transfer between warehouses; inspect project inventory and available quantities; attempt insufficient-stock transfer |
+| Expected | Quantities, on-hand, allocated, received, and transferred values remain consistent; invalid quantities are rejected; users see only permitted warehouses and projects |
+
+### WF-13 — Cash advance direct approval
+
+| Field | Test |
+|---|---|
+| Actor | Site/contractor user creates; Project Manager or executive approves |
+| Steps | Submit cash advance; verify pending status; inspect Approvals page; attempt self-approval; approve as authorized PM/executive; reject another request |
+| Expected | Cash advances appear directly in the approvals workspace without an approval-chain record if that is the configured rule; self-approval is blocked; approval/rejection records approver and timestamp |
+
+### WF-14 — Invoice and retention approval
+
+| Field | Test |
+|---|---|
+| Steps | Create/submit invoice with retention; inspect approval item; open breakdown; approve; verify invoice status and retention hold; reject another invoice; inspect retention page |
+| Expected | Invoice and retention information appears in approvals; approved invoice updates status and retention ledger exactly once; rejected invoice remains rejected; null project relations render safely |
+
+### WF-15 — Documents, drawings, and technical records
+
+| Field | Test |
+|---|---|
+| Steps | Upload document to P-01; categorize; view/download; update status; attempt access from C-03; inspect project Documents and sidebar navigation |
+| Expected | File metadata and project/contractor relation persist; permitted roles can view/download; unrelated tenant receives 403/404 according to policy; missing files produce controlled errors |
+
+### WF-16 — Dashboard role routing and data accuracy
+
+| Field | Test |
+|---|---|
+| Steps | Log in as U-01 through U-10; inspect dashboard heading and cards; compare every displayed count with database queries for the same scope; inspect Site, PM, Contractor, and Executive layouts |
+| Expected | Super Admin/admin → Executive; Project Manager → PM; Contractor Admin/Main/Sub Contractor roles → Contractor; site roles → Site; contractor admin with `user_type=admin` remains Contractor when its assigned role is contractor-based |
+| Data checks | Project counts use valid project statuses; labor uses intended daily-report aggregation; finance, approvals, documents, inventory, and bidding metrics are tenant/project scoped |
+
+### WF-17 — Sidebar navigation and role visibility
+
+| Field | Test |
+|---|---|
+| Steps | Capture sidebar for every role; open every visible parent and child item; directly request hidden routes; inspect badges after creating drafts/submissions/approvals |
+| Expected | Navigation matches permissions and role policy; Bidding is absent from site operations roles where required; badges are relevant to the current role; direct URL access is denied even if a link is hidden |
+
+### WF-18 — Security and tenant isolation regression
+
+| Field | Test |
+|---|---|
+| Steps | From U-04/U-05/U-06/U-07/U-08/U-09, request P-03, its tasks, reports, inventory, invoices, requisitions, POs, documents, bids, and users by URL/ULID; repeat with guessed numeric IDs |
+| Expected | No cross-tenant record is returned, modified, or deleted; response is 403/404 as designed; no sensitive data leaks through Inertia props, JSON, exports, or error messages |
+
+### WF-19 — Validation, error handling, and null relationships
+
+| Field | Test |
+|---|---|
+| Steps | Submit empty forms; invalid dates; negative quantities; missing project; deleted/null related user, contractor, supplier, or project; duplicate codes/numbers; expired invitation |
+| Expected | Server validation is returned to the form; no uncaught React error occurs; pages show a safe fallback such as “Unavailable”; no partial transaction remains in the database |
+
+### WF-20 — Responsive and browser workflow
+
+| Field | Test |
+|---|---|
+| Steps | Repeat critical pages at desktop, tablet, and mobile widths; open sidebar; open modals; scroll tables; use keyboard navigation; test dark mode if enabled |
+| Expected | Grids collapse correctly; buttons remain reachable; modals fit viewport; tables remain usable; focus states and labels are available; no horizontal overflow blocks actions |
+
+## 7. Execution Record
+
+Use one row per case execution.
+
+| Case ID | Date | Build/commit | Actor | Result | Evidence | Defect ID |
+|---|---|---|---|---|---|---|
+| WF-01 | | | | NOT RUN | | |
+| WF-02 | | | | NOT RUN | | |
+| WF-03 | | | | NOT RUN | | |
+| WF-04 | | | | NOT RUN | | |
+| WF-05 | | | | NOT RUN | | |
+| WF-06 | | | | NOT RUN | | |
+| WF-07 | | | | NOT RUN | | |
+| WF-08 | | | | NOT RUN | | |
+| WF-09 | | | | NOT RUN | | |
+| WF-10 | | | | NOT RUN | | |
+| WF-11 | | | | NOT RUN | | |
+| WF-12 | | | | NOT RUN | | |
+| WF-13 | | | | NOT RUN | | |
+| WF-14 | | | | NOT RUN | | |
+| WF-15 | | | | NOT RUN | | |
+| WF-16 | | | | NOT RUN | | |
+| WF-17 | | | | NOT RUN | | |
+| WF-18 | | | | NOT RUN | | |
+| WF-19 | | | | NOT RUN | | |
+| WF-20 | | | | NOT RUN | | |
+
+## 8. Defect Log
+
+Record defects without changing code during this test pass.
+
+| Defect ID | Case | Severity | Preconditions | Steps to reproduce | Expected | Actual | Evidence | Status |
+|---|---|---|---|---|---|---|---|---|
+| D-001 | WF-02 | Major | Fresh test database; guest contractor registration | Submit the contractor registration form with valid data | Registration redirects successfully, creates pending contractor/admin records, and assigns the configured role | HTTP 500: `Spatie\\Permission\\Exceptions\\PermissionDoesNotExist` because `users.access` is missing when `ContractorOnboardingController.php:66` calls `givePermissionTo('users.access')` | `tests/Feature/ContractorOnboardingTest.php::test_guest_can_register_as_contractor` | Resolved |
+| D-002 | WF-13 | Major | Comprehensive E2E fixture; supervisor and initialized project | Submit a cash advance and query the created request | A pending cash advance exists for the submitted amount | `CashAdvance::where('amount', 750.50)->firstOrFail()` finds no record at `ComprehensiveSystemE2ETest.php:156` | `tests/Feature/ComprehensiveSystemE2ETest.php::test_e2e_cash_advance_full_lifecycle_and_security_rules` | Open |
+| D-003 | WF-04 | Major | Project at wizard step 6; no approver IDs | Submit final project initialization with `approver_ids: []` | Validation error is returned for `approver_ids` | Response does not contain the expected session validation error | `tests/Feature/ProjectWizardFlowTest.php::submit_fails_without_approvers` | Open |
+
+Severity guide: Blocker = workflow cannot continue or data/security risk; Critical = major business flow or tenant isolation failure; Major = important function incorrect; Minor = non-blocking UI or copy issue.
+
+## 9. Automated Baseline
+
+At the time this document was created:
+
+| Check | Result | Notes |
+|---|---|---|
+| `npx tsc --noEmit` | PASS | TypeScript completed successfully during the current verification run |
+| `npm run build` | PASS | Vite production build completed successfully during the current verification run |
+| `php artisan test --testsuite=Feature --stop-on-failure --debug` | FAIL | 23 passed, 2 failed, 85 pending; first confirmed failure is D-001 |
+| `php artisan test tests/Feature/ContractorOnboardingTest.php --debug` | FAIL | 4 passed, 1 failed; D-001 reproduced in 3.90s |
+| Existing `ComprehensiveSystemE2ETest` | PARTIAL COVERAGE | Covers page traversal, cash advance, invoice/retention, and part of project wizard; it does not cover all workflows in this document |
+
+## 10. Exit Criteria
+
+The whole-system workflow is ready for sign-off only when:
+
+- All WF-01 through WF-20 have a recorded result.
+- No Blocker or Critical defects remain open.
+- Tenant isolation cases pass for main contractors, subcontractors, site roles, and unrelated contractors.
+- Project wizard, bidding, requisition, PO, inventory, cash advance, invoice/retention, and dashboard flows pass end-to-end.
+- Browser console has no uncaught errors on tested pages.
+- Database assertions and UI states agree for every completed workflow.
+- Failed automated tests are either rerun successfully or documented with an approved exception.
diff --git a/docs/SYSTEM_WORKFLOW_TEST_CASES.txt b/docs/SYSTEM_WORKFLOW_TEST_CASES.txt
new file mode 100644
index 0000000..24e9789
--- /dev/null
+++ b/docs/SYSTEM_WORKFLOW_TEST_CASES.txt
@@ -0,0 +1,308 @@
+# GSB Construction ERP — End-to-End System Workflow Test Cases
+
+## 1. Purpose
+
+This document defines the complete business-workflow test plan for the GSB Construction ERP. It covers authentication, contractor tenancy, roles, projects, bidding, project execution, materials, finance, approvals, dashboards, and cross-role visibility.
+
+This is a test specification. Discovered defects must be recorded in the defect log and must not be fixed during the test run.
+
+## 2. Test Rules
+
+- Use a disposable or staging database only.
+- Use the same test records across a workflow so each state transition can be verified.
+- Follow Arrange → Act → Assert for every case.
+- Record the user, role, contractor, project, route, request payload, response, database state, and screenshot for failures.
+- A workflow passes only when the UI result, server response, authorization rule, and database state agree.
+- Do not mark a case passed because a page loads; verify the action and resulting data.
+
+## 3. Test Environment
+
+| Item | Requirement |
+|---|---|
+| Backend | Laravel application with migrations loaded |
+| Frontend | Vite development build or compiled production assets |
+| Database | Disposable database with seed data plus test fixtures |
+| Browser | Chromium/Chrome, desktop width, responsive width |
+| Browser checks | Console free of uncaught exceptions; network requests return expected status |
+| Build checks | `npx tsc --noEmit`, `npm run build`, `php artisan test` |
+| Date/time | Confirm expected timezone and date formatting before testing reports and deadlines |
+
+## 4. Required Test Accounts and Data
+
+Create these accounts before execution. Replace the placeholder emails with unique test emails.
+
+| ID | Account | Role | Contractor |
+|---|---|---|---|
+| U-01 | Platform owner | Super Admin | None |
+| U-02 | Platform administrator | admin | None |
+| U-03 | Project manager | Project Manager | None |
+| U-04 | Main contractor administrator | Main Contractor Admin | C-01 |
+| U-05 | Main contractor user | Main Contractor User | C-01 |
+| U-06 | Site technical user | Site Technical | C-01 |
+| U-07 | Construction supervisor | Construction Supervisor | C-01 |
+| U-08 | Site operations user | Site Operations | C-01 |
+| U-09 | Subcontractor administrator | Sub Contractor Admin | C-02, child of C-01 |
+| U-10 | Unrelated contractor user | Contractor User | C-03 |
+
+Create at least:
+
+| ID | Fixture | Required state |
+|---|---|---|
+| C-01 | Great SwissMetal Builders Corporation | Active main contractor |
+| C-02 | C-01 subcontractor | Active child contractor |
+| C-03 | Unrelated contractor | Active separate tenant |
+| P-01 | Main construction project | Draft, then initialized at wizard step 7 |
+| P-02 | C-01 active project | `planning` or `in_progress` |
+| P-03 | C-03 project | Must never appear to C-01 users |
+| M-01 | Material catalog item | Active, with unit and cost |
+| L-01 | Labor record | Active labor/trade |
+| E-01 | Equipment record | Active equipment |
+
+## 5. Role and Tenant Access Matrix
+
+Run the matrix against every protected module. “Own tenant” means the user’s contractor and permitted contractor hierarchy. “Related project” means a project directly owned by, linked to, or assigned to that contractor according to the application rule.
+
+| Area | Super Admin/admin | Project Manager | Contractor Admin | Site Technical/Supervisor/Operations | Unrelated contractor |
+|---|---:|---:|---:|---:|---:|
+| Dashboard | Global | Assigned/allowed scope | Contractor dashboard | Related project scope | Own scope only |
+| Users | Global administration | According to permission | Own contractor users | No administration unless explicitly granted | Own contractor only |
+| Projects | Global | Project scope | Own contractor scope | Related project scope | Own contractor scope |
+| Bid package management | Yes | Yes | According to configured role rule | No | No |
+| Bid submissions | Yes | Yes | Yes for invited contractor | No | Only invited packages |
+| Material requisitions | Global | Create/approve as assigned | Own contractor/project | Create on related project | Own scope |
+| Purchase orders | Global | Create/approve as assigned | Own contractor/project | Operate related project | Own scope |
+| Cash advances | Global approver | Approve other users’ requests | Own contractor rules | Create, not self-approve | Own scope |
+| Invoice/retention approvals | Global | As configured | As configured | No approval unless configured | Own scope |
+| Documents/daily reports/tasks | Global | Assigned/managed projects | Own contractor projects | Related projects only | Own scope |
+
+Any deviation must be logged as a defect, including both unexpected access and missing access.
+
+## 6. End-to-End Workflow Cases
+
+### WF-01 — Authentication and account lifecycle
+
+| Field | Test |
+|---|---|
+| Preconditions | U-01 through U-10 exist; active and inactive accounts are available |
+| Steps | Log in with valid credentials; log out; attempt invalid password; attempt inactive account; reset password; complete forced password change |
+| Expected | Valid users reach the correct dashboard; invalid users receive a safe error; inactive users are blocked; password reset and forced password change complete successfully |
+| Security | No password or sensitive token appears in the UI, URL, response, or logs |
+
+### WF-02 — Contractor onboarding and tenant assignment
+
+| Field | Test |
+|---|---|
+| Actor | U-01 or U-02 |
+| Steps | Create C-01 with administrator; verify administrator is linked to C-01; create C-02 as child contractor; create U-05/U-06/U-07 under C-01; create U-09 under C-02 |
+| Expected | Contractor records, user records, roles, profile records, and contractor IDs are consistent; users created by a contractor admin inherit that contractor |
+| Negative | Attempt to assign a contractor user to C-03 from a C-01 admin account; request is rejected and no cross-tenant change is saved |
+
+### WF-03 — User management and role enforcement
+
+| Field | Test |
+|---|---|
+| Actor | U-01, U-04, U-09 |
+| Steps | List users; create user; edit user; assign each supported role; deactivate user; attempt to view/edit a user from another contractor |
+| Expected | Platform users see global users; contractor admins see only their permitted contractor tree; role names and permissions persist; deactivated users cannot log in |
+| Negative | Site technical and supervisor accounts cannot access user-management actions unless explicitly permitted |
+
+### WF-04 — Project creation and initialization wizard
+
+| Field | Test |
+|---|---|
+| Actor | U-02, U-03, U-04 |
+| Steps | Create P-01; enter project information; add milestones; add tasks; add materials; add labor; add equipment; review financial submission; submit final initialization |
+| Expected | Each step saves; back/next navigation preserves data; validation rejects incomplete required data; step number advances correctly; initialized project is visible to permitted users |
+| Database assertions | `projects.current_wizard_step`, project status, contractor ID, milestones, tasks, estimates, labor, equipment, and personnel links are correct |
+| Negative | A draft project is not treated as an initialized execution project; an unrelated contractor cannot open P-01 |
+
+### WF-05 — Project visibility and cross-role reflection
+
+| Field | Test |
+|---|---|
+| Actor | U-04 creates/updates; U-05/U-06/U-07/U-08 verify |
+| Steps | U-04 initializes or updates P-01; sign in as every C-01 role; inspect Projects, project details, tasks, daily reports, documents, inventory, finance, and dashboard |
+| Expected | All permitted C-01 roles see the same contractor-related project state; restricted actions remain hidden or forbidden; C-03 users never see P-01 |
+| Important | Verify both a fresh login and navigation from an already-open session. Record whether updates require manual refresh according to the intended product behavior |
+
+### WF-06 — Bid package lifecycle
+
+| Field | Test |
+|---|---|
+| Actor | U-03 or authorized contractor project-management role |
+| Steps | Create package for initialized P-01; verify initial draft; add scope, criteria, dates, and documents; invite C-01/C-02/C-03 as appropriate; publish; edit while allowed; close/cancel; award |
+| Expected | Package remains draft until published; draft cannot accept submissions; published package is visible only to invited contractors; status transitions follow allowed rules; awarded package records winner |
+| Negative | Contractor User, Site Operations, Site Technical, and Supervisor cannot create/manage packages unless policy explicitly grants it; a draft package must not be displayed as an open bid |
+
+### WF-07 — Contractor bid submission and evaluation
+
+| Field | Test |
+|---|---|
+| Actor | Invited contractor user/admin and U-03 |
+| Steps | Open invitation; submit proposal and price; edit before closing; attempt duplicate submission; evaluate using simple mode; evaluate using scored criteria; award/reject |
+| Expected | Only invited contractor can submit; required fields validate; duplicate and late submissions are handled correctly; scores and totals are persisted; award updates package and submission status |
+| Database assertions | Invitations, submissions, evaluation criteria, scores, total score, award fields, and timestamps match the UI |
+
+### WF-08 — Tasks, milestones, and progress
+
+| Field | Test |
+|---|---|
+| Actor | U-03, U-06, U-07 |
+| Steps | Create task under milestone; move Pending → In Progress → Completed; test Blocked and Closed; open information modal; add materials, labor, and equipment; assign user; record activity |
+| Expected | Only valid transitions are available; transition buttons appear in the information modal; blocked/closed rules work; costs and progress recalculate; activity log records actor and time |
+| Negative | Invalid transitions and unauthorized updates return a controlled error and preserve the previous state |
+
+### WF-09 — Daily reports and resource roll-up
+
+| Field | Test |
+|---|---|
+| Actor | U-06/U-07 |
+| Steps | Create multiple daily reports for P-01 on different dates; add multiple labor rows, trades, equipment rows, materials, activities, and issues; edit one report; inspect dashboard ResourceSummary |
+| Expected | Dashboard labor totals use all intended daily-report labor records; trade totals aggregate correctly; equipment counts follow the documented aggregation rule; blockers and activity feed show permitted reports |
+| Negative | Reports from P-03 or unrelated contractors never affect C-01 dashboard totals |
+
+### WF-10 — Material requisition approval workflow
+
+| Field | Test |
+|---|---|
+| Actor | Site role creates; Project Manager/executive role approves |
+| Steps | Create draft requisition; add materials; save; submit; inspect approver availability; approve; reject a second request; inspect sidebar badge for each role |
+| Expected | Draft is visible to its creator; submitted request is visible to the correct approvers; Project Manager and executive approver rules work; approval changes status and audit history; unrelated roles do not receive irrelevant alerts |
+| Negative | No-approver condition is reported clearly and does not create a falsely submitted request |
+
+### WF-11 — Purchase order workflow
+
+| Field | Test |
+|---|---|
+| Actor | Authorized logistics user; Project Manager/executive approver |
+| Steps | Create PO from requisition or manually; add supplier/items; submit; approve/reject; mark delivered; upload receipt; mark paid; inspect list/detail pages |
+| Expected | PO status transitions are valid; approver list follows configured roles; delivery and payment buttons appear only when applicable; receipt and payment data persist; tenant restrictions hold |
+| Negative | Site roles cannot approve or update finance-sensitive states without permission; null project/supplier relations do not crash the page |
+
+### WF-12 — Inventory, warehouse, movements, and transfers
+
+| Field | Test |
+|---|---|
+| Steps | Receive delivered PO; verify warehouse stock; create movement; transfer between warehouses; inspect project inventory and available quantities; attempt insufficient-stock transfer |
+| Expected | Quantities, on-hand, allocated, received, and transferred values remain consistent; invalid quantities are rejected; users see only permitted warehouses and projects |
+
+### WF-13 — Cash advance direct approval
+
+| Field | Test |
+|---|---|
+| Actor | Site/contractor user creates; Project Manager or executive approves |
+| Steps | Submit cash advance; verify pending status; inspect Approvals page; attempt self-approval; approve as authorized PM/executive; reject another request |
+| Expected | Cash advances appear directly in the approvals workspace without an approval-chain record if that is the configured rule; self-approval is blocked; approval/rejection records approver and timestamp |
+
+### WF-14 — Invoice and retention approval
+
+| Field | Test |
+|---|---|
+| Steps | Create/submit invoice with retention; inspect approval item; open breakdown; approve; verify invoice status and retention hold; reject another invoice; inspect retention page |
+| Expected | Invoice and retention information appears in approvals; approved invoice updates status and retention ledger exactly once; rejected invoice remains rejected; null project relations render safely |
+
+### WF-15 — Documents, drawings, and technical records
+
+| Field | Test |
+|---|---|
+| Steps | Upload document to P-01; categorize; view/download; update status; attempt access from C-03; inspect project Documents and sidebar navigation |
+| Expected | File metadata and project/contractor relation persist; permitted roles can view/download; unrelated tenant receives 403/404 according to policy; missing files produce controlled errors |
+
+### WF-16 — Dashboard role routing and data accuracy
+
+| Field | Test |
+|---|---|
+| Steps | Log in as U-01 through U-10; inspect dashboard heading and cards; compare every displayed count with database queries for the same scope; inspect Site, PM, Contractor, and Executive layouts |
+| Expected | Super Admin/admin → Executive; Project Manager → PM; Contractor Admin/Main/Sub Contractor roles → Contractor; site roles → Site; contractor admin with `user_type=admin` remains Contractor when its assigned role is contractor-based |
+| Data checks | Project counts use valid project statuses; labor uses intended daily-report aggregation; finance, approvals, documents, inventory, and bidding metrics are tenant/project scoped |
+
+### WF-17 — Sidebar navigation and role visibility
+
+| Field | Test |
+|---|---|
+| Steps | Capture sidebar for every role; open every visible parent and child item; directly request hidden routes; inspect badges after creating drafts/submissions/approvals |
+| Expected | Navigation matches permissions and role policy; Bidding is absent from site operations roles where required; badges are relevant to the current role; direct URL access is denied even if a link is hidden |
+
+### WF-18 — Security and tenant isolation regression
+
+| Field | Test |
+|---|---|
+| Steps | From U-04/U-05/U-06/U-07/U-08/U-09, request P-03, its tasks, reports, inventory, invoices, requisitions, POs, documents, bids, and users by URL/ULID; repeat with guessed numeric IDs |
+| Expected | No cross-tenant record is returned, modified, or deleted; response is 403/404 as designed; no sensitive data leaks through Inertia props, JSON, exports, or error messages |
+
+### WF-19 — Validation, error handling, and null relationships
+
+| Field | Test |
+|---|---|
+| Steps | Submit empty forms; invalid dates; negative quantities; missing project; deleted/null related user, contractor, supplier, or project; duplicate codes/numbers; expired invitation |
+| Expected | Server validation is returned to the form; no uncaught React error occurs; pages show a safe fallback such as “Unavailable”; no partial transaction remains in the database |
+
+### WF-20 — Responsive and browser workflow
+
+| Field | Test |
+|---|---|
+| Steps | Repeat critical pages at desktop, tablet, and mobile widths; open sidebar; open modals; scroll tables; use keyboard navigation; test dark mode if enabled |
+| Expected | Grids collapse correctly; buttons remain reachable; modals fit viewport; tables remain usable; focus states and labels are available; no horizontal overflow blocks actions |
+
+## 7. Execution Record
+
+Use one row per case execution.
+
+| Case ID | Date | Build/commit | Actor | Result | Evidence | Defect ID |
+|---|---|---|---|---|---|---|
+| WF-01 | | | | NOT RUN | | |
+| WF-02 | | | | NOT RUN | | |
+| WF-03 | | | | NOT RUN | | |
+| WF-04 | | | | NOT RUN | | |
+| WF-05 | | | | NOT RUN | | |
+| WF-06 | | | | NOT RUN | | |
+| WF-07 | | | | NOT RUN | | |
+| WF-08 | | | | NOT RUN | | |
+| WF-09 | | | | NOT RUN | | |
+| WF-10 | | | | NOT RUN | | |
+| WF-11 | | | | NOT RUN | | |
+| WF-12 | | | | NOT RUN | | |
+| WF-13 | | | | NOT RUN | | |
+| WF-14 | | | | NOT RUN | | |
+| WF-15 | | | | NOT RUN | | |
+| WF-16 | | | | NOT RUN | | |
+| WF-17 | | | | NOT RUN | | |
+| WF-18 | | | | NOT RUN | | |
+| WF-19 | | | | NOT RUN | | |
+| WF-20 | | | | NOT RUN | | |
+
+## 8. Defect Log
+
+Record defects without changing code during this test pass.
+
+| Defect ID | Case | Severity | Preconditions | Steps to reproduce | Expected | Actual | Evidence | Status |
+|---|---|---|---|---|---|---|---|---|
+| D-001 | WF-02 | Major | Fresh test database; guest contractor registration | Submit the contractor registration form with valid data | Registration redirects successfully, creates pending contractor/admin records, and assigns the configured role | HTTP 500: `Spatie\\Permission\\Exceptions\\PermissionDoesNotExist` because `users.access` is missing when `ContractorOnboardingController.php:66` calls `givePermissionTo('users.access')` | `tests/Feature/ContractorOnboardingTest.php::test_guest_can_register_as_contractor` | Resolved |
+| D-002 | WF-13 | Major | Comprehensive E2E fixture; supervisor and initialized project | Submit a cash advance and query the created request | A pending cash advance exists for the submitted amount | `CashAdvance::where('amount', 750.50)->firstOrFail()` finds no record at `ComprehensiveSystemE2ETest.php:156` | `tests/Feature/ComprehensiveSystemE2ETest.php::test_e2e_cash_advance_full_lifecycle_and_security_rules` | Open |
+| D-003 | WF-04 | Major | Project at wizard step 6; no approver IDs | Submit final project initialization with `approver_ids: []` | Validation error is returned for `approver_ids` | Response does not contain the expected session validation error | `tests/Feature/ProjectWizardFlowTest.php::submit_fails_without_approvers` | Open |
+
+Severity guide: Blocker = workflow cannot continue or data/security risk; Critical = major business flow or tenant isolation failure; Major = important function incorrect; Minor = non-blocking UI or copy issue.
+
+## 9. Automated Baseline
+
+At the time this document was created:
+
+| Check | Result | Notes |
+|---|---|---|
+| `npx tsc --noEmit` | PASS | TypeScript completed successfully during the current verification run |
+| `npm run build` | PASS | Vite production build completed successfully during the current verification run |
+| `php artisan test --testsuite=Feature --stop-on-failure --debug` | FAIL | 23 passed, 2 failed, 85 pending; first confirmed failure is D-001 |
+| `php artisan test tests/Feature/ContractorOnboardingTest.php --debug` | FAIL | 4 passed, 1 failed; D-001 reproduced in 3.90s |
+| Existing `ComprehensiveSystemE2ETest` | PARTIAL COVERAGE | Covers page traversal, cash advance, invoice/retention, and part of project wizard; it does not cover all workflows in this document |
+
+## 10. Exit Criteria
+
+The whole-system workflow is ready for sign-off only when:
+
+- All WF-01 through WF-20 have a recorded result.
+- No Blocker or Critical defects remain open.
+- Tenant isolation cases pass for main contractors, subcontractors, site roles, and unrelated contractors.
+- Project wizard, bidding, requisition, PO, inventory, cash advance, invoice/retention, and dashboard flows pass end-to-end.
+- Browser console has no uncaught errors on tested pages.
+- Database assertions and UI states agree for every completed workflow.
+- Failed automated tests are either rerun successfully or documented with an approved exception.
diff --git a/official_system_operations_manual.md b/official_system_operations_manual.md
new file mode 100644
index 0000000..f10755f
--- /dev/null
+++ b/official_system_operations_manual.md
@@ -0,0 +1,132 @@
+# GSB Construction ERP — Official System Operations Manual
+## Wizard-First End-to-End Operational Lifecycle & Module Documentation
+
+This manual documents the official end-to-end operational flow of the GSB Construction ERP platform, starting from **Project Wizard Initialization** through **Subcontractor Bidding**, **Won Bid Award**, **Logistics & Inventory Setup**, **Site Execution**, and **Financial Progress Claims**.
+
+---
+
+## 🗺️ System Master Lifecycle Flow Diagram
+
+```mermaid
+flowchart TD
+ subgraph STAGE1 ["STAGE 1: PROJECT WIZARD INITIALIZATION"]
+ A1["Step 1: Core Parameters & PM"] --> A2["Step 2: WBS Tasks & Milestones"]
+ A2 --> A3["Step 3: Material BOQ Catalog Items"]
+ A3 --> A4["Step 4: Manpower Rate Allocation"]
+ A4 --> A5["Step 5: Equipment & Machinery Allocation"]
+ A5 --> A6["Step 6: Financial Estimation Summary"]
+ A6 --> A7["Step 7: Automated Executive Submission"]
+ end
+
+ subgraph STAGE2 ["STAGE 2: BIDDING & TENDER (Under Bidding)"]
+ A7 --> B1["Project Status: Under Bidding"]
+ B1 --> B2["Publish Tender Packages & RFQs"]
+ B2 --> B3["Collect Subcontractor Bids & Pricing"]
+ B3 --> B4{"Won Bid / Awarded to Client?"}
+ B4 -- Lost / Void --> B5["Status: Closed"]
+ end
+
+ subgraph STAGE3 ["STAGE 3: LOGISTICS & SUPPLY CHAIN SETUP"]
+ B4 -- Won Bid --> C1["Status Transitions to 'In Progress'"]
+ C1 --> C2["Generate Material Requisitions (MR) from Wizard BOQ"]
+ C2 --> C3["Issue Purchase Orders (PO) to Vendors"]
+ C3 --> C4["Goods Received Note (GRN) & Site Laydown Stocking"]
+ end
+
+ subgraph STAGE4 ["STAGE 4: SITE SCHEDULING, TASKS & DAILY OPERATIONS"]
+ C4 --> D1["Load Wizard Tasks into Interactive Gantt Chart"]
+ D1 --> D2["Log Daily Site Reports, Weather & Manpower"]
+ D2 --> D3["Record Site Blockers & Supervisor Attestation"]
+ D3 --> D4["Auto-deduct Material Consumption from On-Hand Inventory"]
+ end
+
+ subgraph STAGE5 ["STAGE 5: FINANCIAL PROGRESS BILLING & HANDOVER"]
+ D4 --> E1["File Progress Billing Invoices from Work Completion %"]
+ E1 --> E2["Deduct 10% Retention Withholding into Project Ledger"]
+ E2 --> E3["Milestone Accomplishment Sign-off & Final Retention Release"]
+ E3 --> E4["Status Transitions to 'Completed' then 'Closed'"]
+ end
+```
+
+---
+
+## 📘 Detailed Stage-by-Stage Operations Guide
+
+### Stage 1: Project Initialization via 7-Step Wizard (`/projects/wizard`)
+
+1. **Trigger**: User with `projects.access` or `Project Manager` / `Admin` role clicks **"New Project"**.
+2. **Step 1 — General Information**:
+ - Fill in Project Name, Classification (`Standard`, `Special`, `Extension`), Client Name, Location, Target Start/End Dates, PM Assignment, and Contract Value.
+3. **Step 2 — Tasks & Milestones (WBS)**:
+ - Define project milestones with weight percentages (must total 100%).
+ - Add scheduled tasks mapped to milestones with target completion dates.
+4. **Step 3 — Material Estimation (BOQ)**:
+ - Select items from Master Materials Catalog.
+ - Enter estimated quantities and unit costs; total materials cost auto-calculates.
+5. **Step 4 — Manpower Rate Allocation**:
+ - Assign labor trade categories (e.g. `Rebar Steelman`, `Formwork Carpenter`, `General Helper`).
+ - Input estimated work hours and link to specific tasks.
+6. **Step 5 — Equipment Allocation**:
+ - Select machinery from Equipment Fleet (e.g. `Caterpillar 320 Excavator`, `10-Wheeler Dump Truck`).
+ - Enter estimated operating hours per task.
+7. **Step 6 — Financial Estimation Summary**:
+ - System aggregates Total Est. Cost (Materials + Labor + Equipment) vs. Contract Value to project Profit Margin %.
+8. **Step 7 — Automated Submission**:
+ - Click **"Submit for Approval"** $\rightarrow$ Request automatically routes to Executive Management (`Admin` / `Super Admin`) for single sign-off.
+
+---
+
+### Stage 2: Bidding & Tender Management (`Under Bidding`)
+
+1. **Status**: Project is created under **`Under Bidding`**.
+2. **Tender Package Creation**: Cost estimators publish trade packages to invited subcontractors.
+3. **Proposal Evaluation**: Subcontractor quotes are logged and compared against the baseline Wizard BOQ estimates.
+4. **Won Bid Gate**: Upon client award, project status transitions to **`In Progress`**.
+
+---
+
+### Stage 3: Logistics & Inventory Setup (`/inventory` & `/procurement`)
+
+1. **Material Requisitions (MR)**: Site Engineers generate MRs pre-populated with quantities from **Step 3 of the Wizard**.
+2. **Purchase Orders (PO)**: Procurement issues POs to approved material suppliers.
+3. **Goods Received Notes (GRN)**: Site receivers inspect incoming deliveries against PO line items.
+4. **Inventory Stocking**: Delivered materials are added to the project's on-hand site laydown inventory (`ProjectInventory`).
+
+---
+
+### Stage 4: Site Scheduling, Tasks & Daily Operations (`/daily-reports`)
+
+1. **Gantt Scheduling**: Tasks defined in **Step 2 of the Wizard** load into the interactive Gantt chart for scheduling and assignment.
+2. **Daily Site Logging**:
+ - Site Supervisors log shift hours, weather conditions, and manpower headcount per trade.
+ - Task completion percentages (`0%` $\rightarrow$ `100%`) updated directly on daily reports.
+3. **Site Issue & Blocker Compliance**:
+ - Encountered blockers are logged with severity levels.
+ - Resolved blockers remain visible on Executive Dashboards with a **Soft Green Resolved Badge** and supervisor attestation.
+4. **Material Consumption**: Daily material usage auto-deducts from site on-hand inventory.
+
+---
+
+### Stage 5: Financial Management & Claims (`/finance`)
+
+1. **Progress Billing Invoices**: Project Manager generates progress invoices based on validated task completion percentages.
+2. **10% Retention Ledger**:
+ - System automatically holds **10% Retention** on every invoice claim.
+ - Debit entries logged in `RetentionEntry` per project.
+3. **Executive Approval & Payment**: Admin / Super Admin approves progress invoices for payment.
+4. **Project Completion & Retention Release**:
+ - Upon 100% work completion, status transitions to **`Completed`**.
+ - Following defect liability period, held retention funds are released to contractor and status transitions to **`Closed`**.
+
+---
+
+## 🔒 Security & Approval Hierarchy Matrix
+
+| Request Type | Initiated By | Required Approver | Enforcement Rules |
+| :--- | :--- | :--- | :--- |
+| **Site Blockers & Daily Logs** | Site Supervisor / Technical | Project Manager or Executive | Green resolved badge with supervisor sign-off |
+| **Cash Advance Requests** | Site Supervisor | Project Manager or Executive | Self-approval blocked |
+| **Material Requisitions (MR)** | Site Technical | Project Manager | BOQ quantity limit checks |
+| **Project Wizard & Estimations** | Project Manager | Executive (Admin / Super Admin) | Single sign-off completes chain |
+| **Progress Invoices** | Project Manager | Executive (Admin / Super Admin) | 10% Retention auto-withheld |
+| **Admin Submissions** | Admin User | Super Admin | Final executive sign-off |
diff --git a/resources/js/Components/AppSidebar.tsx b/resources/js/Components/AppSidebar.tsx
index 9edefa3..3c7b9ec 100644
--- a/resources/js/Components/AppSidebar.tsx
+++ b/resources/js/Components/AppSidebar.tsx
@@ -161,7 +161,22 @@ export default function AppSidebar() {
auth.roles.includes('Project Manager') ||
auth.roles.includes('Main Contractor Admin');
- const hasParentAccess = isAdminUser ||
+ const isBiddingManager = auth.user.user_type === 'admin' ||
+ auth.roles.includes('Super Admin') ||
+ auth.roles.includes('admin') ||
+ auth.roles.includes('Project Manager');
+ const isSiteOperationsUser = auth.roles.some(role => [
+ 'Site Technical',
+ 'Construction Supervisor',
+ 'Site Operations',
+ 'Site Engineer',
+ 'Site Supervisor',
+ ].includes(role));
+ const isContractorPortalUser = auth.user.user_type === 'contractor' || auth.user.contractor_id !== null;
+
+ const hasParentAccess = item.title === 'Bidding'
+ ? !isSiteOperationsUser && (isBiddingManager || isContractorPortalUser)
+ : isAdminUser ||
!item.permissions ||
item.permissions.length === 0 ||
item.permissions.some(p => auth.permissions.includes(p));
@@ -179,7 +194,9 @@ export default function AppSidebar() {
return {
...item,
- children: filteredChildren
+ children: item.title === 'Bidding' && !isBiddingManager
+ ? filteredChildren.filter(child => ['Bid Packages', 'My Bids'].includes(child.title))
+ : filteredChildren
};
}
diff --git a/resources/js/Components/Dashboard/ResourceSummary.tsx b/resources/js/Components/Dashboard/ResourceSummary.tsx
index add9bbc..36d44fa 100644
--- a/resources/js/Components/Dashboard/ResourceSummary.tsx
+++ b/resources/js/Components/Dashboard/ResourceSummary.tsx
@@ -1,4 +1,6 @@
+import { router } from '@inertiajs/react';
import { HardHat, Truck } from 'lucide-react';
+import { useEffect } from 'react';
interface ResourceSummaryProps {
resources: {
@@ -17,39 +19,32 @@ interface ResourceSummaryProps {
}
export default function ResourceSummary({ resources }: ResourceSummaryProps) {
- const laborPercentage = Math.round((resources.labor.actual / resources.labor.expected) * 100);
-
+ useEffect(() => {
+ const refreshTimer = window.setInterval(() => {
+ router.reload({ only: ['resources'] });
+ }, 30000);
+
+ return () => window.clearInterval(refreshTimer);
+ }, []);
+
return (
- Current Active Contractor: {contractorName}
- {auth.user.roles?.some(r => r.name === 'Super Admin') ? (
- (Platform Super Admin)
- ) : (
- — Users you create will be automatically attached to this company.
- )}
-