# Phase 1 Analysis and Audit

## Audit Session - 2026-05-29 11:38:13 +03:00

Scope: analysis only. No product code was intentionally changed. The only planned writes for this phase are Project_memory audit documents.

Important environment note: `php artisan route:list` fails when it uses the default `php` executable because the machine default is PHP 8.1.25. The project requires PHP 8.2, and `C:\php82\php.exe artisan route:list` works.

Critical testing note: `C:\php82\php.exe artisan test` passed all 16 tests, but `phpunit.xml` does not point testing to `:memory:` or a separate test database. Because tests use `RefreshDatabase`, the local SQLite data was reset. Before the test run, live audit data showed 6 users, 1 team, 2 contacts, 5 conversations, 28 messages, and 7 assignments. After the test run, those table counts became 0. This is a critical Phase 2 safety task: configure the test database before running tests again.

## Executive Summary

The application is a Laravel 11 + Filament 3 WhatsApp CRM. The real routes are mostly Filament resources, with one custom dashboard/workspace at `/admin`.

The custom dashboard contains the expected business sidebar items:

- Dashboard
- Conversations
- Waiting List
- Contacts
- Assignment Log
- Team
- Reports
- Permissions
- Settings

However, several sidebar items are only aliases to existing Filament resources:

- Waiting List is a filtered Conversations table.
- Reports opens Webhook Events, not a business reports dashboard.
- Permissions opens Users, not a permissions matrix.
- Settings opens Users, not system settings.
- Team opens Teams, while employee management is actually Users.

The largest structural issue is navigation shell inconsistency. The custom dashboard hides the Filament sidebar and topbar globally through `public/css/chat-workspace.css`. On resource pages, there is no visible custom sidebar and no visible Filament sidebar/topbar, so users land on isolated pages with poor navigation.

## Main Findings

| Area | Finding | Severity |
|---|---|---|
| Screen structure | Sidebar labels exist in the custom dashboard, but not all are real screens. | High |
| Navigation | Dashboard uses `window.location.href`, causing full page reloads for every sidebar click. | High |
| Navigation shell | `.fi-sidebar` and `.fi-topbar` are hidden globally, leaving resource pages without normal app navigation. | High |
| Employee management | Users can be created with role, team, WABA phone ID, password, and active status, but there is no clear employee profile or permission wizard. | Medium |
| Permissions | Roles exist, but permissions table is empty; most permissions are hardcoded in policies/resources/JS. | High |
| Permission gap | Agent can access AssignmentResource according to resource/policy logic; the resource query does not filter agents. | Critical |
| Permission gap | Backend allows an agent to transfer their own conversation to any user, while expected behavior says employee should only handle assigned conversations. | High |
| Role mismatch | Dashboard role selector uses `manager/support/supervisor`, while backend roles are `admin/supervisor/agent`. | Medium |
| WhatsApp workflow | Incoming messages are matched by WhatsApp sender ID (`wa_id`); contacts are unique, but historical duplicate conversations already exist. | Medium |
| Waiting list | Current incoming workflow assigns new conversations to manager/admin as `open`; it does not create unassigned/pending waiting-list items. | High |
| Reports | No business reports screen exists; Reports currently shows internal webhook logs. | High |
| Performance | Full reloads, global CSS, Livewire table polling, database notification polling, and repeated workspace polling contribute to slow navigation. | High |
| Test safety | PHPUnit reset the local SQLite database because no isolated testing database is configured. | Critical |

## Evidence Collected

- Route list collected successfully with `C:\php82\php.exe artisan route:list`.
- Browser audit was performed as `admin@example.com` before the test database reset.
- Browser console showed no frontend errors during the audited page loads.
- Page loads measured in browser:
  - `/admin`: about 1981 ms after login session existed.
  - `/admin/conversations`: about 2985 ms.
  - `/admin/conversations?tableFilters[status][value]=pending`: about 2022 ms.
  - `/admin/contacts`: about 2195 ms.
  - `/admin/assignments`: about 2088 ms.
  - `/admin/teams`: about 2041 ms.
  - `/admin/webhook-events`: about 2077 ms.
  - `/admin/users`: about 3339 ms.
- Automated tests: 16 passed, but test DB isolation is unsafe and reset the local SQLite data.

## Existing Screens Found

