# FlowRise HMS - Agent Knowledge Base

**Last Updated:** July 17, 2026  
**Session:** Documentation alignment re-audit — Inventory Complete (reorder alerts), count refresh, Api module documented  
**Last Update By:** Codebase verification against `modules_statuses.json` and module trees  
**Purpose:** Comprehensive reference for all agents working on FlowRise HMS project

---

## Table of Contents

1. [Project Overview](#project-overview)
2. [Module Status](#module-status)
3. [Architecture Patterns](#architecture-patterns)
4. [Key Decisions](#key-decisions)
5. [Code Patterns](#code-patterns)
6. [Critical File Paths](#critical-file-paths)
7. [Session Progress](#session-progress)
8. [Implementation Guidelines](#implementation-guidelines)

---

## Project Overview

**FlowRise HMS** is a Healthcare Management System built with:
- **Framework:** Laravel 13.x (Filament 5.x admin panel)
- **Language:** PHP 8.4+
- **Architecture:** Modular (using Laravel modules)
- **Key Modules:** Core, Patient, Staff, Clinical, Appointment, Billing, Pharmacy, Insurance, Diagnostics, Inventory, FHIR, AI, Website, Api
- **Canonical status:** [Module Status](shared/module-status.md)

### Business Context

The system handles:
- Patient registration and management
- Clinical encounters (OPD, Emergency, Inpatient)
- Vital signs recording and tracking
- Clinical documentation (SOAP notes, procedure notes)
- Service requests (lab orders, radiology, medications)
- Task management for order fulfillment
- Appointment scheduling, waitlists, and calendar workflows
- Diagnostics fulfillment, result templates, reports, files, and imaging support

---

## Module Status

| Module | Status | Description |
|--------|--------|-------------|
| **Core** | ✅ Complete | Foundation, authentication, base models, DTOs (4), Form Requests (6), enums standardized |
| **Patient** | ✅ Complete | Patient registration, identifiers, contacts, DTOs (1), Form Requests (3), school mgmt |
| **Staff** | ✅ Complete | Staff management, roles, permissions, credentials, ModuleServiceProvider migration |
| **Clinical** | ✅ Complete | Encounters, allergies, vitals, notes, orders, tasks, ADT location events, MAR (board, dose reminders, service, widget, relation manager, flow tests), DTOs (2), Form Requests (3) — 22 test files |
| **Appointments** | ✅ Complete | Scheduling, waitlist, calendar, sync outbox, Form Requests (3), factory coverage complete — 8 test files |
| **Billing** | ✅ Complete | Invoices, payments, deposits, payment plans, gateways, Billing Desk, refunds/write-offs, overdue scheduler, appointment check-in auto-invoice — `PatientFinancialHoldService` exists; no dedicated Filament hold resource — 35 test files |
| **Diagnostics** | ✅ Complete | Fulfillment bridge, catalog, templates, structured observations, panels, lab printing — HL7/FHIR export deferred — 16 test files |
| **Pharmacy** | ✅ Complete | Medications, stock, dispensing, POS, prescription slip — Form Requests (2) — 17 test files |
| **Insurance** | ✅ Complete | Multi-payer policies, claims, NHIS batch export, reconciliation — PatientPolicy/TariffItem models exist; dedicated Filament resources and NHIS catalog sync connector placeholder deferred — 12 test files |
| **Inventory** | ✅ Complete | Stock ledger with lot/FEFO, PO, requisitions, transfers, 7 Filament resources, analytics report, PDFs, Pharmacy bridge, auto-reorder draft PO, scheduled reorder alerts — 21 test files |
| **FHIR** | 🟡 In Progress | Patient/Practitioner/PractitionerRole CRUD; read/search for Organization, Location, HealthcareService, Encounter, Condition, AllergyIntolerance, Observation, Appointment, AppointmentResponse, InventoryItem; SMART/bulk export planned — 9 test files |
| **AI** | ✅ Complete | FlowRise assistant widget, agents, Reverb token streaming, documentation copilot — 12 test files |
| **Website** | ✅ Complete | Public CMS (pages, news, gallery, team, partners, menus), hybrid online booking, booking-request inbox — 8 Filament resources, 10 test files |
| **Api** | 🟡 In Progress | Sanctum token auth (`/api/v1/auth/login|logout`) + Scribe docs tooling; domain REST resources beyond auth not yet implemented — 1 test file |

---

## Architecture Patterns

### 1. Service Layer Pattern

All data operations MUST go through Service classes, NEVER direct Model operations.

```php
// ✅ CORRECT - Use Service
$service->record($patient, $data, $encounterId);

// ❌ WRONG - Don't use Model directly
Model::create($data);
```

**Existing Services:**
- `AllergyService` - Allergy recording
- `VitalSignService` - Vital signs recording (has `record()` method)
- `ClinicalNoteService` - Clinical notes (has `record()` method)
- `ServiceRequestService` - Service requests (has `record()` method)
- `TaskService` - Task management
- `EncounterService` - Encounter management (has `createForPatient()` method)

### 2. Form Schema Pattern

Forms have TWO methods for dual context support:

| Method | Purpose | Context |
|--------|---------|---------|
| `configure()` | Full form with patient/encounter Select fields | Normal resource pages |
| `quickElements()` | Data fields only (no patient/encounter fields) | SlideOver in patient context |

```php
// In form class
class VitalSignForm {
    public static function configure(Schema $schema): Schema {
        return $schema->components(array_merge([
            // Patient/encounter Select fields here
            Select::make('patient_id')->relationship('patient', 'mrn'),
            Select::make('encounter_id')->relationship('encounter', 'encounter_number'),
        ], self::quickElements()));
    }
    
    public static function quickElements() {
        return [
            // Only vital sign data fields - NO patient/encounter fields
            TextInput::make('systolic_bp'),
            TextInput::make('diastolic_bp'),
            // ...
        ];
    }
}
```

### 2b. Billing Filament Resource Schema Pattern

**Clinical** forms use `configure()` + `quickElements()` for patient-context slideOvers. **Billing** resources use a different but equally strict layout: thin resources/pages, schema classes per concern.

| Layer | Responsibility |
|-------|----------------|
| `{Resource}Resource` | Delegates `form()`, `infolist()`, `table()` only |
| `Schemas/{Resource}Form.php` | `configure()`; optional partial methods (e.g. `planFields()`, `collectInstallmentFields()`) for relation managers and header actions |
| `Schemas/{Resource}Infolist.php` | `configure()` for view pages |
| `Tables/{Resource}Table.php` | `configure()` plus `columns()` / `recordActions()` for reuse |
| `Pages/` | `handleRecordCreation()`, header actions, redirects — **no inline form/infolist schemas** |
| `app/Filament/Schemas/` | Shared modal form components for non-resource actions (deposits) |
| `app/Filament/Actions/` | Wire schema components to services |

```php
// Resource delegates — see InvoiceResource, PaymentPlanResource, PaymentResource
public static function form(Schema $schema): Schema
{
    return PaymentPlanForm::configure($schema);
}

public static function infolist(Schema $schema): Schema
{
    return PaymentPlanInfolist::configure($schema);
}

public static function table(Table $table): Table
{
    return PaymentPlansTable::configure($table);
}
```

```php
// Relation manager reuses partial APIs — no duplicated field definitions
CreateAction::make()->form(PaymentPlanForm::planFields())
$table->columns(PaymentPlansTable::columns())
```

```php
// Modal action reuses shared schema
->schema(fn () => RecordDepositForm::components($patientId))
```

**Canonical reference:** `Modules/Billing/app/Filament/Clusters/Billing/Resources/Invoices/`

**Do not:** put form/infolist field arrays on `ViewRecord` pages, duplicate columns in relation managers, or call `PaymentPlan::create()` / `PatientDeposit::create()` from Filament pages — use `PaymentPlanService`, `DepositRecordingService`, `DepositApplicationService`, `PaymentRecordingService`.

### 2c. Client identity (patient or guest)

Walk-ins store `guest_name`, `guest_phone`, and `guest_email` when `patient_id` is null on **Encounter**, **ServiceRequest**, and **Invoice**. Output surfaces label the subject **Client** (not Patient).

**Resolution order:** registered patient name/MRN → guest name/phone/email → `N/A`.

| Artifact | Path |
|----------|------|
| `ClientIdentity` DTO | `Modules/Core/app/Support/ClientIdentity.php` |
| `ClientIdentityResolver` | `Modules/Core/app/Support/ClientIdentityResolver.php` |
| `ProvidesClientIdentity` | `Modules/Core/app/Contracts/ProvidesClientIdentity.php` |
| Print partial | `Modules/Core/resources/views/print/partials/client-identity.blade.php` |
| Filament column | `Modules/Core/app/Filament/Support/ClientIdentityColumn.php` |

Models implementing `clientIdentity()`: `Invoice`, `Payment`, `Encounter`, `ServiceRequest`, `Task` (via service request chain).

```php
$invoice->clientIdentity()->displayWithIdentifier(); // "Jane Doe (MRN-1)" or "Walk-in (+233...)"
@include('core::print.partials.client-identity', ['client' => $invoice->clientIdentity()])
ClientIdentityColumn::make(); // Filament tables
```

### 3. PatientActions Class Pattern

Located at: `Modules/Clinical/app/Classes/Actions/PatientActions.php`

Provides reusable actions for patient context (PatientProfile, Timeline pages).

**Key Methods:**
- `vitals()` - Record vitals action
- `note()` - Add clinical note action  
- `order()` - Create service request action
- `encounter()` - Create encounter action
- `allergy()` - Record allergy action

**Critical Implementation Details:**

```php
Action::make('vitals')
    ->label('Record Vitals')
    ->icon('heroicon-m-heart')
    ->model(VitalSign::class)
    ->slideOver()
    ->schema(fn ($schema) => VitalSignForm::quickElements())  // Use quickElements!
    ->mutateDataUsing(fn (array $data): array => $this->injectVitalSignData($data))  // NOT mutateFormDataUsing
    ->action(fn (array $data) => $this->vitalSignService->record($this->patient, $data, $this->encounterId))
    ->successNotificationTitle('Vital signs recorded');
```

**Data Injection Methods:**
- `injectVitalSignData()` - Adds patient_id, encounter_id, recorded_by, recorded_at
- `injectClinicalNoteData()` - Adds patient_id, encounter_id, author_id
- `injectServiceRequestData()` - Adds patient_id, encounter_id, ordered_by, created_by
- `injectEncounterData()` - Adds patient_id, branch_id, created_by
- `injectAllergyData()` - Adds patient_id, verified_by

---

## Key Decisions

### 1. Form Fields in Patient Context

**Decision:** Forms keep VISIBLE Select fields for patient_id and encounter_id (NOT Hidden fields)

**Rationale:**
- Works in BOTH normal context (manual selection) AND patient context (fields injected via `mutateDataUsing()`)
- PatientProfile = patient's medical dossier
- Timeline = patient's care journey
- `quickElements()` filters these fields at schema level for slideOver contexts

### 2. PatientProfile vs Timeline

| Page | Purpose |
|------|---------|
| **PatientProfile** | Patient's medical dossier - consolidated view of all clinical data |
| **Timeline** | Patient's care journey - chronological history of encounters, notes, vitals, orders |

**Note:** Consider moving sub-navigation from Timeline to PatientProfile after Timeline improvements

### 3. Task Definition

**Business Definition:** A Task represents the execution/fulfillment of a specific service item ordered for a patient.

**Hierarchy:**
```
ServiceRequest (order)
  └── RequestItem (service being ordered)
        └── Task (actual execution)
```

**Workflow:**
1. Doctor creates ServiceRequest with RequestItems
2. Staff picks up task → starts (status: in_progress)
3. Staff completes task → (status: completed, outcome recorded)

### 4. Data Mutating

**Use:** `mutateDataUsing()` (NOT `mutateFormDataUsing()`)

This is a Filament-specific method for modifying data before it's passed to the action.

---

## Code Patterns

### Schema Callback Pattern

```php
->schema(fn ($schema) => VitalSignForm::configure($schema))
```

Always use schema callback with `configure()` or `quickElements()`.

### HasPatientContext Trait

Pages that need patient awareness should use the `HasPatientContext` trait.

Located at: `Modules/Clinical/app/Filament/Clusters/Workspace/Traits/HasPatientContext.php`

### Clinical Workspace Structure

```
Workspace Cluster
├── PatientProfile (patient's medical dossier)
├── Timeline (chronological care journey)
├── Vitals (vital signs page)
├── Notes (clinical notes page)
└── Orders (service requests page)
```

### Resource Hierarchy

```
Clinical
├── Encounter (visit)
│   ├── VitalSign (multiple per encounter)
│   ├── ClinicalNote (documentation)
│   ├── ServiceRequest (orders)
│   │   └── RequestItem (services ordered)
│   │       └── Task (fulfillment tracking)
│   └── EncounterParticipant (staff involved)
└── Allergy
```

---

## Critical File Paths

### Clinical Module

| File | Purpose |
|------|---------|
| `Modules/Clinical/app/Classes/Actions/PatientActions.php` | Reusable actions for patient context |
| `Modules/Clinical/app/Classes/Services/VitalSignService.php` | Vital signs operations |
| `Modules/Clinical/app/Classes/Services/ClinicalNoteService.php` | Clinical notes operations |
| `Modules/Clinical/app/Classes/Services/ServiceRequestService.php` | Service requests operations |
| `Modules/Clinical/app/Classes/Services/ClinicalWorkspaceService.php` | Workspace data operations |
| `Modules/Clinical/app/Filament/Clusters/Clinical/Resources/VitalSigns/Schemas/VitalSignForm.php` | VitalSign form schema |
| `Modules/Clinical/app/Filament/Clusters/Clinical/Resources/ClinicalNotes/Schemas/ClinicalNoteForm.php` | ClinicalNote form schema |
| `Modules/Clinical/app/Filament/Clusters/Clinical/Resources/ServiceRequests/Schemas/ServiceRequestForm.php` | ServiceRequest form schema |
| `Modules/Clinical/app/Filament/Clusters/Workspace/Pages/Timeline.php` | Timeline page |
| `Modules/Clinical/app/Filament/Clusters/Workspace/Pages/PatientProfile.php` | PatientProfile page |
| `Modules/Clinical/resources/views/filament/clinical/workspace/pages/timeline.blade.php` | Timeline view |

### Patient Module

| File | Purpose |
|------|---------|
| `Modules/Patient/app/Models/Patient.php` | Patient model |
| `Modules/Patient/docs/IMPLEMENTATION_PLAN.md` | Patient module plan |

### Staff Module

| File | Purpose |
|------|---------|
| `Modules/Staff/docs/IMPLEMENTATION_PLAN.md` | Staff module plan |

### Billing Module

| File | Purpose |
|------|---------|
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/Invoices/InvoiceResource.php` | Canonical Filament resource (delegates to Schemas/Tables) |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/Invoices/Schemas/InvoiceForm.php` | Invoice form schema |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/Invoices/Schemas/InvoiceInfolist.php` | Invoice view schema |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/Invoices/Tables/InvoicesTable.php` | Invoice list table |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/PaymentPlans/PaymentPlanResource.php` | Payment plan resource |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/PaymentPlans/Schemas/PaymentPlanForm.php` | Plan form + `planFields()`, `collectInstallmentFields()` |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/PaymentPlans/Schemas/PaymentPlanInfolist.php` | Plan view schema |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/PaymentPlans/Tables/PaymentPlansTable.php` | Plan list columns |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/Payments/Schemas/PaymentInfolist.php` | Payment view schema |
| `Modules/Billing/app/Filament/Clusters/Billing/Resources/Payments/Tables/PaymentsTable.php` | Payment list columns + record actions |
| `Modules/Billing/app/Filament/Schemas/RecordDepositForm.php` | Record deposit modal fields |
| `Modules/Billing/app/Filament/Schemas/ApplyDepositForm.php` | Apply deposit modal fields |
| `Modules/Billing/app/Filament/Actions/RecordDepositAction.php` | Record deposit header/modal action |
| `Modules/Billing/app/Filament/Actions/ApplyDepositAction.php` | Apply deposit to invoice |
| `Modules/Billing/app/Services/PaymentPlanService.php` | Create/collect/cancel payment plans |
| `Modules/Billing/app/Services/DepositRecordingService.php` | Record patient deposits |
| `Modules/Billing/app/Services/DepositApplicationService.php` | Apply deposit credit to invoices |

---

## Session Progress

### Completed Tasks

1. ✅ Created `PatientActions` class with `vitals()`, `note()`, `order()`, `encounter()`, `allergy()` methods
2. ✅ Updated `VitalSignForm` - visible Select fields + `quickElements()` method
3. ✅ Updated `ClinicalNoteForm` - visible Select fields + `quickElements()` method
4. ✅ Updated `ServiceRequestForm` - visible Select fields (removed Hidden fields)
5. ✅ Added `ClinicalNoteService.record()` method
6. ✅ Added `ServiceRequestService.record()` method
7. ✅ Verified all PHP files compile without errors
8. ✅ Created Patient module IMPLEMENTATION_PLAN.md
9. ✅ Created Staff module IMPLEMENTATION_PLAN.md
10. ✅ Created Clinical module implementation plan
11. ✅ Created documentation review agent prompt
12. ✅ Moved clinical-module-implementation-plan.md to `Modules/Clinical/docs/`
13. ✅ Timeline chronological display implemented
14. ✅ Patient/encounter field filtering works via `quickElements()`
15. ✅ **Sprint 1: Dependency & infrastructure** — Staff dependencies, phpstan.neon.dist, CI pipeline, phpunit.xml cleanup
16. ✅ **Sprint 2: Form Requests & DTOs** — 26 Form Requests, 7 DTOs across Core/Patient/Clinical/Appointment/Billing/Diagnostics/Insurance/Pharmacy/Staff
17. ✅ **Sprint 3: Factory expansion** — 22 new factories (Appointment 7, Billing 7, Insurance 8), HasFactory on all Billing/Insurance models
18. ✅ **Sprint 4: Tests** — 17 new test files: DTO tests, factory smoke tests, model/feature tests across all modules
19. ✅ **Sprint 5: Architecture cleanup** — `values()` on all enums, HasColor/HasDescription standardized, StaffServiceProvider → ModuleServiceProvider, BaseModel import fix, Patient/Billing/Insurance module.json fixes
20. ✅ **Sprint 6: Production polish** — PHPStan 0 errors (baseline 444), composer lint script, CI pipeline fixed
21. ✅ **Post-review gap fixes** — Added `requires` to Billing/Diagnostics/Insurance module.json, fixed Pharmacy DispenseFulfillmentType enum, removed empty Clinical/Schemas dir, updated roadmap.md + this doc
22. ✅ **Billing Filament schema refactor** — Payment plans, payments, and deposit actions aligned to Invoice pattern (`Schemas/`, `Tables/`, thin pages); user/admin guides and module README updated

### Current Status

- **PHPStan:** Level 1, 0 errors (baseline captures 444 pre-existing dynamic Laravel issues)
- **Factories:** 61 total across all modules (93% model coverage)
- **Form Requests:** 26 across 8 modules (unwired controllers remain)
- **DTOs:** 7 readonly classes with fromArray/toArray pattern
- **Tests:** ~217 test files, 1,350+ automated tests across root app and all 13 enabled modules
- **CI:** Full pipeline — syntax check → migrations → tests → PHPStan → frontend build → deploy

### Remaining Work

1. None currently outstanding. 3 FormRequests wired (AppointmentRequest, PatientRequest, WaitlistEntryRequest); remaining 23 are available for future API controller development.
2. Factory coverage at 95%+ across all modules.
3. CoreUser (abstract) and DepartmentLocation (Pivot) intentionally lack factories — standard Laravel conventions.
4. Diagnostics Unit test and Staff feature test added.
5. Pharmacy enums fully standardized (HasDescription added to MedicationFrequency, MedicationRoute; HasLabel added to DispenseFulfillmentType).

---

## Implementation Guidelines

## Roles and Permissions

### Source of Truth: `UserRole` Enum

All Shield roles are defined in `Modules/Core/app/Enums/UserRole.php`. This is the **single source of truth** for authorization roles AND staff position metadata.

**Key principle:** `UserRole` = who can do what + what profession you are. There is no separate `StaffRole` enum - it was removed.

**48 Shield Roles** defined across these categories:

| Category | Roles | Permissions |
|----------|-------|-------------|
| **Admin** | super_admin (64), system_admin (29), facility_admin (29) | Full system access |
| **Clinical** | doctor, physician, specialist, consultant, clinical_officer, clinical_associate, physician_assistant (27 each) | Patient, Vitals, Notes, Orders, Encounters, Allergies, Appointments |
| **Nursing** | nurse, registered_nurse, practice_nurse, nursing_student (20 each) | Patient read, Vitals, Notes, Allergies |
| **Pharmacy** | pharmacist, pharmacy_technician (7 each) | Patient read, ServiceRequests |
| **Lab** | laboratory_technician, laboratory_scientist (7), pathologist (27) | Patient read, ServiceRequests |
| **Reception** | receptionist, registration_clerk, medical_receptionist (12 each) | Patient CRUD, Appointments |
| **Billing** | billing_clerk, medical_biller, finance_officer (7 each) | Patient read, Invoices, Payments |
| **Ward** | ward_clerk, admissions_staff (9 each) | Patient read, Encounters |
| **Support** | case_manager, social_worker (9 each) | Patient read, Encounters, Notes |
| **IT** | it_admin, database_admin (29 each) | System config, all resources |
| **Ancillary** | radiologist (27), radiology_technician, physiotherapist, occupational_therapist, speech_therapist, dietician (7 each) | Patient read, ServiceRequests |
| **Management** | department_head, medical_director (27), nursing_supervisor (20), operations_manager, quality_officer, compliance_officer (18 each) | Oversight + department data |
| **External** | guest_user, trainee, volunteer, medical_student (1 each) | Minimal read-only |

### Seeder Order

```
DatabaseSeeder
├── ShieldSeeder (super_admin - hardcoded Shield format)
├── ShieldRoleSeeder (iterates UserRole enum - 47 roles)
├── BillingShieldPermissionsSeeder (billing-specific Shield permissions)
├── StaffCustomPermissionSeeder* (print_staff_id)
├── PatientCustomPermissionSeeder* (print_hospital_card, discharge_patient, view_patient_balance)
├── BillingCustomPermissionSeeder* (invoice/receipt permissions)
└── UserSeeder
```

*Custom permission seeders run inside their module's DatabaseSeeder, called from StaffDatabaseSeeder etc.

### How Permissions Work

Each `UserRole` case has a `permissions()` method that returns the appropriate permission array based on role family:

```php
public function permissions(): array
{
    return match (true) {
        $this->isMedicalDoctor() => self::clinicalProviderPermissions(),
        $this->isNursing()       => self::nursingPermissions(),
        $this->isReception()     => self::receptionPermissions(),
        // ...
        default                  => self::basePermissions(),
    };
}
```

Permission families are static methods on the enum:
- `fullAccessPermissions()` - All CRUD on all resources
- `clinicalProviderPermissions()` - Patient + clinical + appointments
- `nursingPermissions()` - Patient read, vitals, notes
- `receptionPermissions()` - Patient CRUD, appointments
- `billingPermissions()` - Invoices, payments
- `basePermissions()` - View MyProfilePage
- etc.

### Adding a New Role

1. Add a case to `UserRole` enum
2. Add label/description/color in the match methods
3. Add to the relevant helper method (e.g., `isMedicalDoctor()`) or create a new one
4. Create a permission family method or reuse an existing one
5. The `ShieldRoleSeeder` automatically picks up the new case - no seeder changes needed

### Helper Methods

`UserRole` provides classification helpers:

| Method | Purpose |
|--------|---------|
| `isMedicalDoctor()` | Licensed clinical practitioners |
| `isNursing()` | Nursing staff |
| `isPharmacyLab()` | Pharmacy and laboratory roles |
| `isAlliedHealth()` | Allied health practitioners |
| `isAdministrative()` | Admin/reception/billing/ward roles |
| `isManagement()` | Department heads, directors, supervisors |
| `isClinical()` | Medical doctor OR nursing |
| `isBillingFinance()` | Billing-specific roles |
| `isReception()` | Front-desk roles |
| `isAncillary()` | Radiology, therapy, nutrition |
| `isExternal()` | Students, guests, volunteers |
| `requiresLicense()` | Roles requiring professional licensure |

### For New Agents Starting Work

1. **Read this file first** - Understand the architecture and patterns
2. **Check Module Status** - Know what's complete vs planned
3. **Follow Service Pattern** - Never use `Model::create()` directly
4. **Use Schema Callbacks** - `->schema(fn ($schema) => Form::configure($schema))`
5. **Use mutateDataUsing()** - NOT `mutateFormDataUsing()`
6. **Dual Context Forms** — Clinical: `configure()` AND `quickElements()`. Billing: `configure()` plus partial field methods (`planFields()`, etc.) for relation managers; shared modal schemas under `Filament/Schemas/`
7. **Billing Filament** — Resources delegate to `Schemas/*` and `Tables/*`; pages hold actions/mutations only (see §2b)
8. **Patient Context** - Use `PatientActions` class for patient-related actions
9. **Documentation** - Update relevant IMPLEMENTATION_PLAN.md files in module docs; keep `docs/user-guide/`, `docs/admin-guide/`, and `docs/shared/module-status.md` aligned with implementation

### Extension Points (by module)

**Insurance (in progress):** claim generation, payer admin UI, connector coverage — see [module status](shared/module-status.md).

**Deferred globally:** FHIR/HL7 interoperability exports.

### Code Style Rules

1. **No comments unless asked** - Keep code clean
2. **Follow existing conventions** - Check neighboring files
3. **Use existing libraries** - Never assume a library is available
4. **Security first** - Never expose secrets or keys
5. **Verify before committing** - Run lint and typecheck commands

### Verification Commands

Before completing work:
```bash
# Full test suite (sequential ~10 min)
./vendor/bin/pest --colors=never

# Parallel CI-style run (requires _test or _test_N database names)
./vendor/bin/pest --parallel --colors=never

# Per-module triage
./vendor/bin/pest Modules/Clinical --colors=never

# Code style
./vendor/bin/pint
php artisan route:cache
composer dump-autoload
php -l path/to/file.php
```

### Test Conventions (Module Tests)

All module feature/unit tests should use this setup pattern:

```php
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    use DatabaseTransactions;

    protected function setUp(): void
    {
        parent::setUp();
        $this->migrateModules(['Core', 'Patient']); // list modules under test
    }
}
```

**Rules:**
- Use `DatabaseTransactions` + `$this->migrateModules([...])` — not `RefreshDatabase` or manual `module:migrate` loops.
- `tests/TestCase.php` runs `migrate:fresh` + `module:migrate --all` once per PHP process; parallel workers use databases matching `/_test(?:_\d+)?$/`.
- `activity_log.attribute_changes` lives in Core module migrations (after `activity_log` table creation). `TestCase::migrateModules()` also calls `ensureActivityLogAttributeChangesColumn()` after module migrations.
- For medication billing tests, use `$this->medicationServiceCategory()` instead of `ServiceCategory::factory()->create(['code' => 'MED'])`.
- For stable enum categories, use `$this->serviceCategory(['code' => ServiceCategoryCode::RAD->value])`.
- Hierarchical category tests: `ServiceCategory::query()->create([...])` with unique enum codes (codes are globally unique).
- Do **not** override `ServiceCategoryFactory::create()` with blanket `firstOrCreate` — it breaks Factory `sequence()` and parent/child tests. Root-only `firstOrCreate` in the factory is OK when `parent_id` is absent.
- Prefer `createStub()` over `createMock()` when no expectations are configured (avoids PHPUnit notices).
- Pass explicit `recordedBy` to `VitalSignService::record()` in tests (column is NOT NULL).
- Pass required allergy fields (`reaction`, `severity`, `onset_type`) when calling `AllergyService::record()`.

**Critical service tests added:**
- `Modules/Clinical/tests/Unit/Classes/Services/VitalSignServiceTest.php`
- `Modules/Clinical/tests/Unit/Classes/Services/AllergyServiceTest.php`
- `Modules/Insurance/tests/Unit/ClaimSubmissionServiceTest.php`
- `Modules/Diagnostics/tests/Unit/DiagnosticResultServiceTest.php`
- `Modules/Appointment/tests/Unit/AppointmentSchedulingServiceTest.php`

---

## Important Notes for Agents

### Critical Context Reminders

1. **Forms have visible Select fields** - Works in normal AND patient context
2. **patient_id, encounter_id, author_id, ordered_by** - Auto-populated via `mutateDataUsing()` in PatientActions
3. **quickElements()** - Returns elements WITHOUT patient/encounter fields (filtered at schema level)
4. **Service layer pattern** - `VitalSignService.record()`, `ClinicalNoteService.record()`, etc.
5. **Timeline = chronological** - Patient's care journey
6. **PatientProfile = dossier** - Patient's medical record

### Filament-Specific Patterns

- Use `->model()` to set target model for Filament actions
- Use `->slideOver()` for modal forms
- Use `->schema(fn ($schema) => ...)` for dynamic schemas
- Use `->mutateDataUsing()` for data injection
- Use `->action(fn () => ...)` for service calls

---

## Session History Summary

**Date:** April 2026  
**Focus:** Clinical Module Implementation

**Major Achievements:**
1. Built complete PatientActions system for patient context
2. Implemented dual-context form schemas (configure + quickElements)
3. Created service layer with record() methods
4. Built Timeline with chronological display
5. Established patterns for future modules
6. Created ShieldRoleSeeder with 13 operational Shield roles
7. Created comprehensive AGENT_KNOWLEDGE_BASE.md for cross-agent knowledge sharing

**Key Learning:** The dual-context form pattern (configure vs quickElements) allows forms to work seamlessly in both normal resource pages AND patient-specific contexts like PatientProfile/Timeline.

---

**End of Knowledge Base**

*For questions or updates to this document, refer to the session conversation history or create an issue in the project repository.*
