# Models: Prescription + PrescriptionItem

**Tables**: `clinic_prescriptions`, `clinic_prescription_items` (new, Phase 8)

## Purpose

Structured replacement for the free-text `prescription` column on the legacy
`clinic_medical_records`. One prescription per encounter, with one or more structured line items —
the source for both the patient-portal prescription view and the Phase 12 printable prescription.

## Fields — `clinic_prescriptions`

| Column | Type | Constraints | Notes |
|---|---|---|---|
| `id` | bigint | PK | |
| `encounter_id` | bigint | `foreignId('encounter_id')->constrained('clinic_encounters')->cascadeOnDelete()` unique | 1:1 with the encounter |
| `doctor_id` | bigint | `foreignId('doctor_id')->constrained('clinic_doctors')->restrictOnDelete()` | denormalized for print header/authorship display without a join through `encounter` |
| `notes` | text | nullable | general instructions not tied to a specific line item |
| `issued_at` | datetime | default `now()` | |
| `created_at` / `updated_at` | timestamp | | |

## Fields — `clinic_prescription_items`

| Column | Type | Constraints | Notes |
|---|---|---|---|
| `id` | bigint | PK | |
| `prescription_id` | bigint | `foreignId('prescription_id')->constrained('clinic_prescriptions')->cascadeOnDelete()` | |
| `medication_id` | bigint | `foreignId('medication_id')->nullable()->constrained('clinic_medications')->nullOnDelete()` | nullable — see `Medication.md` decision on free-text fallback |
| `medication_name_freetext` | string | nullable | used when `medication_id` is null |
| `dose` | string | | e.g. "500mg" |
| `frequency` | string | | e.g. "twice daily" |
| `duration_days` | unsignedSmallInteger | nullable | |
| `route` | string | nullable | oral / injection / topical / etc. |
| `instructions` | string | nullable | e.g. "after meals" |
| `sort_order` | unsignedSmallInteger | default `0` | print/display order |
| `created_at` / `updated_at` | timestamp | | |

## Relationships

| Relation | Type | Target |
|---|---|---|
| `Prescription::encounter()` | `belongsTo` | `Encounter` |
| `Prescription::doctor()` | `belongsTo` | `Doctor` |
| `Prescription::items()` | `hasMany` | `PrescriptionItem` |
| `PrescriptionItem::prescription()` | `belongsTo` | `Prescription` |
| `PrescriptionItem::medication()` | `belongsTo` | `Medication` |

## Decisions

- Split into a header + line-item pair (not one flat table) because a prescription routinely has
  multiple drugs — same "header + items" shape already used elsewhere in the ERP for any
  multi-line document (e.g. invoices), not a new pattern.
- `medication_id` nullable with a `medication_name_freetext` fallback keeps prescribing unblocked
  by catalog completeness (see `Medication.md`) while still preferring the structured FK when the
  drug exists in the catalog, for reporting purposes.
