# Documents

## Purpose

Staff needs a place to attach the paperwork tied to a patient — the signed contract, exam reports, therapy plans — and the patient needs to be able to read those documents, without being able to touch them.

This feature adds:

1. A **Documenti** card in the *Area Gestionale* section of the admin and company admin dashboards, opening a searchable, filterable document list where files can be uploaded, opened and deleted.
2. A **read-only** document list on the patient dashboard, with the same search and type filter: the patient (and whoever can view that patient) can find and open the files, nothing else.

## Document types

Types are **data, not code**: they live in the `document_types` table. A fresh install is seeded with `Contratto`, `Esami` and `Terapia` (`DocumentTypeSeeder`, list in `DocumentType::DEFAULT_TYPES`), and new ones are created straight from the upload form — picking *Nuova tipologia…* in the type select reveals a free-text field.

The name match is case insensitive (`DocumentType::findOrCreateByName`), so uploading with `contratto` reuses the existing `Contratto` instead of creating a near-duplicate.

Existing types are renamed or deleted from the **Tipologie** panel on the management list. Renaming carries every document of that type along — the association is by id, not by name. Deleting is refused while the type is still used by at least one document: the documents would be left without a category, and the foreign key would block it anyway. The panel shows each type's usage count and disables the delete button when it is not zero.

Creating a type lives in the upload form rather than in the panel, because that is where a missing type is actually noticed. Types are shared across companies, so a company admin renaming one changes it for everybody — same reach they already have when creating one.

## File storage

Files are stored on the **private** `local` disk under `documents/{user_id}/`, never under `public/`. They are only reachable through `GET /documents/{document}/file`, which authorizes the request and then streams the file inline (so PDFs and images open in the browser tab).

The record keeps both the **display name** (editable, defaults to the uploaded file name) and the untouched `original_name`, plus mime type and size. Deleting a document deletes its file too (`Document::booted`).

Accepted extensions (`Document::ALLOWED_EXTENSIONS`): `jpeg`, `jpg`, `png`, `pdf`, `doc`, `docx`. Max size 10 MB (`Document::MAX_SIZE_KB`).

## Visibility and permissions

| Action | Admin | Company admin | Medical operator | Patient |
|--------|-------|---------------|------------------|---------|
| Management list (`/documents`) | all | own company only | own patients only | ✗ |
| Open a file | ✓ | own company | own patients | own documents |
| Upload | ✓ | own company | ✗ | ✗ |
| Delete | ✓ | own company | ✗ | ✗ |

Scoping is done by `Document::scopeVisibleTo` (list) and `DocumentPolicy` (single document). Uploading and deleting are deliberately limited to admins and company admins: for everyone else these documents are read-only.

## Search and filter

Both lists filter on the server: `search` matches the document name, the original file name and the patient name/surname; `document_type_id` narrows to a single type. Search, type and page number travel together, so changing one does not reset the others.

On the patient list the type select only offers the types that patient actually has — filtering on a type with no documents would be a dead end. The management list offers every existing type.

## Routes

| Method | Path | Name | Who |
|--------|------|------|-----|
| GET | `/documents` | `admin-documents` | Admin / company admin / medical operator |
| POST | `/documents` | `documents.create` | Admin / company admin |
| GET | `/documents/{document}/file` | `documents.file` | Anyone who can view the document |
| DELETE | `/documents/{document}` | `admin-documents.delete` | Admin / company admin |
| GET | `/{patient}/documents` | `patient-documents` | Anyone who can view the patient |
| PUT | `/document-types/{documentType}` | `document-types.update` | Admin / company admin |
| DELETE | `/document-types/{documentType}` | `document-types.delete` | Admin / company admin |

## Notes / edge cases

- **Deleting a patient** cascades to their documents rows; the files on disk are removed by the model event only when the delete goes through Eloquent.
- **A type in use cannot disappear**: `documents.document_type_id` is a restricting foreign key, so a type referenced by a document cannot be deleted from the database. The controller checks first and answers with a validation message instead of letting the query blow up.
- **No update**: a document is uploaded or deleted, never edited — re-uploading is the way to correct a file.

## Related documentation

- [Business Logic](../business-logic.md) — patients, companies, roles
- [Audit Logs](./audit-logs.md) — documents and document types are audited
