Project Management Guide
Last Updated: 2026-01-12 Status: Implemented Plan Reference: 006-project-management.md, 071-project-management-improvement.md
Overview
The Project Management system allows administrators to create and manage projects for clients. Projects track work progress through status workflows, contain files, and provide a central hub for client collaboration.
Table of Contents
- Accessing Projects
- Features
- Project Status Workflow
- How to Use
- Technical Architecture
- Related Features
Accessing Projects
Navigation
| Access Point | Location | URL | Role |
|---|---|---|---|
| All Projects | Admin sidebar | /admin/projects | Admin |
| Create Project | Projects page | /admin/projects/create | Admin |
| View Project | Project row | /admin/projects/{id} | Admin |
| Edit Project | Project detail | /admin/projects/{id}/edit | Admin |
| My Projects | Portal sidebar | /portal/projects | Client User |
| Project Detail | Portal | /portal/projects/{id} | Client User |
Permissions
| Action | Admin | Client User |
|---|---|---|
| View all projects | ✅ | ❌ |
| View client's projects | ✅ | ✅ |
| Create project | ✅ | ❌ |
| Edit project | ✅ | ❌ |
| Delete project | ✅ | ❌ |
| Upload files | ✅ | ✅ |
| Download files | ✅ | ✅ (visible only) |
Features
Project Details
- Project name and description
- Client association
- Status tracking
- Start and due dates
- Budget tracking
- Notes and internal comments
Project Status
- Draft → Active → Completed → Archived workflow
- Color-coded status badges
- Status change logging
Project Files
- File uploads and organization
- Version tracking
- Client visibility controls
- Download tracking
Project Statistics
- File count
- Time tracked (if enabled)
- Invoice associations
- Activity history
Project Status Workflow
Status Enum
Location: app/Enums/ProjectStatus.php
| Status | Value | Description | Color |
|---|---|---|---|
| Draft | draft | Not yet started | Gray |
| Active | active | Currently in progress | Blue |
| Completed | completed | Work finished | Green |
| Archived | archived | Closed/historical | Yellow |
Status Transitions
Draft → Active → Completed → Archived
↑ ↓
←──────────┘ (reopen)
Status Methods
// Check status
$project->status->isDraft();
$project->status->isActive();
$project->status->isCompleted();
$project->status->isArchived();
// Get display values
$project->status->label(); // "Active"
$project->status->color(); // "blue"
How to Use
Creating a New Project
- Navigate to Admin → Projects
- Click "Create Project"
- Fill in required fields:
- Project Name (required)
- Client (required, select from dropdown)
- Fill in optional fields:
- Description
- Start Date
- Due Date
- Budget
- Notes
- Set initial status (default: Draft)
- Click "Create Project"
Viewing Project Details
- Navigate to Admin → Projects or Portal → Projects
- Click on project name or "View"
- View project information:
- Basic details
- Client information
- File list
- Activity timeline
- Related invoices
Editing a Project
- Navigate to Admin → Projects → [Project]
- Click "Edit" button
- Modify fields as needed
- Click "Update Project"
Changing Project Status
- Navigate to Admin → Projects → [Project]
- Click "Edit" or use status dropdown
- Select new status
- Save changes
Note: Status changes are logged in activity history.
Deleting a Project
- Navigate to Admin → Projects → [Project]
- Click "Delete" button
- Confirm deletion
Warning: Deleting a project removes all associated files.
Managing Project Files
See File Sharing Guide for detailed file management.
- Navigate to project detail page
- Click "Upload File" or drag-and-drop
- Set visibility (admin-only or client-visible)
- Files appear in project file list
Advanced Features
Project Templates
Create reusable templates with predefined milestones.
Creating a Template
use App\Models\ProjectTemplate;
$template = ProjectTemplate::create([
'name' => 'Website Redesign',
'description' => 'Standard website redesign project',
'default_status' => 'draft',
'milestones' => [
['title' => 'Discovery & Planning', 'days_offset' => 7],
['title' => 'Design Phase', 'days_offset' => 21],
['title' => 'Development', 'days_offset' => 42],
['title' => 'Testing & Launch', 'days_offset' => 56],
],
'is_active' => true,
'created_by' => auth()->id(),
]);
Applying a Template to a Project
use App\Services\ProjectTemplateService;
$service = new ProjectTemplateService();
// Apply to existing project
$project = $service->applyTemplate($project, $template);
// Create new project from template
$project = $service->createFromTemplate([
'client_id' => $client->id,
'name' => 'Client Website Redesign',
], $template);
Creating a Template from a Project
$template = $service->createFromProject(
$project,
'My Template Name',
auth()->id()
);
Project Cloning
Duplicate a project with its plans and milestones.
- Navigate to Admin → Projects → [Project]
- Click "Clone" button
- Review clone preview showing what will/won't be cloned
- Customize new project name and client
- Click "Clone Project"
use App\Services\ProjectCloneService;
$service = new ProjectCloneService();
// Preview what will be cloned
$preview = $service->preview($project);
// Returns: ['project' => [...], 'will_clone' => [...], 'will_not_clone' => [...]]
// Clone the project
$clonedProject = $service->clone($project);
// Clone with overrides
$clonedProject = $service->clone($project, [
'name' => 'Custom Name',
'client_id' => $otherClient->id,
]);
What gets cloned:
- Project details
- Project plans
- Milestones (reset to "Not Started")
What does NOT get cloned:
- Files
- Conversations
- Approvals
Bulk Status Operations
Update multiple project statuses at once via configuration.
Configuration
Project management settings in config/project-management.php:
return [
'templates' => [
'enabled' => true,
'max_milestones' => 20,
],
'cloning' => [
'enabled' => true,
'include_plans' => true,
'include_milestones' => true,
'reset_milestone_status' => true,
],
'bulk' => [
'enabled' => true,
'max_projects' => 50,
'operations' => [
'activate' => true,
'complete' => true,
'archive' => true,
'delete' => true,
],
],
'defaults' => [
'status' => 'draft',
],
];
Technical Architecture
Model
Location: app/Models/Project.php
class Project extends Model
{
protected $fillable = [
'client_id',
'name',
'description',
'status',
'start_date',
'due_date',
'budget',
'notes',
];
protected $casts = [
'status' => ProjectStatus::class,
'start_date' => 'date',
'due_date' => 'date',
'budget' => 'decimal:2',
];
}
Relationships
// Project model
public function client(): BelongsTo
{
return $this->belongsTo(Client::class);
}
public function files(): HasMany
{
return $this->hasMany(ProjectFile::class);
}
public function invoices(): HasMany
{
return $this->hasMany(Invoice::class);
}
public function timeEntries(): HasMany
{
return $this->hasMany(TimeEntry::class);
}
Controller
Location: app/Http/Controllers/Admin/ProjectController.php
| Method | Route | Description |
|---|---|---|
index() | GET /admin/projects | List projects |
create() | GET /admin/projects/create | Create form |
store() | POST /admin/projects | Create project |
show() | GET /admin/projects/{project} | View project |
edit() | GET /admin/projects/{project}/edit | Edit form |
update() | PUT /admin/projects/{project} | Update project |
destroy() | DELETE /admin/projects/{project} | Delete project |
Routes
// Admin routes
Route::prefix('admin')->middleware(['auth', 'admin'])->group(function () {
Route::resource('projects', Admin\ProjectController::class);
});
// Portal routes
Route::prefix('portal')->middleware(['auth'])->group(function () {
Route::get('projects', [Portal\ProjectController::class, 'index'])->name('portal.projects.index');
Route::get('projects/{project}', [Portal\ProjectController::class, 'show'])->name('portal.projects.show');
});
Database Schema
Table: projects
| Column | Type | Description |
|---|---|---|
id | bigint | Primary key |
client_id | bigint | Foreign key to clients |
name | string | Project name |
description | text | Project description |
status | string | Status enum value |
start_date | date | Project start date |
due_date | date | Project due date |
budget | decimal | Budget amount |
notes | text | Internal notes |
created_at | timestamp | Creation date |
updated_at | timestamp | Last update |
Views
| View | Path | Purpose |
|---|---|---|
| Index | resources/views/admin/projects/index.blade.php | Project list |
| Create | resources/views/admin/projects/create.blade.php | Create form |
| Show | resources/views/admin/projects/show.blade.php | Project details |
| Edit | resources/views/admin/projects/edit.blade.php | Edit form |
| Portal Index | resources/views/portal/projects/index.blade.php | Client's projects |
| Portal Show | resources/views/portal/projects/show.blade.php | Client's view |
Form Validation
// app/Http/Requests/ProjectRequest.php
public function rules(): array
{
return [
'client_id' => 'required|exists:clients,id',
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'status' => 'required|in:draft,active,completed,archived',
'start_date' => 'nullable|date',
'due_date' => 'nullable|date|after_or_equal:start_date',
'budget' => 'nullable|numeric|min:0',
'notes' => 'nullable|string',
];
}
Scopes and Query Helpers
Available Scopes
// By status
Project::status(ProjectStatus::Active)->get();
// Active projects only
Project::active()->get();
// For a specific client
Project::forClient($client)->get();
// With relationships
Project::with(['client', 'files'])->get();
// With counts
Project::withCount('files')->get();
// Overdue projects
Project::overdue()->get();
// Search
Project::search('website redesign')->get();
Related Features
Dependencies
| Feature | Relationship |
|---|---|
| Client Management | Projects belong to clients |
| Authorization | ProjectPolicy controls access |
Complementary Features
| Feature | Description |
|---|---|
| File Sharing | Project file management |
| Invoicing | Project-related invoices |
| Time Tracking | Track time on projects |
| Activity Logging | Project change history |
| Workflow Automation | Automated status updates |
Best Practices
For Administrators
- Use clear project names that identify the work
- Set realistic due dates for expectations
- Update status regularly to reflect progress
- Archive completed projects to keep lists clean
- Use description for client-visible summary
- Use notes for internal information
For Developers
- Use ProjectStatus enum instead of strings
- Eager load client relationship for lists
- Use policies for all authorization
- Scope queries for client users
Troubleshooting
| Issue | Solution |
|---|---|
| Project not visible to client | Check client association |
| Can't change status | Verify admin permissions |
| Files not showing | Check file visibility settings |
| Due date validation error | Ensure due date is after start date |
See Also
- Client Management - Client organization
- File Sharing - Project files
- Invoicing - Project billing
- Time Tracking - Time on projects