# RTM / RPM / CCM Integration — Agent Task List & Prompt

---

## 📋 TASK LIST

### Phase 1 — Reconnaissance (DO THIS FIRST, before writing any code)
- [ ] 1.1 Read all existing Laravel models in `app/Models/` and list their columns, relationships, and fillable fields
- [ ] 1.2 Read all existing migrations in `database/migrations/` to understand the full DB schema
- [ ] 1.3 Read `routes/api.php` and `routes/web.php` — note route naming conventions, prefix groups, and middleware stacks
- [ ] 1.4 Read existing controllers in `app/Http/Controllers/Doctor/` and `app/Http/Controllers/Staff/` to confirm Splade response patterns
- [ ] 1.5 Read existing Action classes in `app/Actions/MedicalRecord/` and `app/Actions/UrgentCare/` to confirm the `execute()` pattern
- [ ] 1.6 Read existing Form Request classes in `app/Http/Requests/LOA/` and `app/Http/Requests/` root to confirm `authorize()`, `rules()`, `messages()`, and `attributes()` patterns
- [ ] 1.7 Identify the authenticated user model and how patient/doctor/staff relationships are stored

---

### Phase 2 — Database Migrations (only create what doesn't already exist)
- [ ] 2.1 Create migration: `remote_care_patient_intakes`
- [ ] 2.2 Create migration: `remote_care_medications`
- [ ] 2.3 Create migration: `remote_care_physician_orders`
- [ ] 2.4 Create migration: `remote_care_monitoring_enrollments`

---

### Phase 3 — Form Request Classes
- [ ] 3.1 `app/Http/Requests/RemoteMonitoring/StorePatientIntakeRequest.php`
- [ ] 3.2 `app/Http/Requests/RemoteMonitoring/StorePhysicianOrderRequest.php`

---

### Phase 4 — Action Classes
- [ ] 4.1 `app/Actions/RemoteMonitoring/CreatePatientIntakeAction.php`
- [ ] 4.2 `app/Actions/RemoteMonitoring/CreatePhysicianOrderAction.php`

---

### Phase 5 — Laravel Models & Relationships
- [ ] 5.1 `app/Models/PatientIntake.php`
- [ ] 5.2 `app/Models/RemoteCareMedication.php`
- [ ] 5.3 `app/Models/PhysicianOrder.php`
- [ ] 5.4 `app/Models/MonitoringEnrollment.php`

---

### Phase 6 — Thin Controllers & Routes
- [ ] 6.1 `app/Http/Controllers/RemoteMonitoring/PatientIntakeController.php`
- [ ] 6.2 `app/Http/Controllers/RemoteMonitoring/PhysicianOrderController.php`
- [ ] 6.3 Register routes in `routes/web.php` matching existing Splade middleware and naming conventions

---

### Phase 7 — Vue.js Views
- [ ] 7.1 `resources/js/components/RemoteMonitoring/PatientIntakeForm.vue`
- [ ] 7.2 `resources/js/components/RemoteMonitoring/PhysicianOrderForm.vue`
- [ ] 7.3 `resources/js/components/RemoteMonitoring/StaffQualificationSummary.vue`

---

### Phase 8 — Wiring & Testing
- [ ] 8.1 Confirm Vue components use `Splade.request()` (imported from `@protonemedia/laravel-splade`) to the correct routes
- [ ] 8.2 Confirm flow: Controller → Form Request (validation) → Action `execute()` → Model (persistence)
- [ ] 8.3 Confirm `PhysicianOrderForm.vue` pre-fills from the PatientIntake record on mount

---

## 🤖 CODING AGENT PROMPT

---

### ROLE

You are a senior full-stack developer working on a **Laravel Splade** telemedical application. Your job is to add Remote Therapeutic Monitoring (RTM), Remote Physiologic Monitoring (RPM), and Chronic Care Management (CCM) forms. You must not duplicate existing logic, and you must strictly follow the patterns already established in this codebase — which are documented with real examples below.

