feat(project): Complete Project Lifecycle capability with full TDD workflow
- Implement ProjectController with CRUD, status transitions, estimate/forecast - Add ProjectService with state machine validation - Extract ProjectStatusService for reusable state machine logic - Add ProjectPolicy for role-based authorization - Create ProjectSeeder with test data - Implement frontend project management UI with modal forms - Add projectService API client - Complete all 9 incomplete unit tests (ProjectModelTest, ProjectForecastTest, ProjectPolicyTest) - Fix E2E test timing issues with loading state waits - Add Scribe API documentation annotations - Improve forecasted effort validation messages with detailed feedback Test Results: - Backend: 49 passed (182 assertions) - Frontend Unit: 32 passed - E2E: 134 passed (Chromium + Firefox) Phase 3 Refactor: - Extract ProjectStatusService for state machine - Optimize project list query with status joins - Improve forecasted effort validation messages Phase 4 Document: - Add Scribe annotations to ProjectController - Generate API documentation
This commit is contained in:
@@ -18,6 +18,7 @@ class DatabaseSeeder extends Seeder
|
||||
RoleSeeder::class,
|
||||
ProjectStatusSeeder::class,
|
||||
ProjectTypeSeeder::class,
|
||||
ProjectSeeder::class,
|
||||
UserSeeder::class,
|
||||
]);
|
||||
}
|
||||
|
||||
83
backend/database/seeders/ProjectSeeder.php
Normal file
83
backend/database/seeders/ProjectSeeder.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ProjectSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Get status and type IDs
|
||||
$preSalesStatus = DB::table('project_statuses')->where('name', 'Pre-sales')->first();
|
||||
$sowApprovalStatus = DB::table('project_statuses')->where('name', 'SOW Approval')->first();
|
||||
$estimationStatus = DB::table('project_statuses')->where('name', 'Estimation')->first();
|
||||
$inProgressStatus = DB::table('project_statuses')->where('name', 'In Progress')->first();
|
||||
$onHoldStatus = DB::table('project_statuses')->where('name', 'On Hold')->first();
|
||||
|
||||
$projectType = DB::table('project_types')->where('name', 'Project')->first();
|
||||
$supportType = DB::table('project_types')->where('name', 'Support')->first();
|
||||
|
||||
if (! $preSalesStatus || ! $projectType) {
|
||||
$this->command->warn('Required statuses or types not found. Run ProjectStatusSeeder and ProjectTypeSeeder first.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$projects = [
|
||||
[
|
||||
'id' => Str::uuid()->toString(),
|
||||
'code' => 'PROJ-001',
|
||||
'title' => 'Website Redesign',
|
||||
'status_id' => $preSalesStatus->id, // Pre-sales for transition testing
|
||||
'type_id' => $projectType->id,
|
||||
'approved_estimate' => null,
|
||||
'forecasted_effort' => null,
|
||||
],
|
||||
[
|
||||
'id' => Str::uuid()->toString(),
|
||||
'code' => 'PROJ-002',
|
||||
'title' => 'API Integration',
|
||||
'status_id' => $estimationStatus->id ?? $preSalesStatus->id,
|
||||
'type_id' => $projectType->id,
|
||||
'approved_estimate' => null,
|
||||
'forecasted_effort' => null,
|
||||
],
|
||||
[
|
||||
'id' => Str::uuid()->toString(),
|
||||
'code' => 'SUP-001',
|
||||
'title' => 'Bug Fixes',
|
||||
'status_id' => $onHoldStatus->id ?? $preSalesStatus->id,
|
||||
'type_id' => $supportType->id,
|
||||
'approved_estimate' => 40.00,
|
||||
'forecasted_effort' => json_encode(['2024-02' => 20, '2024-03' => 20]),
|
||||
],
|
||||
[
|
||||
'id' => Str::uuid()->toString(),
|
||||
'code' => 'PROJ-003',
|
||||
'title' => 'Mobile App Development',
|
||||
'status_id' => $inProgressStatus->id ?? $preSalesStatus->id,
|
||||
'type_id' => $projectType->id,
|
||||
'approved_estimate' => 120.00,
|
||||
'forecasted_effort' => json_encode(['2024-02' => 40, '2024-03' => 50, '2024-04' => 30]),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($projects as $project) {
|
||||
DB::table('projects')->updateOrInsert(
|
||||
['code' => $project['code']],
|
||||
array_merge($project, [
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
$this->command->info('Seeded '.count($projects).' projects.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user