| | 1 | == Ограничувања и интегритет на податоците |
| | 2 | |
| | 3 | === Company_Category |
| | 4 | |
| | 5 | Табелата `Company_Category` ги содржи категориите на компании (на пример: Salon, Spa, Barber Shop). |
| | 6 | |
| | 7 | * `company_category_id` е примарен клуч (PRIMARY KEY) и обезбедува единствена идентификација на секоја категорија. |
| | 8 | * `category_name` има UNIQUE ограничување со цел да не постојат две категории со исто име. |
| | 9 | |
| | 10 | === Company |
| | 11 | |
| | 12 | Табелата `Company` ги содржи основните информации за компаниите. |
| | 13 | |
| | 14 | * `company_id` е примарен клуч. |
| | 15 | * `email` има UNIQUE ограничување бидејќи секоја компанија мора да има единствена контакт адреса. |
| | 16 | * `phone` има UNIQUE ограничување за да се избегне внесување на ист телефонски број за повеќе компании. |
| | 17 | * `is_active` има DEFAULT TRUE со што новите компании автоматски се означуваат како активни. |
| | 18 | * `created_at` има DEFAULT NOW() за автоматско снимање на датумот на креирање. |
| | 19 | |
| | 20 | === Company_Company_Category |
| | 21 | |
| | 22 | Оваа табела претставува M:N врска помеѓу компаниите и категориите. |
| | 23 | |
| | 24 | * Композитниот PRIMARY KEY (`company_id`, `company_category_id`) спречува дупли врски. |
| | 25 | * `company_id` е FOREIGN KEY кон `Company`. |
| | 26 | * `ON DELETE CASCADE` е избран бидејќи при бришење на компанија треба автоматски да се избришат и сите нејзини категории. |
| | 27 | * `company_category_id` е FOREIGN KEY кон `Company_Category`. |
| | 28 | * `ON DELETE CASCADE` овозможува автоматско отстранување на сите поврзувања доколку се избрише категорија. |
| | 29 | |
| | 30 | === Company_Location |
| | 31 | |
| | 32 | Табелата ги содржи физичките локации на компаниите. |
| | 33 | |
| | 34 | * `location_id` е примарен клуч. |
| | 35 | * `company_id` е FOREIGN KEY кон `Company`. |
| | 36 | * `ON DELETE CASCADE` е избран бидејќи локација не може да постои без компанија. |
| | 37 | |
| | 38 | === Business_Hours |
| | 39 | |
| | 40 | Табелата го дефинира работното време на секоја локација. |
| | 41 | |
| | 42 | * `hours_id` е примарен клуч. |
| | 43 | * `location_id` е FOREIGN KEY кон `Company_Location`. |
| | 44 | * `ON DELETE SET DEFAULT` е предвиден за задржување на историски записи доколку локацијата се избрише. |
| | 45 | * UNIQUE (`location_id`, `day_of_week`) гарантира дека за еден ден постои само едно работно време. |
| | 46 | * `chk_business_hours_order` осигурува дека времето на затворање е по времето на отворање. |
| | 47 | * `chk_closed_times` осигурува дека затворен ден нема часови, а работен ден мора да има часови. |
| | 48 | |
| | 49 | === User |
| | 50 | |
| | 51 | Табелата ги содржи сите корисници во системот. |
| | 52 | |
| | 53 | * `user_id` е примарен клуч. |
| | 54 | * `email` има UNIQUE ограничување бидејќи секој корисник мора да има единствена е-пошта. |
| | 55 | * `role` користи `user_role_enum` за контрола на дозволените типови корисници. |
| | 56 | * `is_active` има DEFAULT TRUE. |
| | 57 | * `created_at` има DEFAULT NOW(). |
| | 58 | |
| | 59 | === Client |
| | 60 | |
| | 61 | Табелата содржи дополнителни информации за клиентите. |
| | 62 | |
| | 63 | * `client_id` е PRIMARY KEY и истовремено FOREIGN KEY кон `User`. |
| | 64 | * `ON DELETE CASCADE` овозможува автоматско бришење на клиентскиот профил кога ќе се избрише корисникот. |
| | 65 | * `loyalty_points >= 0` спречува негативен број поени. |
| | 66 | |
| | 67 | === Owner |
| | 68 | |
| | 69 | Табелата ги содржи сопствениците на компании. |
| | 70 | |
| | 71 | * `owner_id` е PRIMARY KEY и FOREIGN KEY кон `User`. |
| | 72 | * `ON DELETE CASCADE` обезбедува конзистентност помеѓу корисникот и сопственикот. |
| | 73 | * `company_id` е FOREIGN KEY кон `Company`. |
| | 74 | * `owner_since` автоматски го поставува тековниот датум. |
| | 75 | |
| | 76 | === Staff |
| | 77 | |
| | 78 | Табелата ги содржи вработените. |
| | 79 | |
| | 80 | * `staff_id` е PRIMARY KEY и FOREIGN KEY кон `User`. |
| | 81 | * `ON DELETE CASCADE` осигурува дека нема осиротени записи. |
| | 82 | * `location_id` е FOREIGN KEY кон `Company_Location`. |
| | 83 | * `hourly_rate >= 0` спречува негативна саатница. |
| | 84 | |
| | 85 | === Staff_Type |
| | 86 | |
| | 87 | Табелата `Staff_Type` ги дефинира улогите и специјализациите на вработените. |
| | 88 | |
| | 89 | * `staff_type_id` е примарен клуч. |
| | 90 | * `staff_id` е FOREIGN KEY кон `Staff`. |
| | 91 | * `ON DELETE CASCADE` е избран бидејќи записот за улогата нема значење без вработениот. |
| | 92 | * `years_experience >= 0` спречува внесување негативно искуство. |
| | 93 | * UNIQUE (`staff_id`, `role_type`) спречува еден вработен повеќепати да ја има истата улога. |
| | 94 | |
| | 95 | === Service_Category |
| | 96 | |
| | 97 | Табелата содржи категории на услуги. |
| | 98 | |
| | 99 | * `service_category_id` е примарен клуч. |
| | 100 | * `category_name` има UNIQUE ограничување за да нема дупликат категории. |
| | 101 | |
| | 102 | === Service |
| | 103 | |
| | 104 | Табелата ги содржи сите услуги кои ги нуди компанијата. |
| | 105 | |
| | 106 | * `service_id` е примарен клуч. |
| | 107 | * `company_id` е FOREIGN KEY кон `Company`. |
| | 108 | * `ON DELETE SET NULL` е избран за услугата да може да остане зачувана во историски податоци дури и ако компанијата биде избришана. |
| | 109 | * `service_category_id` е FOREIGN KEY кон `Service_Category`. |
| | 110 | * `duration_minutes > 0` осигурува позитивно времетраење. |
| | 111 | * `duration_minutes % 15 = 0` осигурува услугите да се планираат во интервали од 15 минути. |
| | 112 | * `price >= 0` спречува негативни цени. |
| | 113 | * `is_active` овозможува деактивација без физичко бришење. |
| | 114 | |
| | 115 | === Staff_Service |
| | 116 | |
| | 117 | Табелата претставува M:N врска помеѓу вработени и услуги. |
| | 118 | |
| | 119 | * Композитниот PRIMARY KEY (`staff_id`, `service_id`) спречува дупли записи. |
| | 120 | * `staff_id` е FOREIGN KEY кон `Staff`. |
| | 121 | * `ON DELETE CASCADE` автоматски ги отстранува врските при бришење на вработен. |
| | 122 | * `service_id` е FOREIGN KEY кон `Service`. |
| | 123 | * `ON DELETE CASCADE` автоматски ги отстранува врските при бришење на услуга. |
| | 124 | |
| | 125 | === Staff_Availability |
| | 126 | |
| | 127 | Табелата ја дефинира неделната достапност на вработените. |
| | 128 | |
| | 129 | * `availability_id` е примарен клуч. |
| | 130 | * `staff_id` е FOREIGN KEY кон `Staff`. |
| | 131 | * `ON DELETE CASCADE` бидејќи достапноста нема смисла без вработен. |
| | 132 | * UNIQUE (`staff_id`, `day_of_week`) гарантира еден запис по ден. |
| | 133 | * `chk_availability_order` осигурува крајното време да е после почетното. |
| | 134 | |
| | 135 | === Blocked_Time |
| | 136 | |
| | 137 | Табелата содржи периоди кога вработениот не е достапен. |
| | 138 | |
| | 139 | * `block_id` е примарен клуч. |
| | 140 | * `staff_id` е FOREIGN KEY кон `Staff`. |
| | 141 | * `ON DELETE CASCADE` автоматски ги брише блокираните периоди. |
| | 142 | * `chk_blocked_time_order` осигурува правилен временски интервал. |
| | 143 | |
| | 144 | === Appointment |
| | 145 | |
| | 146 | Табелата ги содржи сите закажани термини. |
| | 147 | |
| | 148 | * `appointment_id` е примарен клуч. |
| | 149 | * `client_id` е FOREIGN KEY кон `Client`. |
| | 150 | * `ON DELETE SET DEFAULT` овозможува историскиот термин да остане зачуван дури и ако клиентот биде избришан. |
| | 151 | * `staff_id` е FOREIGN KEY кон `Staff`. |
| | 152 | * `ON DELETE SET DEFAULT` овозможува зачувување на историјата на термини. |
| | 153 | * `location_id` е FOREIGN KEY кон `Company_Location`. |
| | 154 | * `ON DELETE SET DEFAULT` овозможува историските термини да останат во системот. |
| | 155 | * `status` користи `appointment_status_enum` за контрола на валидни статуси. |
| | 156 | * `booked_at` автоматски го снима времето на закажување. |
| | 157 | * `chk_appointment_time_order` осигурува крајот на терминот да биде по почетокот. |
| | 158 | * `chk_cancellation` осигурува дека откажан термин мора да има датум на откажување. |
| | 159 | * UNIQUE (`staff_id`, `appointment_date`, `appointment_time`) спречува двојно резервирање на ист вработен. |
| | 160 | |
| | 161 | === Appointment_Service |
| | 162 | |
| | 163 | Табелата ги поврзува термините со услугите. |
| | 164 | |
| | 165 | * Композитниот PRIMARY KEY (`appointment_id`, `service_id`) спречува дупли услуги во ист термин. |
| | 166 | * `appointment_id` е FOREIGN KEY кон `Appointment`. |
| | 167 | * `ON DELETE SET DEFAULT` овозможува зачувување на историски финансиски податоци. |
| | 168 | * `service_id` е FOREIGN KEY кон `Service`. |
| | 169 | * `duration_minutes > 0` осигурува валидно времетраење. |
| | 170 | * `price >= 0` спречува негативни вредности. |
| | 171 | * Цената се чува денормализирано за да остане непроменета и по идни промени на ценовникот. |
| | 172 | |
| | 173 | === Product |
| | 174 | |
| | 175 | Табелата ги содржи сите производи и потрошни материјали. |
| | 176 | |
| | 177 | * `product_id` е примарен клуч. |
| | 178 | * `unit_price >= 0` спречува негативни цени. |
| | 179 | * `reorder_level >= 0` спречува негативен праг за нарачка. |
| | 180 | |
| | 181 | === Appointment_Product |
| | 182 | |
| | 183 | Табелата ги поврзува термините со искористените производи. |
| | 184 | |
| | 185 | * Композитниот PRIMARY KEY (`appointment_id`, `product_id`) спречува дупли записи. |
| | 186 | * `appointment_id` е FOREIGN KEY кон `Appointment`. |
| | 187 | * `ON DELETE CASCADE` бидејќи искористените производи немаат значење без терминот. |
| | 188 | * `product_id` е FOREIGN KEY кон `Product`. |
| | 189 | * `quantity_used > 0` осигурува позитивна количина. |
| | 190 | * Количината претставува историски запис за потрошувачката. |
| | 191 | |
| | 192 | === Inventory |
| | 193 | |
| | 194 | Табелата ја следи залихата на продукти по локација. |
| | 195 | |
| | 196 | * `inventory_id` е примарен клуч. |
| | 197 | * `product_id` е FOREIGN KEY кон `Product`. |
| | 198 | * `location_id` е FOREIGN KEY кон `Company_Location`. |
| | 199 | * `quantity_on_hand >= 0` спречува негативна залиха. |
| | 200 | * UNIQUE (`product_id`, `location_id`) осигурува само еден запис по производ и локација. |
| | 201 | |
| | 202 | === Invoice |
| | 203 | |
| | 204 | Табелата ги содржи фактурите. |
| | 205 | |
| | 206 | * `invoice_id` е примарен клуч. |
| | 207 | * `appointment_id` е FOREIGN KEY кон `Appointment`. |
| | 208 | * `ON DELETE RESTRICT` е избран бидејќи термин што има фактура не смее да биде избришан. |
| | 209 | * `appointment_id` има UNIQUE ограничување бидејќи еден термин може да има само една фактура. |
| | 210 | * `client_id` е FOREIGN KEY кон `Client`. |
| | 211 | * `subtotal >= 0` |
| | 212 | * `discount_total >= 0` |
| | 213 | * `tax >= 0` |
| | 214 | * `total` автоматски се пресметува како: |
| | 215 | `subtotal + tax - discount_total` |
| | 216 | * `payment_method` користи enum за валидни начини на плаќање. |
| | 217 | |
| | 218 | === Promo_Code |
| | 219 | |
| | 220 | Табелата содржи промотивни кодови. |
| | 221 | |
| | 222 | * `promo_id` е примарен клуч. |
| | 223 | * `company_id` е FOREIGN KEY кон `Company`. |
| | 224 | * `ON DELETE CASCADE` бидејќи кодот не може да постои без компанија. |
| | 225 | * `discount_value > 0` осигурува позитивен попуст. |
| | 226 | * `chk_promo_dates` осигурува датумот на истекување да биде после датумот на почеток. |
| | 227 | * UNIQUE (`company_id`, `code`) спречува дупликат кодови во иста компанија. |
| | 228 | |
| | 229 | === Invoice_Promo |
| | 230 | |
| | 231 | Табелата претставува M:N врска помеѓу фактури и промо кодови. |
| | 232 | |
| | 233 | * Композитниот PRIMARY KEY (`invoice_id`, `promo_id`) спречува дупли записи. |
| | 234 | * `invoice_id` е FOREIGN KEY кон `Invoice`. |
| | 235 | * `ON DELETE CASCADE` автоматски ги брише поврзаните записи. |
| | 236 | * `promo_id` е FOREIGN KEY кон `Promo_Code`. |
| | 237 | * `ON DELETE CASCADE` автоматски ги брише поврзаните записи. |
| | 238 | |
| | 239 | === Review |
| | 240 | |
| | 241 | Табелата содржи оценки и коментари од клиентите. |
| | 242 | |
| | 243 | * `review_id` е примарен клуч. |
| | 244 | * `appointment_id` е FOREIGN KEY кон `Appointment`. |
| | 245 | * UNIQUE (`appointment_id`) гарантира само една рецензија по термин. |
| | 246 | * `client_id` е FOREIGN KEY кон `Client`. |
| | 247 | * `rating BETWEEN 1 AND 5` осигурува валидна оцена. |
| | 248 | * `created_at` автоматски го снима времето на креирање. |
| | 249 | |
| | 250 | === Loyalty_Transaction |
| | 251 | |
| | 252 | Табелата ја следи историјата на поени. |
| | 253 | |
| | 254 | * `transaction_id` е примарен клуч. |
| | 255 | * `client_id` е FOREIGN KEY кон `Client`. |
| | 256 | * `appointment_id` е FOREIGN KEY кон `Appointment`. |
| | 257 | * `ON DELETE SET NULL` овозможува задржување на трансакцијата дури и ако терминот се избрише. |
| | 258 | * `points_earned >= 0` |
| | 259 | * `points_spent >= 0` |
| | 260 | * `chk_loyalty_nonzero` осигурува дека барем едно од полињата има вредност поголема од нула. |
| | 261 | |
| | 262 | === Service_Price_History |
| | 263 | |
| | 264 | Табелата ја чува историјата на промени на цените. |
| | 265 | |
| | 266 | * `price_history_id` е примарен клуч. |
| | 267 | * `service_id` е FOREIGN KEY кон `Service`. |
| | 268 | * `ON DELETE CASCADE` бидејќи записите немаат значење без услугата. |
| | 269 | * `old_price >= 0` |
| | 270 | * `new_price >= 0` |
| | 271 | * `changed_at` автоматски го снима времето на промената. |
| | 272 | |
| | 273 | === Staff_Time_Slot |
| | 274 | |
| | 275 | Табелата содржи 15-минутни временски слотови за вработените. |
| | 276 | |
| | 277 | * `slot_id` е примарен клуч. |
| | 278 | * `staff_id` е FOREIGN KEY кон `Staff`. |
| | 279 | * `ON DELETE CASCADE` бидејќи слотовите немаат значење без вработен. |
| | 280 | * `appointment_id` е FOREIGN KEY кон `Appointment`. |
| | 281 | * `ON DELETE SET NULL` овозможува слотот да остане достапен ако терминот се избрише. |
| | 282 | * `slot_end` автоматски се пресметува од `slot_start`. |
| | 283 | * `chk_slot_order` осигурува правилен временски интервал. |
| | 284 | * UNIQUE (`staff_id`, `slot_start`) спречува два идентични слота за ист вработен. |
| | 285 | |