| Screen | Route | Backing File | Current Result |
|---|---|---|---|
| Dashboard / Chat Workspace | `/admin` | `app/Filament/Pages/Dashboard.php`, `resources/views/filament/pages/chat-workspace.blade.php` | Loads custom chat workspace. |
| Conversations | `/admin/conversations` | `app/Filament/Resources/ConversationResource.php` | Loads Filament table. |
| Conversation View | `/admin/conversations/{record}` | `app/Filament/Resources/ConversationResource/Pages/ViewConversation.php` | Loads details plus transfer/close actions, but not a full chat thread. |
| Waiting List | `/admin/conversations?tableFilters[status][value]=pending` | Same as Conversations | Loads empty filtered table when no pending records exist. |
| Contacts | `/admin/contacts` | `app/Filament/Resources/ContactResource.php` | Loads contacts table for admin. |
| Assignment Log | `/admin/assignments` | `app/Filament/Resources/AssignmentResource.php` | Loads assignment table. |
| Team | `/admin/teams` | `app/Filament/Resources/TeamResource.php` | Loads teams table for admin. |
| Users / Employees | `/admin/users` | `app/Filament/Resources/UserResource.php` | Loads employee table and create/edit forms. |
| Webhook Events | `/admin/webhook-events` | `app/Filament/Resources/WebhookEventResource.php` | Loads technical webhook log; currently used as Reports. |

## Working Screens

- Dashboard / chat workspace loads.
- Conversations table loads.
- Waiting List route opens as filtered Conversations table.
- Contacts table loads for admin.
- Assignment Log table loads.
- Team table loads for admin.
- Users / Employees table loads for admin.
- Create Employee and Edit Employee forms load.
- Create Team and Edit Contact forms load.
- Webhook Events table loads.
- Conversation view loads with transfer and close actions.

## Broken or Misleading Screens

| Screen | Status | Reason |
|---|---|---|
| Reports | Misleading / incomplete | Opens Webhook Events, not business reports. |
| Permissions | Misleading / incomplete | Opens Users, not a permissions screen. |
| Settings | Misleading / incomplete | Opens Users, not system settings. |
| Waiting List | Incomplete | It is only a filtered conversations table; no real unassigned intake workflow. |
| Team | Role mismatch | Dashboard allows supervisor, but TeamResource allows admin only. |
| Contacts | Role mismatch | Dashboard allows supervisor, but ContactResource allows admin only. |
| Resource pages | Navigation broken/incomplete | Filament sidebar/topbar hidden globally and custom sidebar is absent on these pages. |

## Employee Management Summary

Current employee management exists through `UserResource`:

- Create employee: yes, admin only.
- Edit employee: yes, admin only.
- Disable employee: yes, via `is_active`.
- Delete employee: yes, but blocked if assigned conversations exist.
- Assign role: yes, multi-select role field.
- Assign team: yes, `team_id`.
- Assign under supervisor: indirectly through team; supervisor is assigned on Team.
- Assign WhatsApp phone ID: yes, `whatsapp_phone_id`.
- Assign conversation: yes through conversation transfer, but not from a clear employee profile.
- Employee profile: no dedicated profile screen.
- Per-employee permission customization: no.

## Permission Summary

Roles are stored with Spatie Permission:

- `admin`
- `supervisor`
- `agent`

The permissions table is empty. Role behavior is hardcoded in:

- `app/Policies/*.php`
- Filament resource `canViewAny()` / `getEloquentQuery()`
- Dashboard JavaScript `PERMISSIONS` and `NAV_ITEMS`

Backend conversation access is generally strong through `ConversationPolicy`, `AssignedScope`, and message query scoping. Main gaps are resource-level access around Assignment Log and inconsistent screen availability.

## WhatsApp Workflow Summary

Current incoming flow:

1. Meta sends webhook to `/api/webhooks/whatsapp`.
2. Signature middleware checks `X-Hub-Signature-256`.
3. Webhook event is stored by message ID for idempotency.
4. `ProcessIncomingMessageJob` locks/fetches contact by `wa_id`.
5. It reuses the latest conversation for that contact, reopening it if closed.
6. If no conversation exists, `ConversationRouter` assigns it to manager/admin.
7. Incoming message is saved with unique `wa_message_id`.
8. Conversation `last_message_at` and `unread_count` update.
9. Notification and broadcast event are emitted.
10. Employee reply is saved locally, sent through WhatsApp Cloud API, then marked sent/failed.

Important gap: the waiting list is not part of the incoming routing flow. New conversations go to manager/admin as open conversations.

## Recommended Phase 2 Order

1. Fix test database isolation immediately.
2. Stabilize navigation shell and screen map without redesigning the full UI.
3. Create real screen boundaries for Dashboard, Conversations, Waiting List, Contacts, Assignment Log, Team/Employees, Reports, Permissions, Settings.
4. Fix permission gaps, especially Assignment Log and agent transfer behavior.
5. Clarify employee creation workflow with role/team/active/login setup.
6. Implement a real waiting/unassigned conversation workflow.
7. Replace misleading Reports/Permissions/Settings aliases with real pages or remove them from sidebar until implemented.
8. Address slow navigation after structure is stable.