---

### STEP 0 — READ BEFORE YOU WRITE ANYTHING

Before creating any file, read the following to confirm the patterns below still match:
1. `app/Actions/MedicalRecord/CreateMedicalCondition.php`
2. `app/Actions/UrgentCare/HandleUrgentCareUserCreation.php`
3. `app/Http/Requests/UrgentCareQuestionsRequest.php`
4. `app/Http/Requests/LOA/StoreLOAPatientEnrollmentRequest.php`
5. `app/Http/Controllers/Doctor/PatientMedicalQuestionnaireController.php`
6. `app/Http/Controllers/Staff/SubscriptionManagementController.php`
7. `resources/js/components/GeneralMedicalQuestionForm.vue`
8. `resources/js/components/DynamicMedicalQuestionnaire.vue`

Output a one-paragraph confirmation that the patterns below match what you found, then proceed.

---

### ESTABLISHED PATTERNS — FOLLOW THESE EXACTLY

#### ✅ Action Pattern

Actions extend `App\Actions\Action`, use a public `execute(array $data): array` method, return an associative array with a `success` boolean key, wrap logic in try/catch, and log errors with `Log::error()`.

```php
namespace App\Actions\RemoteMonitoring;

use App\Actions\Action;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;

class CreatePatientIntakeAction extends Action
{
    public function execute(array $data): array
    {
        try {
            DB::transaction(function () use ($data, &$result) {
                // ... all DB writes here
            });

            return [
                'success' => true,
                'message' => 'Patient intake saved successfully.',
                'data' => $result,
            ];
        } catch (\Exception $e) {
            Log::error('Error in CreatePatientIntakeAction: ' . $e->getMessage());

            return [
                'success' => false,
                'message' => 'Failed to save patient intake. Please try again.',
                'error' => $e->getMessage(),
            ];
        }
    }
}
```

#### ✅ Form Request Pattern

Form Requests extend `Illuminate\Foundation\Http\FormRequest`. `authorize()` checks role via `auth()->user()->hasRole()` for role-gated endpoints, or returns `true` for open endpoints. `rules()` uses **array syntax** (not pipe syntax). Include `messages(): array` and `attributes(): array` where field names need human-readable labels.

```php
namespace App\Http\Requests\RemoteMonitoring;

use Illuminate\Foundation\Http\FormRequest;

class StorePatientIntakeRequest extends FormRequest
{
    public function authorize(): bool
    {
        return auth()->check() && auth()->user()->hasRole('staff');
    }

    public function rules(): array
    {
        return [
            'patient_id'   => ['required', 'exists:users,id'],
            'has_hypertension' => ['nullable', 'boolean'],
            'medications'  => ['nullable', 'array'],
            'medications.*.name' => ['required_with:medications', 'string', 'max:255'],
            // ...
        ];
    }

    public function messages(): array
    {
        return [
            'patient_id.required' => 'A patient must be selected.',
            'patient_id.exists'   => 'The selected patient does not exist.',
            // ...
        ];
    }

    public function attributes(): array
    {
        return [
            'patient_id' => 'patient',
            // ...
        ];
    }
}
```

#### ✅ Controller Pattern

Controllers extend `App\Http\Controllers\Controller`. They use **Splade** for responses: `Toast::danger()`, `Toast::warning()`, `Toast::success()`, and `return view('...')`. Controllers instantiate Actions directly with `(new SomeAction)->execute([...])` — they do NOT use constructor injection for Actions. Form Requests are type-hinted in method signatures.

