== Ограничувања и интегритет на податоците === Company_Category Табелата `Company_Category` ги содржи категориите на компании (на пример: Salon, Spa, Barber Shop). * `company_category_id` е примарен клуч (PRIMARY KEY) и обезбедува единствена идентификација на секоја категорија. * `category_name` има UNIQUE ограничување со цел да не постојат две категории со исто име. === Company Табелата `Company` ги содржи основните информации за компаниите. * `company_id` е примарен клуч. * `email` има UNIQUE ограничување бидејќи секоја компанија мора да има единствена контакт адреса. * `phone` има UNIQUE ограничување за да се избегне внесување на ист телефонски број за повеќе компании. * `is_active` има DEFAULT TRUE со што новите компании автоматски се означуваат како активни. * `created_at` има DEFAULT NOW() за автоматско снимање на датумот на креирање. === Company_Company_Category Оваа табела претставува M:N врска помеѓу компаниите и категориите. * Композитниот PRIMARY KEY (`company_id`, `company_category_id`) спречува дупли врски. * `company_id` е FOREIGN KEY кон `Company`. * `ON DELETE CASCADE` е избран бидејќи при бришење на компанија треба автоматски да се избришат и сите нејзини категории. * `company_category_id` е FOREIGN KEY кон `Company_Category`. * `ON DELETE CASCADE` овозможува автоматско отстранување на сите поврзувања доколку се избрише категорија. === Company_Location Табелата ги содржи физичките локации на компаниите. * `location_id` е примарен клуч. * `company_id` е FOREIGN KEY кон `Company`. * `ON DELETE CASCADE` е избран бидејќи локација не може да постои без компанија. === Business_Hours Табелата го дефинира работното време на секоја локација. * `hours_id` е примарен клуч. * `location_id` е FOREIGN KEY кон `Company_Location`. * `ON DELETE SET DEFAULT` е предвиден за задржување на историски записи доколку локацијата се избрише. * UNIQUE (`location_id`, `day_of_week`) гарантира дека за еден ден постои само едно работно време. * `chk_business_hours_order` осигурува дека времето на затворање е по времето на отворање. * `chk_closed_times` осигурува дека затворен ден нема часови, а работен ден мора да има часови. === User Табелата ги содржи сите корисници во системот. * `user_id` е примарен клуч. * `email` има UNIQUE ограничување бидејќи секој корисник мора да има единствена е-пошта. * `role` користи `user_role_enum` за контрола на дозволените типови корисници. * `is_active` има DEFAULT TRUE. * `created_at` има DEFAULT NOW(). === Client Табелата содржи дополнителни информации за клиентите. * `client_id` е PRIMARY KEY и истовремено FOREIGN KEY кон `User`. * `ON DELETE CASCADE` овозможува автоматско бришење на клиентскиот профил кога ќе се избрише корисникот. * `loyalty_points >= 0` спречува негативен број поени. === Owner Табелата ги содржи сопствениците на компании. * `owner_id` е PRIMARY KEY и FOREIGN KEY кон `User`. * `ON DELETE CASCADE` обезбедува конзистентност помеѓу корисникот и сопственикот. * `company_id` е FOREIGN KEY кон `Company`. * `owner_since` автоматски го поставува тековниот датум. === Staff Табелата ги содржи вработените. * `staff_id` е PRIMARY KEY и FOREIGN KEY кон `User`. * `ON DELETE CASCADE` осигурува дека нема осиротени записи. * `location_id` е FOREIGN KEY кон `Company_Location`. * `hourly_rate >= 0` спречува негативна саатница. === Staff_Type Табелата `Staff_Type` ги дефинира улогите и специјализациите на вработените. * `staff_type_id` е примарен клуч. * `staff_id` е FOREIGN KEY кон `Staff`. * `ON DELETE CASCADE` е избран бидејќи записот за улогата нема значење без вработениот. * `years_experience >= 0` спречува внесување негативно искуство. * UNIQUE (`staff_id`, `role_type`) спречува еден вработен повеќепати да ја има истата улога. === Service_Category Табелата содржи категории на услуги. * `service_category_id` е примарен клуч. * `category_name` има UNIQUE ограничување за да нема дупликат категории. === Service Табелата ги содржи сите услуги кои ги нуди компанијата. * `service_id` е примарен клуч. * `company_id` е FOREIGN KEY кон `Company`. * `ON DELETE SET NULL` е избран за услугата да може да остане зачувана во историски податоци дури и ако компанијата биде избришана. * `service_category_id` е FOREIGN KEY кон `Service_Category`. * `duration_minutes > 0` осигурува позитивно времетраење. * `duration_minutes % 15 = 0` осигурува услугите да се планираат во интервали од 15 минути. * `price >= 0` спречува негативни цени. * `is_active` овозможува деактивација без физичко бришење. === Staff_Service Табелата претставува M:N врска помеѓу вработени и услуги. * Композитниот PRIMARY KEY (`staff_id`, `service_id`) спречува дупли записи. * `staff_id` е FOREIGN KEY кон `Staff`. * `ON DELETE CASCADE` автоматски ги отстранува врските при бришење на вработен. * `service_id` е FOREIGN KEY кон `Service`. * `ON DELETE CASCADE` автоматски ги отстранува врските при бришење на услуга. === Staff_Availability Табелата ја дефинира неделната достапност на вработените. * `availability_id` е примарен клуч. * `staff_id` е FOREIGN KEY кон `Staff`. * `ON DELETE CASCADE` бидејќи достапноста нема смисла без вработен. * UNIQUE (`staff_id`, `day_of_week`) гарантира еден запис по ден. * `chk_availability_order` осигурува крајното време да е после почетното. === Blocked_Time Табелата содржи периоди кога вработениот не е достапен. * `block_id` е примарен клуч. * `staff_id` е FOREIGN KEY кон `Staff`. * `ON DELETE CASCADE` автоматски ги брише блокираните периоди. * `chk_blocked_time_order` осигурува правилен временски интервал. === Appointment Табелата ги содржи сите закажани термини. * `appointment_id` е примарен клуч. * `client_id` е FOREIGN KEY кон `Client`. * `ON DELETE SET DEFAULT` овозможува историскиот термин да остане зачуван дури и ако клиентот биде избришан. * `staff_id` е FOREIGN KEY кон `Staff`. * `ON DELETE SET DEFAULT` овозможува зачувување на историјата на термини. * `location_id` е FOREIGN KEY кон `Company_Location`. * `ON DELETE SET DEFAULT` овозможува историските термини да останат во системот. * `status` користи `appointment_status_enum` за контрола на валидни статуси. * `booked_at` автоматски го снима времето на закажување. * `chk_appointment_time_order` осигурува крајот на терминот да биде по почетокот. * `chk_cancellation` осигурува дека откажан термин мора да има датум на откажување. * UNIQUE (`staff_id`, `appointment_date`, `appointment_time`) спречува двојно резервирање на ист вработен. === Appointment_Service Табелата ги поврзува термините со услугите. * Композитниот PRIMARY KEY (`appointment_id`, `service_id`) спречува дупли услуги во ист термин. * `appointment_id` е FOREIGN KEY кон `Appointment`. * `ON DELETE SET DEFAULT` овозможува зачувување на историски финансиски податоци. * `service_id` е FOREIGN KEY кон `Service`. * `duration_minutes > 0` осигурува валидно времетраење. * `price >= 0` спречува негативни вредности. * Цената се чува денормализирано за да остане непроменета и по идни промени на ценовникот. === Product Табелата ги содржи сите производи и потрошни материјали. * `product_id` е примарен клуч. * `unit_price >= 0` спречува негативни цени. * `reorder_level >= 0` спречува негативен праг за нарачка. === Appointment_Product Табелата ги поврзува термините со искористените производи. * Композитниот PRIMARY KEY (`appointment_id`, `product_id`) спречува дупли записи. * `appointment_id` е FOREIGN KEY кон `Appointment`. * `ON DELETE CASCADE` бидејќи искористените производи немаат значење без терминот. * `product_id` е FOREIGN KEY кон `Product`. * `quantity_used > 0` осигурува позитивна количина. * Количината претставува историски запис за потрошувачката. === Inventory Табелата ја следи залихата на продукти по локација. * `inventory_id` е примарен клуч. * `product_id` е FOREIGN KEY кон `Product`. * `location_id` е FOREIGN KEY кон `Company_Location`. * `quantity_on_hand >= 0` спречува негативна залиха. * UNIQUE (`product_id`, `location_id`) осигурува само еден запис по производ и локација. === Invoice Табелата ги содржи фактурите. * `invoice_id` е примарен клуч. * `appointment_id` е FOREIGN KEY кон `Appointment`. * `ON DELETE RESTRICT` е избран бидејќи термин што има фактура не смее да биде избришан. * `appointment_id` има UNIQUE ограничување бидејќи еден термин може да има само една фактура. * `client_id` е FOREIGN KEY кон `Client`. * `subtotal >= 0` * `discount_total >= 0` * `tax >= 0` * `total` автоматски се пресметува како: `subtotal + tax - discount_total` * `payment_method` користи enum за валидни начини на плаќање. === Promo_Code Табелата содржи промотивни кодови. * `promo_id` е примарен клуч. * `company_id` е FOREIGN KEY кон `Company`. * `ON DELETE CASCADE` бидејќи кодот не може да постои без компанија. * `discount_value > 0` осигурува позитивен попуст. * `chk_promo_dates` осигурува датумот на истекување да биде после датумот на почеток. * UNIQUE (`company_id`, `code`) спречува дупликат кодови во иста компанија. === Invoice_Promo Табелата претставува M:N врска помеѓу фактури и промо кодови. * Композитниот PRIMARY KEY (`invoice_id`, `promo_id`) спречува дупли записи. * `invoice_id` е FOREIGN KEY кон `Invoice`. * `ON DELETE CASCADE` автоматски ги брише поврзаните записи. * `promo_id` е FOREIGN KEY кон `Promo_Code`. * `ON DELETE CASCADE` автоматски ги брише поврзаните записи. === Review Табелата содржи оценки и коментари од клиентите. * `review_id` е примарен клуч. * `appointment_id` е FOREIGN KEY кон `Appointment`. * UNIQUE (`appointment_id`) гарантира само една рецензија по термин. * `client_id` е FOREIGN KEY кон `Client`. * `rating BETWEEN 1 AND 5` осигурува валидна оцена. * `created_at` автоматски го снима времето на креирање. === Loyalty_Transaction Табелата ја следи историјата на поени. * `transaction_id` е примарен клуч. * `client_id` е FOREIGN KEY кон `Client`. * `appointment_id` е FOREIGN KEY кон `Appointment`. * `ON DELETE SET NULL` овозможува задржување на трансакцијата дури и ако терминот се избрише. * `points_earned >= 0` * `points_spent >= 0` * `chk_loyalty_nonzero` осигурува дека барем едно од полињата има вредност поголема од нула. === Service_Price_History Табелата ја чува историјата на промени на цените. * `price_history_id` е примарен клуч. * `service_id` е FOREIGN KEY кон `Service`. * `ON DELETE CASCADE` бидејќи записите немаат значење без услугата. * `old_price >= 0` * `new_price >= 0` * `changed_at` автоматски го снима времето на промената. === Staff_Time_Slot Табелата содржи 15-минутни временски слотови за вработените. * `slot_id` е примарен клуч. * `staff_id` е FOREIGN KEY кон `Staff`. * `ON DELETE CASCADE` бидејќи слотовите немаат значење без вработен. * `appointment_id` е FOREIGN KEY кон `Appointment`. * `ON DELETE SET NULL` овозможува слотот да остане достапен ако терминот се избрише. * `slot_end` автоматски се пресметува од `slot_start`. * `chk_slot_order` осигурува правилен временски интервал. * UNIQUE (`staff_id`, `slot_start`) спречува два идентични слота за ист вработен.