feat(docs): add laser treatment plan and related ADRs for multi-session treatments
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# Treatment Sessions are separate from Appointments
|
||||
|
||||
Multi-session treatments (laser courses, botox top-ups) need a session that keeps its number and its
|
||||
clinical record across cancellations and reschedules, and they must not lock eight months of calendar
|
||||
slots the moment a course starts. So a Treatment Session is its own record owning the clinical data,
|
||||
holding an optional reference to an Appointment; booking a session creates the Appointment, and
|
||||
rescheduling swaps it without disturbing the session.
|
||||
|
||||
## Considered Options
|
||||
|
||||
Making the Appointment itself the session was rejected: session numbering would break on every
|
||||
cancellation, and pre-creating every future session as a real Appointment would occupy slots months
|
||||
ahead for patients who may never attend.
|
||||
@@ -0,0 +1,11 @@
|
||||
# A Treatment Case snapshots its areas
|
||||
|
||||
The areas a service covers are derived from the catalog category graph, which the clinic manager can
|
||||
edit at any time. Because a session's area records are a medical record, a Treatment Case copies its
|
||||
area list at creation and never re-derives it; editing the category graph afterwards affects only
|
||||
cases opened from then on.
|
||||
|
||||
## Consequences
|
||||
|
||||
An in-flight case will not pick up a category change. If a clinic genuinely needs that, it has to be
|
||||
an explicit re-sync action, not a silent side effect of editing settings.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Resource-backed appointments are guarded by occupancy, not the doctor slot key
|
||||
|
||||
An appointment's `active_slot_key` is `doctor_id:slot_start` under a unique index, which assumes the
|
||||
doctor is the thing being occupied. Once a doctor supervises several devices that assumption breaks:
|
||||
the second booking in the same hour on a different device is rejected. Resource occupancy already
|
||||
guards those bookings at the database level via `uniq_bucket_resource_seat (resource_id, bucket_at,
|
||||
seat)`, so an appointment that carries a resource leaves `active_slot_key` null and lets occupancy be
|
||||
the sole authority; only resourceless legacy bookings keep the doctor key.
|
||||
|
||||
## Considered Options
|
||||
|
||||
Rekeying on the resource (`r{resource_id}:{slot_start}`) was rejected because it silently defeats
|
||||
`ClinicResource.capacity`: a room seating three would reject its second patient, and the unique index
|
||||
knows nothing about seats, buffers, or setup and cleanup time.
|
||||
|
||||
## Consequences
|
||||
|
||||
Any booking path that omits the resource falls back to the doctor key. Those paths have to be found
|
||||
and made resource-aware, or they end up with weaker protection than they have today.
|
||||
@@ -0,0 +1,14 @@
|
||||
# Session parameters are JSON, described by the resource type
|
||||
|
||||
What an operator records for a treated area splits in two: facts every specialty shares — which
|
||||
resource, when it started and finished, the note — and readings that belong to one kind of device,
|
||||
like a laser's energy, pulse and shot count. The shared facts are real columns on the session's area
|
||||
record; the device-specific readings live in a `parameters` JSON column, and the field list that
|
||||
drives the form and its validation is declared on the resource type. Adding a dentistry or RF device
|
||||
is then a settings change, not a migration.
|
||||
|
||||
## Consequences
|
||||
|
||||
Aggregate reporting over a JSON key (average energy per area over a quarter) has no index behind it
|
||||
and will be slow. If such a report becomes a first-class requirement, the specific keys get promoted
|
||||
to real columns rather than the whole design being reversed.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Treatment workflows are tagged services, not a configurable engine
|
||||
|
||||
Everything that differs between specialties as *data* — categories, protocol steps, resource types,
|
||||
form fields — is already stored as data. What is left is behaviour: when a case opens, what happens
|
||||
when a session completes. That is expressed as a `TreatmentWorkflow` interface with one
|
||||
implementation per practice domain, resolved through a Symfony tagged-service registry, so booking
|
||||
code never names a specialty and a new one is a new class rather than a core change.
|
||||
|
||||
## Considered Options
|
||||
|
||||
A data-driven state machine editable by clinic managers was rejected: no clinic manager will author a
|
||||
state machine, so in practice only developers would use it — code with worse syntax, no type safety
|
||||
and no debugger.
|
||||
@@ -0,0 +1,14 @@
|
||||
# The clinical record of a session is separate from its visit record
|
||||
|
||||
`PatientSession` already means "an attended visit that gets billed" — it is created when an
|
||||
Appointment is confirmed and owns services, insurance shares, discounts and payments. A Treatment
|
||||
Session, by contrast, exists from the moment a course is planned, long before any booking, and must
|
||||
survive reschedules. So the two stay separate: a Treatment Session holds the plan and the clinical
|
||||
record (its area records, devices and readings) and carries no money, while the Visit Record keeps
|
||||
the financial side and is reached through the Appointment.
|
||||
|
||||
## Consequences
|
||||
|
||||
A session's full picture spans four records — case, session, appointment, visit — so queries are
|
||||
longer. In exchange, neither side can silently become a second source of truth for the other. Any
|
||||
money field appearing on a Treatment Session is a design error.
|
||||
Reference in New Issue
Block a user