```php
namespace App\Http\Controllers\RemoteMonitoring;

use App\Http\Controllers\Controller;
use App\Http\Requests\RemoteMonitoring\StorePatientIntakeRequest;
use App\Actions\RemoteMonitoring\CreatePatientIntakeAction;
use App\Models\PatientIntake;
use ProtoneMedia\Splade\Facades\Toast;

class PatientIntakeController extends Controller
{
    public function store(StorePatientIntakeRequest $request)
    {
        $result = (new CreatePatientIntakeAction)->execute([
            'data' => $request->validated(),
        ]);

        if (! $result['success']) {
            Toast::danger($result['message'])->autoDismiss(4);
            return redirect()->back();
        }

        Toast::success('Patient intake saved successfully.')->autoDismiss(3);
        return redirect()->route('remote-monitoring.order.create', $result['data']->id);
    }

    public function show(PatientIntake $intake)
    {
        $intake->load(['medications', 'physicianOrder']);
        return view('remote-monitoring.intake.show', compact('intake'));
    }
}
```

#### ✅ Vue.js Pattern

Vue components use the **Options API** (`export default {}`). HTTP calls use the **`Splade` object imported from `"./Splade"`** — specifically `Splade.request(url, method, data)`. Do NOT use `this.$splade`, Axios, `fetch()`, or Inertia.

Splade exposes native validation error and toast helpers that must be used instead of manually parsing `error.response`:
- `Splade.hasValidationErrors(Splade.currentStack.value)` — check if the last response had validation errors
- `Splade.validationErrors(Splade.currentStack.value)` — retrieve the validation errors object
- `Splade.flashData(Splade.currentStack.value).message` — read flash messages from the server response
- `Splade.pushToast({ message, type, autoDismiss })` — show a toast from within a Vue component

Styling is **Tailwind CSS**. Store a local `errors` object in `data()` as a fallback for generic errors. Dynamic medication rows use `push()` / `splice()`. Conditional field visibility uses `shouldShowField()` or a computed property. Emit events to parents via `this.$emit()` where needed.

```javascript
import { Splade } from "@protonemedia/laravel-splade"; // adjust relative path to match existing components

export default {
    props: {
        intakeId: { type: Number, default: null }
    },
    data() {
        return {
            formData: {
                patient_id: null,
                has_hypertension: false,
                medications: [],
                // ...
            },
            errors: {},
            loading: false,
        };
    },
    computed: {
        servicePath() {
            if (this.formData.has_multiple_conditions) return 'ccm';
            if (this.formData.has_copd_asthma) return 'rtm_resp';
            if (this.formData.has_chronic_pain || this.formData.has_arthritis) return 'rtm_msk';
            if (this.formData.has_hypertension || this.formData.has_diabetes || this.formData.has_heart_failure) return 'rpm';
            return null;
        }
    },
    methods: {
        addMedication() {
            this.formData.medications.push({ name: '', dosage: '', frequency: '', purpose: '' });
        },
        removeMedication(index) {
            this.formData.medications.splice(index, 1);
        },
        submitForm() {
            this.loading = true;
            this.errors = {};

            Splade.request('/remote-monitoring/intake', 'POST', this.formData)
                .then(() => {
                    this.loading = false;
                    // Use Splade's native validation error helpers first
                    if (Splade.hasValidationErrors(Splade.currentStack.value)) {
                        this.errors = Splade.validationErrors(Splade.currentStack.value);
                        return;
                    }
                    // handle success — e.g. read flash message or redirect
                    const message = Splade.flashData(Splade.currentStack.value)?.message;
                    if (message) {
                        Splade.pushToast({ message, type: 'success', autoDismiss: true });
                    }
                })
                .catch(() => {
                    this.loading = false;
                    this.errors = { general: 'An error occurred while submitting the form. Please try again.' };
                });
        }
    }
};
```

**Important:** Check how existing components in `resources/js/components/` import `Splade` and use the exact same relative import path. Do not guess the path.

---

### STEP 1 — DATABASE MIGRATIONS

Create only if the table does not already exist.

