| | 236 | |
| | 237 | === Explanation of grouping by determinants |
| | 238 | |
| | 239 | The grouping is performed based on the principle that each set of attributes is determined by a single identifier. |
| | 240 | This ensures that each relation will have a primary key on which all other attributes fully depend, |
| | 241 | thus satisfying 2NF. |
| | 242 | |
| | 243 | * user_id → username, email, name, surname, full_name, password_hash, user_created_at |
| | 244 | These attributes describe a user and depend only on user_id, so they are grouped into the Users relation. |
| | 245 | |
| | 246 | * client_id → user_id, is_blocked, blocked_at, blocked_reason |
| | 247 | These attributes describe the client role of a user, so they are grouped into Clients, separated from Users. |
| | 248 | |
| | 249 | * admin_id → user_id |
| | 250 | This represents the admin role, so it is separated into its own relation to reflect specialization. |
| | 251 | |
| | 252 | * owner_id → client_id |
| | 253 | Owner is a specialization of Client, so it is grouped separately to preserve this hierarchy. |
| | 254 | |
| | 255 | * notification_id → notification_type, notification_message, notification_created_at, is_read, user_id |
| | 256 | These attributes describe a notification and depend only on notification_id, so they form the Notifications relation. |
| | 257 | |
| | 258 | * clinic_id → clinic_name, clinic_email, clinic_phone, clinic_address, clinic_location, clinic_city |
| | 259 | These attributes describe a clinic and depend only on clinic_id, so they are grouped into VetClinics. |
| | 260 | |
| | 261 | * application_id → app_name, app_email, app_phone, app_city, app_address, submitted_at, app_status, reviewed_at, reviewed_by, denial_reason, clinic_id |
| | 262 | These attributes describe a clinic application and depend only on application_id, so they form VetClinicApplications. |
| | 263 | |
| | 264 | * animal_id → animal_name, located_name, species, animal_type, breed, sex, date_of_birth, photo_url, owner_id |
| | 265 | These attributes describe an animal and depend only on animal_id, so they form the Animals relation. |
| | 266 | |
| | 267 | * listing_id → listing_status, listing_created_at, price, listing_description, animal_id, admin_id |
| | 268 | These attributes describe a listing and depend only on listing_id, so they form the Listings relation. |
| | 269 | |
| | 270 | * appointment_id → date_time, appointment_status, notes, animal_id, clinic_id |
| | 271 | These attributes describe an appointment and depend only on appointment_id, so they form the Appointments relation. |
| | 272 | |
| | 273 | * healthrecord_id → hr_type, hr_description, hr_date, animal_id, appointment_id |
| | 274 | These attributes describe a health record and depend only on healthrecord_id, so they form the HealthRecords relation. |
| | 275 | |
| | 276 | * review_id → reviewer_id, rating, comment, review_created_at, updated_at, is_deleted |
| | 277 | These attributes describe a review and depend only on review_id, so they form the Reviews relation. |
| | 278 | |
| | 279 | * review_id → target_user_id / target_clinic_id |
| | 280 | These attributes represent specialization (UserReview and ClinicReview), so they will be separated later. |
| | 281 | |
| | 282 | * FavoriteListings has key (saved_user_id, saved_listing_id) only |
| | 283 | This represents a many-to-many relationship between users and listings. Since it has no non-key attributes, it is already correctly grouped and does not require further decomposition. |