Changes between Version 4 and Version 5 of RelationalModel
- Timestamp:
- 04/19/26 23:46:09 (13 days ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
RelationalModel
v4 v5 8 8 9 9 === !TreatmentType and Treatment === 10 '''!TreatmentType''' acts as a catalogue of the kinds of treatments the clinic offers, while **Treatment** represents an actual instance of a treatment performed during a specific **Examination**. The two are separated to avoid redundancy: the type-level information (“name”, “category”) lives in ** TreatmentType**, while instance-level data (which examination, which employee, notes) lives in **Treatment**. The system supports three treatment types: ''Vaccination'', ''Operation'', and ''Consultation''. Examinations that result in neither a vaccination nor an operation, including those that result only in a prescription, are classified as ''Consultation'', since a prescription is an outcome of a consultation rather than a distinct treatment category.10 '''!TreatmentType''' acts as a catalogue of the kinds of treatments the clinic offers, while **Treatment** represents an actual instance of a treatment performed during a specific **Examination**. The two are separated to avoid redundancy: the type-level information (“name”, “category”) lives in **!TreatmentType**, while instance-level data (which examination, which employee, notes) lives in **Treatment**. The system supports three treatment types: ''Vaccination'', ''Operation'', and ''Consultation''. Examinations that result in neither a vaccination nor an operation, including those that result only in a prescription, are classified as ''Consultation'', since a prescription is an outcome of a consultation rather than a distinct treatment category. 11 11 12 12 === !TreatmentAttribute and !TreatmentAttributeValue (Generic Modeling) === 13 This segment uses the Entity-Attribute-Value (EAV) generic modeling technique, introduced because different treatment types have structurally different properties. Rather than creating a separate table per treatment type (a **Vaccination** table, an **Operation** table, and a **Consultation** table) with hardcoded columns, EAV allows each ** TreatmentType** to define its own set of attributes dynamically. **TreatmentAttribute** stores the attribute name (e.g. “vacc_name”, “anesthesia”, “date_checkup”) and a “data_type” field indicating what kind of value it holds (e.g. varchar, int, date). **TreatmentAttributeValue** then stores the actual value for a given **Treatment** instance, always as a varchar regardless of the logical type.13 This segment uses the Entity-Attribute-Value (EAV) generic modeling technique, introduced because different treatment types have structurally different properties. Rather than creating a separate table per treatment type (a **Vaccination** table, an **Operation** table, and a **Consultation** table) with hardcoded columns, EAV allows each **!TreatmentType** to define its own set of attributes dynamically. **!TreatmentAttribute** stores the attribute name (e.g. “vacc_name”, “anesthesia”, “date_checkup”) and a “data_type” field indicating what kind of value it holds (e.g. varchar, int, date). **!TreatmentAttributeValue** then stores the actual value for a given **Treatment** instance, always as a varchar regardless of the logical type. 14 14 15 15 The “data_type” column is not enforced at the database level, it serves as metadata for the application layer. When the application retrieves a value, it reads the corresponding “data_type” and performs the appropriate cast before using the value (e.g. parsing "2" as an integer for “num_dose”, or "2026-01-01" as a date for “date_next”). This is an accepted tradeoff of the EAV pattern: flexibility and extensibility are gained (new treatment types with new attributes can be added without any schema changes), at the cost of delegating type enforcement and parsing to the application rather than the database. … … 18 18 **Coupon** and Discount serve distinct purposes in the billing model. A **Discount** is an optional reduction applied directly to an individual **ShopItem**. A **Coupon** is a promotional code applied at the **Invoice** level, carrying validation rules such as validity dates (“valid_from”, “valid_to”), a minimum order total (“min_total”), usage limits (“usage_limit”), and an “is_active” status flag. This separation reflects two different business scenarios: a staff member marking down a specific item with a discount versus a customer applying a promotional code to their whole invoice. 19 19 20 === InvoiceItem ===21 An ** InvoiceItem** represents a single billable line on an **Invoice**, and in PawCare two categories of things can be billed: shop items and treatments. For treatments, ''Vaccinations'' and ''Operations'' are linked via the **Treatment** table to an **InvoiceItem**. ''Consultations'', including those that result in a prescription, are also billed as **InvoiceItem** entries through the same **Treatment** - **TreatmentType** path, since a prescription is considered an outcome of a consultation rather than a standalone billable category.20 === !InvoiceItem === 21 An **!InvoiceItem** represents a single billable line on an **Invoice**, and in !PawCare two categories of things can be billed: shop items and treatments. For treatments, ''Vaccinations'' and ''Operations'' are linked via the **Treatment** table to an **!InvoiceItem**. ''Consultations'', including those that result in a prescription, are also billed as **!InvoiceItem** entries through the same **Treatment** - **!TreatmentType** path, since a prescription is considered an outcome of a consultation rather than a standalone billable category. 22 22 23 The same structure applies to shop items: a ** ShopItem** sold through the clinic (e.g. medicine, accessories, grooming products) is billed as an **InvoiceItem** referencing the **ShopItem** table, with quantity and price recorded on the line. **ShopItem** follows an analogous generic attribute pattern to treatments: **ShopItemAttribute** and **ShopItemAttributeValue** allow different product categories (e.g. “food” vs. “accessories”) to carry different properties without requiring separate tables.23 The same structure applies to shop items: a **!ShopItem** sold through the clinic (e.g. medicine, accessories, grooming products) is billed as an **!InvoiceItem** referencing the **!ShopItem** table, with quantity and price recorded on the line. **!ShopItem** follows an analogous generic attribute pattern to treatments: **!ShopItemAttribute** and **!ShopItemAttributeValue** allow different product categories (e.g. “food” vs. “accessories”) to carry different properties without requiring separate tables. 24 24 25 **Medicine** exists independently of ** ShopItem** because medicines are used in prescriptions regardless of whether the clinic sells them. The two are linked via an optional one-to-one relationship: a **Medicine** record may carry a foreign key to a **ShopItem**, indicating that this particular medicine is also available for purchase at the shop (under the category "medicine"). Both sides are optional: not every medicine is sold in the shop, and not every shop item is a medicine. When the link exists, it connects the clinical record of a medicine to its corresponding shop listing.25 **Medicine** exists independently of **!ShopItem** because medicines are used in prescriptions regardless of whether the clinic sells them. The two are linked via an optional one-to-one relationship: a **Medicine** record may carry a foreign key to a **!ShopItem**, indicating that this particular medicine is also available for purchase at the shop (under the category "medicine"). Both sides are optional: not every medicine is sold in the shop, and not every shop item is a medicine. When the link exists, it connects the clinical record of a medicine to its corresponding shop listing. 26 26 27 27 === Employee Hierarchy and Examination Assignment === 28 **Employee** contains a nullable “upervised_by” foreign key that references another row in the same table, modeling a supervisory hierarchy. In PawCare's business logic, vet assistants each have exactly one supervising vet (“supervised_by” holds that vet's “id”), while vets have no supervisor (“supervised_by” is NULL). This self-referencing relationship also implies that a vet can supervise multiple assistants.28 **Employee** contains a nullable “upervised_by” foreign key that references another row in the same table, modeling a supervisory hierarchy. In !PawCare's business logic, vet assistants each have exactly one supervising vet (“supervised_by” holds that vet's “id”), while vets have no supervisor (“supervised_by” is NULL). This self-referencing relationship also implies that a vet can supervise multiple assistants. 29 29 30 30 On the **Examination** table, the foreign key referencing the **Employee** table records which vet is responsible for the examination. Only the vet is stored directly on the examination, assistant involvement is not redundantly recorded here, since any assistants working with that vet can be derived through the “supervised_by” relationship in **Employee**. This is a deliberate design decision to avoid storing unnecessary data about all employees present, keeping the examination record focused on the responsible clinician.