#### `remote_care_patient_intakes`
- `id` (bigIncrements)
- `patient_id` (foreignId → users)
- `staff_id` (foreignId → users, nullable)
- `has_hypertension` (boolean, default false)
- `has_diabetes` (boolean, default false)
- `has_heart_failure` (boolean, default false)
- `has_chronic_pain` (boolean, default false)
- `has_arthritis` (boolean, default false)
- `has_copd_asthma` (boolean, default false)
- `has_multiple_conditions` (boolean, default false)
- `service_path` (enum: `rpm`,`rtm_msk`,`rtm_resp`,`ccm`, nullable)
- `primary_goal` (text, nullable)
- `recent_hospitalization` (boolean, default false)
- `medication_request_type` (enum: `refill`,`new`,`none`, default `none`)
- `medication_request_reason` (text, nullable)
- `has_smartphone` (boolean, default false)
- `willing_to_use_device` (boolean, default false)
- `has_caregiver` (boolean, default false)
- `status` (enum: `pending`,`ordered`,`enrolled`, default `pending`)
- `timestamps`

#### `remote_care_medications`
- `id`
- `patient_intake_id` (foreignId → remote_care_patient_intakes)
- `name` (string)
- `dosage` (string, nullable)
- `frequency` (string, nullable)
- `purpose` (string, nullable)
- `timestamps`

#### `remote_care_physician_orders`
- `id`
- `patient_intake_id` (foreignId → remote_care_patient_intakes)
- `provider_id` (foreignId → users)
- `service_rpm` (boolean, default false)
- `service_rtm_msk` (boolean, default false)
- `service_rtm_resp` (boolean, default false)
- `service_ccm` (boolean, default false)
- `goal_stabilize_vitals` (boolean, default false)
- `goal_therapy_adherence` (boolean, default false)
- `goal_medication_management` (boolean, default false)
- `goal_care_coordination` (boolean, default false)
- `clinical_goal_notes` (text, nullable)
- `primary_diagnosis_icd10` (string, nullable)
- `cpt_codes` (json, nullable)
- `patient_consented` (boolean, default false)
- `patient_understands_cost` (boolean, default false)
- `patient_agreed_16_days` (boolean, default false)
- `patient_signature` (string, nullable)
- `patient_signed_at` (timestamp, nullable)
- `provider_npi` (string, nullable)
- `provider_signed_at` (timestamp, nullable)
- `timestamps`

#### `remote_care_monitoring_enrollments`
- `id`
- `patient_id` (foreignId → users)
- `physician_order_id` (foreignId → remote_care_physician_orders)
- `service_path` (enum: `rpm`,`rtm_msk`,`rtm_resp`,`ccm`)
- `cpt_codes` (json)
- `enrolled_at` (timestamp)
- `discharged_at` (timestamp, nullable)
- `timestamps`

---

### STEP 2 — MODELS

Create in `app/Models/`. Match property ordering and cast style of existing models. Cast all boolean fields as `boolean`. Cast `cpt_codes` as `array`.

- `PatientIntake` → hasMany `RemoteCareMedication`, hasOne `PhysicianOrder`, belongsTo `User` (as `patient`), belongsTo `User` (as `staff`)
- `RemoteCareMedication` → belongsTo `PatientIntake`
- `PhysicianOrder` → belongsTo `PatientIntake`, belongsTo `User` (as `provider`), hasOne `MonitoringEnrollment`
- `MonitoringEnrollment` → belongsTo `PhysicianOrder`, belongsTo `User` (as `patient`)

---

### STEP 3 — FORM REQUEST CLASSES

Create in `app/Http/Requests/RemoteMonitoring/`. Follow the pattern above exactly.

