Client Management Guide
Last Updated: 2026-01-12 Status: Implemented Plan Reference: 005-client-management.md, 070-client-management-improvement.md
Overview
The Client Management system allows administrators to create, manage, and organize client organizations. Each client represents a company or individual that uses the portal. Clients can have multiple users (contacts), projects, and invoices associated with them.
Table of Contents
- Accessing Client Management
- Features
- How to Use
- Client Users
- Technical Architecture
- Related Features
Accessing Client Management
Navigation
| Access Point | Location | URL | Role |
|---|---|---|---|
| Client List | Admin sidebar | /admin/clients | Admin |
| Create Client | Client list page | /admin/clients/create | Admin |
| View Client | Client row | /admin/clients/{id} | Admin |
| Edit Client | Client detail page | /admin/clients/{id}/edit | Admin |
Note: Client users access their organization data through the portal dashboard and project views, not a dedicated clients page.
Permissions
| Action | Admin | Client User |
|---|---|---|
| View all clients | ✅ | ❌ |
| View own client | ✅ | ✅ |
| Create client | ✅ | ❌ |
| Edit client | ✅ | ❌ |
| Delete client | ✅ | ❌ |
| Manage client users | ✅ | ❌ |
Features
Client Profile
- Company name and contact information
- Address details (street, city, state, ZIP, country)
- Phone number and email
- Website URL
- Active/inactive status
- Notes field for internal information
Client Users
- Multiple users per client
- User-client association via pivot table
- Client users access portal with scoped permissions
Client Status
- Active: Full access to portal
- Inactive: No portal access
Client Statistics
- Total projects count
- Active projects count
- Total invoices
- Outstanding invoice amount
- Total paid amount
How to Use
Creating a New Client
- Navigate to Admin → Clients
- Click "Create Client" button
- Fill in the required fields:
- Company Name (required)
- Email (required)
- Fill in optional fields:
- Contact name
- Phone number
- Address details
- Website
- Notes
- Set status to Active or Inactive
- Click "Create Client"
Viewing Client Details
- Navigate to Admin → Clients
- Click on a client name or "View" button
- View client information including:
- Contact details
- Associated projects
- Invoice history
- Client users
- Activity log
Editing a Client
- Navigate to Admin → Clients → [Client]
- Click "Edit" button
- Modify desired fields
- Click "Update Client"
Deleting a Client
- Navigate to Admin → Clients → [Client]
- Click "Delete" button
- Confirm deletion in modal
Warning: Deleting a client may affect associated projects and invoices.
Advanced Features
Bulk Operations
Perform actions on multiple clients simultaneously.
- Navigate to Admin → Clients
- Select clients using checkboxes
- Choose bulk action:
- Archive: Mark selected clients as inactive
- Activate: Mark selected clients as active
- Delete: Remove selected clients
// Using ClientBulkController
use App\Http\Controllers\Admin\ClientBulkController;
// Routes
Route::post('clients-bulk/archive', [ClientBulkController::class, 'archive']);
Route::post('clients-bulk/activate', [ClientBulkController::class, 'activate']);
Route::post('clients-bulk/delete', [ClientBulkController::class, 'delete']);
Export Clients
Export client data in multiple formats.
- Navigate to Admin → Clients
- Click "Export" dropdown
- Select format:
- CSV: Spreadsheet-compatible format
- JSON: Developer-friendly format
// Using ClientExportService
use App\Services\ClientExportService;
$service = new ClientExportService();
// Export all clients to CSV
$csvContent = $service->toCsv(Client::all());
// Export to JSON
$jsonContent = $service->toJson(Client::all());
// Get import template
$template = $service->getImportTemplate();
Import Clients
Import clients from CSV files.
- Navigate to Admin → Clients
- Click "Import" button
- Download template (optional)
- Upload CSV file with client data
- Review import results
Required CSV columns: name, email
Optional columns: phone, address, status
// Using ClientImportService
use App\Services\ClientImportService;
$service = new ClientImportService();
// Validate CSV before import
$errors = $service->validateCsv($fileContents);
// Import clients
$results = $service->fromCsv($fileContents, $importedBy);
// Returns ['success' => [...], 'errors' => [...]]
Merge Clients
Combine two clients into one, transferring all relationships.
- Navigate to Admin → Clients → [Source Client]
- Click "Merge" button
- Select target client
- Review merge preview:
- Users to transfer
- Projects to transfer
- Invoices to transfer
- Conversations to transfer
- Confirm merge
Note: The source client is deleted after merge.
// Using ClientMergeService
use App\Services\ClientMergeService;
$service = new ClientMergeService();
// Preview merge
$preview = $service->preview($sourceClient, $targetClient);
// Execute merge
$targetClient = $service->merge($sourceClient, $targetClient);
Configuration
Client management settings in config/client-management.php:
return [
'bulk' => [
'enabled' => true,
'max_clients' => 100,
'operations' => [
'archive' => true,
'activate' => true,
'delete' => true,
],
],
'import' => [
'enabled' => true,
'max_rows' => 1000,
'required_columns' => ['name', 'email'],
'default_status' => 'active',
],
'export' => [
'enabled' => true,
'formats' => ['csv', 'json'],
],
'merge' => [
'enabled' => true,
'transfer_users' => true,
'transfer_projects' => true,
'transfer_invoices' => true,
'transfer_conversations' => true,
],
];
Managing Client Users
- Navigate to Admin → Clients → [Client]
- Scroll to "Client Users" section
- Click "Add User" to associate existing user
- Or click "Create User" to create new client user
- To remove: Click "Remove" next to user
Client Users
User-Client Association
Users can be associated with one or more clients. This is managed through the client_user pivot table.
Adding a User to a Client
// In controller or service
$client->users()->attach($user->id);
// With pivot data
$client->users()->attach($user->id, ['role' => 'primary']);
Checking User Access
// Check if user belongs to client
$user->belongsToClient($client);
// Get all clients for a user
$user->clients;
// Get all users for a client
$client->users;
Technical Architecture
Model
Location: app/Models/Client.php
class Client extends Model
{
protected $fillable = [
'company_name',
'contact_name',
'email',
'phone',
'address',
'city',
'state',
'zip',
'country',
'website',
'notes',
'is_active',
];
protected $casts = [
'is_active' => 'boolean',
];
}
Relationships
// Client model
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class);
}
public function projects(): HasMany
{
return $this->hasMany(Project::class);
}
public function invoices(): HasMany
{
return $this->hasMany(Invoice::class);
}
Controller
Location: app/Http/Controllers/Admin/ClientController.php
| Method | Route | Description |
|---|---|---|
index() | GET /admin/clients | List all clients |
create() | GET /admin/clients/create | Show create form |
store() | POST /admin/clients | Create client |
show() | GET /admin/clients/{client} | View client |
edit() | GET /admin/clients/{client}/edit | Show edit form |
update() | PUT /admin/clients/{client} | Update client |
destroy() | DELETE /admin/clients/{client} | Delete client |
Routes
// Admin routes (routes/web.php)
Route::prefix('admin')->middleware(['auth', 'admin'])->group(function () {
Route::resource('clients', Admin\ClientController::class);
});
// Portal routes
Route::prefix('portal')->middleware(['auth'])->group(function () {
Route::get('clients', [Portal\ClientController::class, 'index'])->name('portal.clients.index');
Route::get('clients/{client}', [Portal\ClientController::class, 'show'])->name('portal.clients.show');
});
Database Schema
Table: clients
| Column | Type | Description |
|---|---|---|
id | bigint | Primary key |
company_name | string | Company/organization name |
contact_name | string | Primary contact name |
email | string | Contact email |
phone | string | Phone number |
address | string | Street address |
city | string | City |
state | string | State/province |
zip | string | ZIP/postal code |
country | string | Country |
website | string | Website URL |
notes | text | Internal notes |
is_active | boolean | Active status |
created_at | timestamp | Creation date |
updated_at | timestamp | Last update |
Pivot Table: client_user
| Column | Type | Description |
|---|---|---|
client_id | bigint | Foreign key to clients |
user_id | bigint | Foreign key to users |
created_at | timestamp | Association date |
Views
| View | Path | Purpose |
|---|---|---|
| Index | resources/views/admin/clients/index.blade.php | Client list |
| Create | resources/views/admin/clients/create.blade.php | Create form |
| Show | resources/views/admin/clients/show.blade.php | Client details |
| Edit | resources/views/admin/clients/edit.blade.php | Edit form |
| Portal Index | resources/views/portal/clients/index.blade.php | Client's view |
Form Validation
Location: app/Http/Requests/ClientRequest.php
public function rules(): array
{
return [
'company_name' => 'required|string|max:255',
'contact_name' => 'nullable|string|max:255',
'email' => 'required|email|max:255',
'phone' => 'nullable|string|max:50',
'address' => 'nullable|string|max:255',
'city' => 'nullable|string|max:100',
'state' => 'nullable|string|max:100',
'zip' => 'nullable|string|max:20',
'country' => 'nullable|string|max:100',
'website' => 'nullable|url|max:255',
'notes' => 'nullable|string',
'is_active' => 'boolean',
];
}
Scopes and Query Helpers
Available Scopes
// Only active clients
Client::active()->get();
// Only inactive clients
Client::inactive()->get();
// Search by name or email
Client::search('acme')->get();
// With project count
Client::withCount('projects')->get();
Related Features
Dependencies
| Feature | Relationship |
|---|---|
| Authorization | ClientPolicy controls access |
| Authentication | User login required |
Complementary Features
| Feature | Description |
|---|---|
| Project Management | Projects belong to clients |
| Invoicing | Invoices belong to clients |
| Activity Logging | Logs client changes |
| File Sharing | Files scoped to client projects |
Best Practices
For Administrators
- Use descriptive company names for easy identification
- Keep contact information updated for notifications
- Use notes field for internal context
- Deactivate rather than delete clients with history
- Assign primary contact as first client user
For Developers
- Always use policies for authorization
- Eager load relationships to avoid N+1 queries
- Use scopes for common query patterns
- Validate input using Form Request classes
Troubleshooting
| Issue | Solution |
|---|---|
| Client not appearing | Check is_active status |
| User can't see client | Verify user-client association |
| Can't delete client | Check for associated projects/invoices |
| Validation errors | Review required fields |
See Also
- Project Management - Managing client projects
- Invoicing - Client billing
- Authorization - Access control
- Activity Logging - Audit trail