# Contact Module (CRM View)

> **No new DB tables.** Reuses existing `contacts` table (managed by ContactModules/Customer module).
> This module adds a CRM-specific view at `/crm/contacts` with pipeline awareness and label support.

---

## Scope

| In scope (Phase 2) | Deferred (Phase 3) |
|--------------------|-------------------|
| `/crm/contacts` index (read + basic edit) | Segments / saved filters |
| Contact → Leads + Deals linked records | Bulk tag management |
| CRM label integration (Student, Client, etc.) | Import for CRM contacts |

---

## Routes

```php
// CrmApp/Contact/routes/tenant.php
Route::prefix('crm')->name('crm.')->group(function () {
    Route::middleware(['web', ..., 'auth', 'verified'])->group(function () {
        Route::resource('contacts', CrmContactController::class)
            ->only(['index', 'show', 'update'])
            ->names('contacts');
    });
});
```

Routes render as:
- `GET  /crm/contacts` → `crm.contacts.index`
- `GET  /crm/contacts/{contact}` → `crm.contacts.show`
- `PUT  /crm/contacts/{contact}` → `crm.contacts.update`

---

## Controller

```php
namespace CrmApp\Contact\Http\Controllers;

use ContactModules\Customer\Models\Contact;

class CrmContactController extends Controller
{
    public function index(Request $request): Response|JsonResponse
    {
        $contacts = Contact::filter($request->all())
            ->with(['leads' => fn ($q) => $q->limit(3), 'deals' => fn ($q) => $q->limit(3)])
            ->simplePaginate(25);

        if ($request->wantsJson()) {
            return response()->json([
                'data'   => CrmContactResource::collection($contacts->items()),
                'meta'   => simple_pagination_meta($contacts),
                'status' => 'success',
            ]);
        }

        return Inertia::render('Contact/Index', [
            'contactData' => [
                'data'        => CrmContactResource::collection($contacts->items()),
                'meta'        => simple_pagination_meta($contacts),
                'queryParams' => $request->all(),
            ],
        ]);
    }

    public function show(Contact $contact): Response
    {
        $contact->load(['leads', 'deals', 'activityLogs']);
        return Inertia::render('Contact/Show', [
            'contact' => new CrmContactResource($contact),
        ]);
    }
}
```

---

## Contact Model Relationships (add to existing Contact model)

Add these relationships to `ContactModules/Customer/Models/Contact.php` (or via observer):

```php
public function leads(): HasMany
{
    return $this->hasMany(\CrmApp\Lead\Models\Lead::class, 'contact_id');
}

public function deals(): HasMany
{
    return $this->hasMany(\CrmApp\Deal\Models\Deal::class, 'contact_id');
}
```

---

## `CrmContactResource`

```php
public function toArray($request): array
{
    return [
        'id'    => $this->id,
        'name'  => $this->name,
        'email' => $this->email,
        'phone' => $this->phone,
        'leads' => $this->whenLoaded('leads', fn () =>
            $this->leads->map(fn ($l) => ['id' => $l->id, 'uid' => $l->uid, 'name' => $l->name, 'status' => $l->status])
        ),
        'deals' => $this->whenLoaded('deals', fn () =>
            $this->deals->map(fn ($d) => ['id' => $d->id, 'uid' => $d->uid, 'name' => $d->name, 'value' => $d->value])
        ),
        'created_at' => $this->created_at->toDateTimeString(),
    ];
}
```

---

## Pages

| Page | Path |
|------|------|
| Index | `CrmApp/Contact/resources/assets/js/pages/Contact/Index.tsx` |
| Show | `CrmApp/Contact/resources/assets/js/pages/Contact/Show.tsx` |

Index: DataTable with linked leads/deals counts.
Show: Standard show-page layout (see `CLAUDE.md` Show/Detail Design System).
Breadcrumbs: `Home → CRM → useLabel('contact_plural')`

---

## Label Integration

Contact module uses `useLabel('contact_singular')` / `useLabel('contact_plural')` in:
- Page titles
- Breadcrumb labels
- Empty state messages

This is why education profile shows "Students" not "Contacts" in the sidebar and page headers.