#### `StorePatientIntakeRequest`
- `authorize()`: `auth()->check() && auth()->user()->hasRole('staff')`
- Rules:
  - `patient_id` → `['required', 'exists:users,id']`
  - All `has_*` booleans → `['nullable', 'boolean']`
  - `primary_goal` → `['nullable', 'string', 'max:500']`
  - `recent_hospitalization` → `['nullable', 'boolean']`
  - `medication_request_type` → `['nullable', 'in:refill,new,none']`
  - `medication_request_reason` → `['nullable', 'string', 'max:500']`
  - `has_smartphone`, `willing_to_use_device`, `has_caregiver` → `['nullable', 'boolean']`
  - `medications` → `['nullable', 'array']`
  - `medications.*.name` → `['required_with:medications', 'string', 'max:255']`
  - `medications.*.dosage`, `*.frequency`, `*.purpose` → `['nullable', 'string', 'max:255']`
- Include `messages()` with user-friendly strings for all required rules
- Include `attributes()` for `patient_id` → `'patient'`

#### `StorePhysicianOrderRequest`
- `authorize()`: `auth()->check() && auth()->user()->hasRole('doctor')`
- Rules:
  - `patient_intake_id` → `['required', 'exists:remote_care_patient_intakes,id']`
  - All `service_*` and `goal_*` booleans → `['nullable', 'boolean']`
  - `clinical_goal_notes` → `['nullable', 'string', 'max:1000']`
  - `primary_diagnosis_icd10` → `['nullable', 'string', 'max:20']`
  - `patient_consented`, `patient_understands_cost`, `patient_agreed_16_days` → `['nullable', 'boolean']`
  - `patient_signature` → `['nullable', 'string', 'max:255']`
  - `provider_npi` → `['nullable', 'string', 'max:20']`
- Include `messages()` and `attributes()`

---

### STEP 4 — ACTION CLASSES

Create in `app/Actions/RemoteMonitoring/`. Follow the Action pattern above exactly — extend `Action`, use `execute(array $data): array`, wrap in try/catch, log errors.

#### `CreatePatientIntakeAction`

Inside `execute(array $data): array`:
1. Extract validated data from `$data['data']`.
2. Compute `service_path` with this priority:
   - `has_multiple_conditions` → `'ccm'`
   - `has_copd_asthma` → `'rtm_resp'`
   - `has_chronic_pain` or `has_arthritis` → `'rtm_msk'`
   - `has_hypertension`, `has_diabetes`, or `has_heart_failure` → `'rpm'`
3. Create `PatientIntake` record including computed `service_path`.
4. If `medications` array is present and non-empty, use `$intake->medications()->createMany(...)`.
5. Wrap all DB writes in `DB::transaction()`.
6. Return `['success' => true, 'data' => $intake->load('medications')]`.

#### `CreatePhysicianOrderAction`

Inside `execute(array $data): array`:
1. Extract validated data from `$data['data']`.
2. Assemble `cpt_codes` from selected services:
   - `service_rpm` → `[99453, 99454, 99457]`
   - `service_rtm_msk` → `[98975, 98977, 98980]`
   - `service_rtm_resp` → `[98975, 98976, 98980]`
   - `service_ccm` → `[99490, 99439, 99491]`
   - Deduplicate with `array_unique(array_merge(...))`.
3. Set `provider_signed_at` to `now()`.
4. Create `PhysicianOrder` with assembled `cpt_codes`.
5. Load related `PatientIntake` to get `service_path`.
6. Create `MonitoringEnrollment` with `service_path` and `cpt_codes` from the order.
7. Update `PatientIntake` status to `'ordered'`.
8. Wrap all DB writes in `DB::transaction()`.
9. Return `['success' => true, 'data' => $order->load(['patientIntake', 'monitoringEnrollment'])]`.

---

### STEP 5 — CONTROLLERS

Create in `app/Http/Controllers/RemoteMonitoring/`. Follow the controller pattern above — use Splade Toasts, instantiate Actions with `(new Action)->execute([...])`, return Blade views. No business logic in controllers.

#### `PatientIntakeController`
- `store(StorePatientIntakeRequest $request)` → call `CreatePatientIntakeAction`, Toast on failure, redirect to physician order creation on success
- `show(PatientIntake $intake)` → load `['medications', 'physicianOrder']`, return view

