# Change Guide

Use this before modifying lead/form/dashboard/auth behavior.

## Change Public Form Fields

Files to update:

- Blade UI: `resources/views/pages/contact.blade.php`
- Frontend capture/submit: `public/js/lead-tracking.js`
- Server validation/save: `app/Http/Controllers/LeadController.php`
- Fallback native POST if needed: `app/Http/Controllers/ContactController.php`
- Database if persisted: `database/migrations/*`
- Model fillable: `app/Models/Lead.php`
- Dashboard display/export if visible: `app/Http/Controllers/LeadDashboardController.php`, `resources/views/dashboard/leads/index.blade.php`, `resources/views/dashboard/leads/show.blade.php`

Checklist:

1. Add the input in `contact.blade.php`.
2. If it must be tracked before submit, add it to `getFormDataForCapture()` in `public/js/lead-tracking.js`.
3. Add validation in `LeadController::submitFormHandler`.
4. Add the field to `$lead->update([...])` in `submitFormHandler`.
5. Add a database migration.
6. Add it to `Lead::$fillable`.
7. Add dashboard/export output if required.
8. Keep `ContactController::submit` in sync if native form POST must support it.

## Change Lead Validation

Main API path:

- `app/Http/Controllers/LeadController.php`
- Private method `submitFormHandler`

Partial capture path:

- `LeadController::captureFormData`
- `public/js/lead-tracking.js` method `captureFullForm`

Native fallback path:

- `app/Http/Controllers/ContactController.php` method `submit`

Current rule:

- Phone and message are optional in the UI, frontend validation, `LeadController::submitFormHandler`, and `ContactController::submit`.
- If either becomes required later, update all four places together.

## Change Dashboard Columns/Cards

Lead listing card:

- `resources/views/dashboard/leads/index.blade.php`

Data source:

- `LeadDashboardController::index`
- `$leads = $query->orderBy('created_at', 'desc')->paginate(20)`

Stats cards:

- Controller method `getStatistics`
- View top stats section in `dashboard/leads/index.blade.php`

Sidebar cards:

- `getTopSources`
- `getTopReferralSources`
- `getServiceBreakdown`
- `getMarketBreakdown`
- View sidebar in `dashboard/leads/index.blade.php`

Detail page:

- `resources/views/dashboard/leads/show.blade.php`

CSV export:

- `LeadDashboardController::export`

## Change Dashboard Stats

File: `app/Http/Controllers/LeadDashboardController.php`

Update:

- `getStatistics()` for top cards/today/conversion/average completion.
- `getMarketBreakdown()` for market sidebar.
- `getTopSources()` for source page sidebar.
- `getTopReferralSources()` for traffic source sidebar.
- `getServiceBreakdown()` for service sidebar.

Then update labels/layout in:

- `resources/views/dashboard/leads/index.blade.php`

## Change Login/Dashboard Access

Files:

- Routes: `routes/web.php`
- Controller: `app/Http/Controllers/AuthController.php`
- View: `resources/views/auth/login.blade.php`
- User model: `app/Models/User.php`
- Auth config: `config/auth.php`
- Middleware: `app/Http/Kernel.php`, `app/Http/Middleware/RedirectIfAuthenticated.php`

Current access model:

- Dashboard routes require `auth` and `admin`.
- Admin means `users.is_admin = true`.

To change admin access:

1. Update `users.is_admin` values.
2. Keep `app/Http/Middleware/EnsureAdmin.php` as the dashboard gate.
3. If replacing with roles later, update `EnsureAdmin`, `app/Models/User.php`, and the users migration/schema.
4. Add tests for non-admin denial and admin access.

## Change Lead Statuses

Files:

- Model status labels/colors: `app/Models/Lead.php`
- Status validation: `LeadDashboardController::updateStatus`
- Filters/status selects: `resources/views/dashboard/leads/index.blade.php`, `resources/views/dashboard/leads/show.blade.php`
- Stats: `LeadDashboardController::getStatistics`
- Migration/schema: `database/migrations/2026_01_19_113036_create_leads_table.php` plus a new migration for existing DBs
- Translations: `resources/lang/*/messages.php`

Important:

- Do not edit old migrations for an existing deployed DB. Add a new migration.
- `database/migrations/2026_05_09_000001_harden_leads_dashboard_and_schema.php` ensures MySQL supports `archived`.

## Change Email/Notifications

Current notification paths:

- Broadcast event: `app/Events/LeadNotification.php`
- Trigger points: `app/Http/Controllers/LeadController.php`
  - cold lead in `findOrCreateLead`
  - abandoned in `formAbandoned`
  - submitted in `submitFormHandler`
- Push service: `app/Services/LeadBeamsNotificationService.php`
- Dashboard browser listener: `resources/views/dashboard/leads/index.blade.php`
- Config: `config/beams.php`, `config/broadcasting.php`

No email sender exists today.

To add email:

1. Create a mailable/notification.
2. Configure `config/mail.php` if present or add it according to Laravel version.
3. Trigger after successful DB save in `LeadController::submitFormHandler`.
4. Keep email failures isolated so lead submission still succeeds.
5. Log failures with enough lead id/context.

To add webhook:

1. Add config for endpoint/secret.
2. Dispatch a queued job after lead save.
3. Sign payloads.
4. Retry with backoff.
5. Never block the user-facing submit on webhook latency.

## Change Database Fields

Files:

- New migration in `database/migrations`
- Model: `app/Models/Lead.php`
- Controller save logic: `app/Http/Controllers/LeadController.php`
- Dashboard/export as needed: `app/Http/Controllers/LeadDashboardController.php`

Before changing:

- Verify current production schema.
- Local SQLite is currently missing visible calculator migration fields.
- Check `php artisan migrate:status` in the target environment.

## Change Calculator Lead Payload

Files:

- Calculator view: `resources/views/pages/calculator.blade.php`
- Calculator JS: `public/js/quote-calculator.js`
- Contact hidden fields: `resources/views/pages/contact.blade.php`
- Lead validation/save: `app/Http/Controllers/LeadController.php`
- Database/model: migration + `app/Models/Lead.php`

Key method:

- `public/js/quote-calculator.js` -> `buildLeadPayload()`

Flow:

```mermaid
flowchart TD
    A["Calculator state"] --> B["buildLeadPayload()"]
    B --> C["Contact URL query params"]
    C --> D["contact.blade.php hidden fields"]
    D --> E["lead-tracking.js submitForm"]
    E --> F["LeadController::submitFormHandler"]
    F --> G["leads table"]
```

## Safety Rules

- Do not modify functionality until the target flow is mapped in these docs.
- Keep native `/contact` fallback and JS `/api/leads/submit` behavior intentionally aligned.
- Add database migrations instead of editing old migrations.
- Verify production migrations have run before deploying code that depends on `is_admin`, `archived`, or calculator columns.
- Lead API rate limiting and honeypot are in place; consider captcha only if spam persists.
- Test both English `/contact` and localized `/{locale}/contact`.