#### `PhysicianOrderController`
- `store(StorePhysicianOrderRequest $request)` → call `CreatePhysicianOrderAction`, Toast on failure, redirect to order show on success
- `show(PhysicianOrder $order)` → load `['patientIntake', 'monitoringEnrollment']`, return view

---

### STEP 6 — ROUTES

Register in `routes/web.php` inside the same middleware group as existing Doctor and Staff routes. Use the same prefix and naming convention you find there. Example — adjust to match what already exists:

```php
Route::middleware(['auth', 'role:staff'])->prefix('remote-monitoring')->name('remote-monitoring.')->group(function () {
    Route::post('/intake', [PatientIntakeController::class, 'store'])->name('intake.store');
    Route::get('/intake/{intake}', [PatientIntakeController::class, 'show'])->name('intake.show');
});

Route::middleware(['auth', 'role:doctor'])->prefix('remote-monitoring')->name('remote-monitoring.')->group(function () {
    Route::post('/physician-order', [PhysicianOrderController::class, 'store'])->name('order.store');
    Route::get('/physician-order/{order}', [PhysicianOrderController::class, 'show'])->name('order.show');
});
```

---

### STEP 7 — VUE.JS VIEWS

Create in `resources/js/components/RemoteMonitoring/`. All components must use:
- **Options API** (`export default {}`) — not Composition API / `<script setup>`
- **`Splade.request(url, method, data)`** imported from `"../Splade"` (verify exact path from existing components) — not `this.$splade`, not Axios, not fetch
- **Splade native helpers** for errors and toasts: `Splade.hasValidationErrors()`, `Splade.validationErrors()`, `Splade.pushToast()`
- **Tailwind CSS** — matching the utility classes used in existing components
- **`errors: {}`** in `data()` for fallback/generic error display
- **`loading: false`** in `data()` for submit button state

---

#### 7.1 `PatientIntakeForm.vue` — Staff / Prospecting Form

```
props: { patientId: Number }
data(): { formData: { patient_id, has_hypertension, has_diabetes, has_heart_failure,
          has_chronic_pain, has_arthritis, has_copd_asthma, has_multiple_conditions,
          primary_goal, recent_hospitalization, medication_request_type,
          medication_request_reason, has_smartphone, willing_to_use_device,
          has_caregiver, medications: [] }, errors: {}, loading: false, submitted: false, savedIntakeId: null }
computed: { servicePath() — same priority logic as Action }
methods: { addMedication(), removeMedication(index), submitForm() }
```

**Section 1 — Condition & Symptom Screening**

Render as a table. Each row has the condition label, Yes radio, No radio, and a service path badge column (internal staff view only). Use `v-model` bound to the corresponding `has_*` boolean in `formData`.

| Condition | Yes | No | Service Path (Internal) |
|---|---|---|---|
| High Blood Pressure (Hypertension) | ○ | ○ | RPM (99454/99445) |
| Diabetes or High Blood Sugar | ○ | ○ | RPM (99454/99445) |
| Congestive Heart Failure / Heart Issues | ○ | ○ | RPM (99454/99445) |
| Chronic Back, Neck, or Joint Pain | ○ | ○ | RTM – MSK (98977) |
| Arthritis or Limited Mobility | ○ | ○ | RTM – MSK (98977) |
| COPD, Asthma, or Shortness of Breath | ○ | ○ | RTM – Resp (98976) |
| 2 or more of the above? | ○ | ○ | CCM (99490) |

Below the table show a reactive badge: `"This patient qualifies for: {{ servicePath }}"` — hidden if `servicePath` is null.

**Section 2 — Medication Reconciliation**

Dynamic rows using `addMedication()` / `removeMedication(index)` — same pattern as `GeneralMedicalQuestionForm.vue`. Each row: Name, Dosage, Frequency, Purpose inputs. Add Medication / Remove buttons styled consistently with existing components.

Below rows: radio group for `medication_request_type` (Refill / New Medication / None). Textarea for `medication_request_reason` shown only when type is not `'none'` (use `v-if`).

**Section 3 — Tech & Support Qualification**

Three Yes/No radio groups for `has_smartphone`, `willing_to_use_device`, `has_caregiver`.

**Section 4 — Primary Goal & Hospitalization**

Text input for `primary_goal`. Yes/No radio for `recent_hospitalization`.

**Submit behavior**: `submitForm()` calls `Splade.request('/remote-monitoring/intake', 'POST', this.formData)`. On resolution, check `Splade.hasValidationErrors()` first. On success, set `submitted = true` and `savedIntakeId` from the flash data or response. Show a success panel with a "Send to Doctor" button that navigates to the physician order form route passing `savedIntakeId`.

Display `errors.general` and per-field errors below each field using `v-if="errors.fieldName"`.

---

#### 7.2 `PhysicianOrderForm.vue` — Doctor Order Form

```
props: { intakeId: Number }
data(): { intake: null, formData: { patient_intake_id, service_rpm, service_rtm_msk,
          service_rtm_resp, service_ccm, goal_stabilize_vitals, goal_therapy_adherence,
          goal_medication_management, goal_care_coordination, clinical_goal_notes,
          primary_diagnosis_icd10, patient_consented, patient_understands_cost,
          patient_agreed_16_days, patient_signature, provider_npi, provider_name },
          errors: {}, loading: false, submitted: false, finalCptCodes: [] }
computed: { dynamicCptCodes() — assembles and deduplicates CPT codes from checked services, same logic as Action }
mounted(): fetch intake via Splade.request('/remote-monitoring/intake/' + this.intakeId, 'GET') and store result in this.intake to pre-fill patient info
methods: { submitForm() — calls Splade.request('/remote-monitoring/physician-order', 'POST', this.formData), checks Splade.hasValidationErrors() on resolution }
```

**Header (read-only)**: Patient Name, DOB, Date — populated from `intake` object after mount.

**Section 1 — Clinical Indications & Service Selection**

Multi-select checkboxes (`v-model` on each `service_*` boolean). Below the table, show a live-updating CPT Code Summary box driven by `dynamicCptCodes` computed property:

| ☐ | Service Path | Qualifying Diagnosis | CPT Codes |
|---|---|---|---|
| ☐ | RPM (Physiological) | Hypertension, CHF, Diabetes | 99453, 99454, 99457 |
| ☐ | RTM (Musculoskeletal) | Chronic Pain, Arthritis, Mobility | 98975, 98977, 98980 |
| ☐ | RTM (Respiratory) | COPD, Asthma, Bronchitis | 98975, 98976, 98980 |
| ☐ | CCM (Chronic Care) | 2+ Chronic Conditions | 99490, 99439, 99491 |

**Section 2 — Medical Necessity & Plan of Care**

Checkboxes for each `goal_*` boolean. Textarea for `clinical_goal_notes`. Text input for `primary_diagnosis_icd10`.

**Section 3 — Patient Consent & Attestation**

Pre-filled from the `intake` record where applicable. Each item is a checkbox the doctor confirms:
- ☐ Patient consents to remote monitoring and use of a digital medical device/app
- ☐ Patient understands data will be transmitted electronically to this clinic
- ☐ Patient is aware that standard co-pays and deductibles apply monthly
- ☐ Patient agrees to use the device/app for **at least 16 days per month** (required for RTM/RPM billing)

Patient/Guardian Signature text input + Date.

**Section 4 — Provider Authorization**

Render this legal text verbatim in a styled blockquote — do not alter or paraphrase it:

> *"I hereby order the Remote Care Services checked above. I certify that this patient is under my care and that these services are integral to the treatment of their chronic condition(s). This order remains valid until the patient is discharged from the program or clinical goals are achieved."*

Provider Signature text input, NPI Number, Printed Name, Date.

On success, set `submitted = true` and show a confirmation panel displaying the final assigned CPT codes from the response.

---

#### 7.3 `StaffQualificationSummary.vue` — Read-Only Summary Component

```
props: { intake: Object }
computed: { activeRows() — returns which rows apply based on intake booleans }
```

Renders a reference table. Rows that apply to the current patient (based on `intake` prop) are highlighted with a colored background; rows that don't apply are dimmed with reduced opacity. No HTTP calls — purely presentational.

| If Staff Checked... | Doctor Should Order... | Primary Billing Codes (2026) |
|---|---|---|
| 2+ conditions | CCM | 99490 (20 min management) |
| Vitals tracking (HTN / DM / CHF) | RPM | 99454 (16+ days) or 99445 (2–15 days) |
| Pain or Respiratory | RTM | 98977 (MSK) or 98976 (Resp) |
| Medication Request | Care Plan Update | Document in CCM or RTM Adherence |

---

### STEP 8 — CONSTRAINTS & RULES

1. **No duplication.** If a column, model, Form Request, Action, or route already exists, reuse it.
2. **Actions are called with `(new Action)->execute([...])`** — not injected into controller constructors.
3. **No inline validation.** Never use `$request->validate()` in a controller. All validation lives in Form Request classes.
4. **Actions use `execute(array $data): array`** and always return `['success' => bool, ...]`.
5. **Actions wrap all DB writes in `DB::transaction()`** and catch exceptions with `Log::error()`.
6. **Controllers use Splade Toasts** (`Toast::danger()`, `Toast::success()`) and return Blade views — not JSON responses.
7. **Vue uses `Splade.request()`** — import `Splade` from the same relative path used in existing components. Do not use `this.$splade`, Axios, fetch, or Inertia. Use `Splade.hasValidationErrors()` and `Splade.validationErrors()` for server-side validation errors. Use `Splade.pushToast()` for client-side toast notifications.
8. **Vue uses Options API** — not Composition API / `<script setup>`.
9. **Tailwind CSS only** — no inline styles, no other CSS frameworks.
10. **CPT auto-assignment.** `CreatePhysicianOrderAction` must assemble and deduplicate CPT codes before saving.
11. **Verbatim legal text.** The physician order form must display the exact authorization text from Section 7.2. Do not paraphrase it.
12. **16-day rule.** Patient consent must explicitly record agreement to the 16-day/month device usage requirement — required for CMS billing compliance.

---

### DELIVERABLES CHECKLIST

- [ ] All 4 migrations created with no conflicts
- [ ] All 4 models with correct `$fillable`, boolean/array casts, and relationships
- [ ] `StorePatientIntakeRequest` — role-gated to `staff`, array rule syntax, `messages()`, `attributes()`
- [ ] `StorePhysicianOrderRequest` — role-gated to `doctor`, array rule syntax, `messages()`, `attributes()`
- [ ] `CreatePatientIntakeAction` — extends `Action`, `execute()`, try/catch, `DB::transaction()`, returns `['success' => ...]`
- [ ] `CreatePhysicianOrderAction` — extends `Action`, `execute()`, try/catch, `DB::transaction()`, CPT deduplication, returns `['success' => ...]`
- [ ] Both controllers are thin, use `(new Action)->execute()`, use Splade Toasts, return Blade views
- [ ] Routes registered with correct middleware and naming convention
- [ ] `PatientIntakeForm.vue` — Options API, `$splade.request()`, Tailwind, reactive `servicePath` badge, dynamic medication rows, success state with "Send to Doctor" button
- [ ] `PhysicianOrderForm.vue` — Options API, `$splade.request()`, pre-fills from intake on mount, live CPT summary, verbatim legal text, success confirmation
- [ ] `StaffQualificationSummary.vue` — purely presentational, highlights applicable rows
- [ ] No existing code duplicated
