Changes between Version 10 and Version 11 of RelationalModel
- Timestamp:
- 04/25/26 19:54:33 (7 days ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
RelationalModel
v10 v11 7 7 == Архитектура и главни концепти 8 8 9 === Корис тачи и нивни улоги9 === Корисници и нивни улоги 10 10 11 Основна е поделбата меѓу `users` (сите во системот), `drivers` (возачи) и `passengers` (патници). Табелата `users` е како "мајка" — содржи основни информации (име, телефон, емајл). Потоа `drivers` и `passengers`додаваат своите специфични полиња. Една иста личност може да биде и возач и патник — нема никаква забрана за тоа.11 Основна е поделбата меѓу `users` (сите во системот), `drivers` (возачи) и `passengers` (патници). Табелата `users` е како „мајка“ — ги содржи основните информации (име, телефон, е-пошта). Потоа `drivers` и `passengers` ги додаваат своите специфични полиња. Една иста личност може да биде и возач и патник — нема никаква забрана за тоа. 12 12 13 13 === Возила и производители 14 14 15 Возилата имаат три нивоа организирање. Прво `manufacturers` (Volkswagen, Mercedes, итн.), потоа `vehicle_models` (Golf, C-Class), потоа самите `vehicles` (твоја лична кола). Вакво расчленување спречува да пишувале "Volkswagen" стоди пати во базата.15 Возилата се организирани во три нивоа. Прво `manufacturers` (Volkswagen, Mercedes итн.), потоа `vehicle_models` (Golf, C-Class), па самите `vehicles` (твојата лична кола). Ваквото расчленување спречува да се пишува "Volkswagen" стотици пати во базата. 16 16 17 Возачот има много возила, возило мора да припаѓа на возач. За тоа го имаме `vehicle_ownership` — табела која чува каде возачот имал кола. Кога возачот купи ново возило, едноставно ј додаваме нов ред во `vehicle_ownership`. Старото возило останува во историјата, не го бришеме. Вака видиме точно кој возач кога ималкола.17 Возачот може да има многу возила, а секое возило мора да припаѓа на возач. За тоа ја користиме `vehicle_ownership` — табела која чува податоци за тоа кој возач кој автомобил го поседувал. Кога возачот ќе купи ново возило, едноставно додаваме нов ред во `vehicle_ownership`. Старото возило останува во историјата и не го бришеме. На овој начин точно гледаме кој возач во кој период поседувал одредена кола. 18 18 19 19 === Рути и возења 20 20 21 `Routes` е шаблон — замисли рута "Скопје → Куманово → Пријепа" дефинирана веќе во системот. `Rides` е конкретно возење: „Во понеделник во 08:00 возачот Марко ја возеше оваа рута со Volkswagen Golf".21 `Routes` е шаблон — замисли рута „Скопје → Куманово → Прилеп“ која е веќе дефинирана во системот. `Rides` е конкретно возење: „Во понеделник во 08:00 часот возачот Марко ја возеше оваа рута со Volkswagen Golf“. 22 22 23 Застанувањата на рутата се во `route_stops` со редоследни броеви (1, 2, 3...). Рутата може да има 2 застанувања или 10 застанувања. Исто така, на иста рута може ш да направиш и круг (почеток и крајиста локација).23 Застанувањата на рутата се во `route_stops` со редоследни броеви (1, 2, 3...). Рутата може да има 2 застанувања или 10 застанувања. Исто така, на иста рута може да се направи и круг (почетокот и крајот да се на иста локација). 24 24 25 25 === Сегменти — како се делат возењата 26 26 27 Возењето од Скопје до При јепа преку Куманово не е "целина"во пресметките. Поделено е на сегменти:28 -Скопје → Куманово29 - Куманово → Пријепа 27 Возењето од Скопје до Прилеп преку Куманово не е „целина“ во пресметките. Поделено е на сегменти: 28 * Скопје → Куманово 29 * Куманово → Прилеп 30 30 31 Патниците не мора да патуваат целата рута. Еден патник можеш да влезе во Куманово и да излезе во Пријепа. За тоа `route_segments` дели рутата на делови меѓу два стопа, а `passenger_segments` чува колку патници беа на секој сегмент. Вака точно можеме да изразунаме колку требало да плати секој патник според каде вле и каде слезе.31 Патниците не мора да ја патуваат целата рута. Еден патник може да влезе во Куманово и да излезе во Прилеп. Затоа `route_segments` ја дели рутата на делови меѓу два стопа, а `passenger_segments` чува податоци за тоа колку патници имало на секој сегмент. Вака точно можеме да пресметаме колку треба да плати секој патник според тоа каде влегол и каде слегол. 32 32 33 33 === Патарини 34 34 35 Не можеме едноставно да кажеме "возење чини X денари". Некои возења минуваатнаплатни рампи. За тоа имаме:36 - `toll_points` — каде се наплатните рампи и колку чинат по типвозило37 - `ride_tolls` — евидентира дека возењето Хминало низ рампата Y38 - `toll_passenger_split` — раздела на патарината меѓу патниците кои беаприсутни35 Не можеме едноставно да кажеме дека „возењето чини X денари“. Некои возења поминуваат низ наплатни рампи. За тоа имаме: 36 * `toll_points` — каде се наплатните рампи и колку чинат според типот на возило 37 * `ride_tolls` — евидентира дека возењето Х поминало низ рампата Y 38 * `toll_passenger_split` — поделба на патарината меѓу патниците кои биле присутни 39 39 40 === Готовина, не картички40 === Готовина, а не картички 41 41 42 Апликацијата е готовина-само. Нема онлајн плаќања, нема дигитални портфели. Возачот собира готовина од патниците. Табелите `fare_splits` и `booking_final_fare` служат само да покажат возачу колку собираод кого — ништо повеќе.42 Апликацијата работи исклучиво со готовина. Нема онлајн плаќања, ниту дигитални паричници. Возачот ја собира готовината од патниците. Табелите `fare_splits` и `booking_final_fare` служат само за да му покажат на возачот колку пари треба да собере од кого — ништо повеќе. 43 43 44 44 === Оценувања 45 45 46 Патниците оценуваат возачи, возачи оценуваат патници. Табелата `ratings` чува сите оценувања. Има CHECK constraint кој вели: "Човек не може да го оцени самиот себеси". За просечната оцена не пишуваме `avg_rating` поле директно. Наместо тоа, правиме view-и `driver_ratings` и `passenger_ratings` кои пресметуваат просек на лету. Вакаако додадеш нова оценка, просекот се ажурира веднаш без дополнителна логика.46 Патниците ги оценуваат возачите, а возачите ги оценуваат патниците. Табелата `ratings` ги чува сите оценувања. Постои CHECK constraint кој вели: „Корисникот не може да се оцени самиот себеси“. За просечната оцена не користиме директно поле `avg_rating`. Наместо тоа, користиме погледи (views) `driver_ratings` и `passenger_ratings` кои го пресметуваат просекот во реално време (on the fly). Вака, ако додадеш нова оценка, просекот се ажурира веднаш без дополнителна логика. 47 47 48 === Истори яи следливост48 === Историја и следливост 49 49 50 Кога возење промени статус (scheduled → in_progress → completed), промената оди во `ride_status_history` со временска марка. Исто и резервациите во `booking_status_history`. Вака администраторот има целосна историја — кога точно се случи што.50 Кога возењето ќе го промени статусот (scheduled → in_progress → completed), промената се запишува во `ride_status_history` со временска ознака. Истото важи и за резервациите во `booking_status_history`. На овој начин администраторот има целосна историја — кога точно што се случило. 51 51 52 52 === Бришење на податоци 53 53 54 Претпоставка: администраторот избрише користачки профил. Но возачот има 50 завршени возења! Ние не ги бришеме поврзаните возења — користиме `ON DELETE RESTRICT`. За статистика, користиме резервиран корисник со `id = 0` наречен "избришан корисник". Вака можеме да видиме "некој возач" направил возење, дури и кога профилоте избришан.54 Претпоставка: администраторот брише кориснички профил. Но возачот има 50 завршени возења! Ние не ги бришеме поврзаните возења — користиме `ON DELETE RESTRICT`. За потребите на статистиката, користиме резервиран корисник со `id = 0` наречен „избришан корисник“. Така можеме да видиме дека „некој возач“ направил возење, дури и кога оригиналниот профил е избришан. 55 55 56 56 == Прегледи (Views) 57 57 58 Сите овие табели се напалени со JOIN-ови. Наместо апликацијата да пишува `SELECT ... FROM rides JOIN drivers JOIN vehicles ...` низ целиот код, ми направивме 9 views. Секој view е спремена SQL "забелешка" која делува како табела.58 Сите овие табели се поврзани со JOIN-ови. Наместо апликацијата да пишува `SELECT ... FROM rides JOIN drivers JOIN vehicles ...` низ целиот код, направивме 9 погледи (views). Секој поглед е подготвена SQL „забелешка“ која се однесува како табела. 59 59 60 60 === v_available_rides — Возења отворени за резервирање 61 61 62 Ова е она што патникот вижи кога пребарува возење. Показува:63 -Кога поаѓа возењето64 - Каде почнува,каде завршува65 - Име на возач 66 - Марка и модел на возило67 -Проценета цена68 -Просечна оцена на возачот62 Ова е она што патникот го гледа кога пребарува возење. Прикажува: 63 * Кога поаѓа возењето 64 * Каде почнува, а каде завршува 65 * Име на возачот 66 * Марка и модел на возилото 67 * Проценета цена 68 * Просечна оцена на возачот 69 69 70 VIEW вика JOIN меѓу `rides`, `drivers`, `vehicles`, `vehicle_models`, `manufacturers`, `routes`, `route_stops`, `ratings` и пресметува просечна оцена на лету. Филтрира само возења со статус `scheduled`.70 Овој VIEW прави JOIN меѓу `rides`, `drivers`, `vehicles`, `vehicle_models`, `manufacturers`, `routes`, `route_stops`, `ratings` и го пресметува просекот на оценките во реално време. Ги филтрира само возењата со статус `scheduled`. 71 71 72 72 Апликацијата го користи вака: `SELECT * FROM v_available_rides WHERE origin_city = 'Скопје' AND departure_time >= NOW()`. Едноставно! 73 73 74 === v_driver_profile — Профил отна возачот74 === v_driver_profile — Профил на возачот 75 75 76 Возачот кога си ажурира профилот, вижи ова. Исто и патникот пред да резервира место ако сака да види со кого ќе возеше.76 Возачот го гледа ова кога го ажурира својот профил. Исто така, патникот го гледа ова пред да резервира место ако сака да види со кого ќе се вози. 77 77 78 78 Содржи: 79 -Лични податоци (име, телефон)80 -Информации за возачка дозвола (број, датум на издавање)81 - Примарното возило на возачот (ако има повеќе, земаме оносо најмал ID)82 -Статистика: вкупно возења, завршени, откажани83 -Просечна оцена79 * Лични податоци (име, телефон) 80 * Информации за возачка дозвола (број, датум на издавање) 81 * Примарното возило на возачот (ако има повеќе, го земаме она со најмал ID) 82 * Статистика: вкупно возења, завршени, откажани 83 * Просечна оцена 84 84 85 VIEW прави JOIN меѓу `drivers`, `users`, `driver_licenses`, `vehicles`, `vehicle_ownership`, `rides` и `ratings`. Пресметува број на возења по статус и просек на оценувања.85 VIEW-то прави JOIN меѓу `drivers`, `users`, `driver_licenses`, `vehicles`, `vehicle_ownership`, `rides` и `ratings`. Ги пресметува бројот на возења според статус и просекот на оценките. 86 86 87 87 === v_passenger_trip_history — Моја патна историја 88 88 89 Патникот кога кликне на "Мои патувања" вижи:90 - Кога бешевозењето91 - Каде почнало,каде завршило92 - Име на возач 93 - Потврда дека је качен (pickup_confirmed_at)94 - Потврда дека је слезен (dropoff_confirmed_at)95 -Колку платил96 -Неговата оценка за возачот (ако ја дал)89 Патникот, кога ќе кликне на „Мои патувања“, го гледа следново: 90 * Кога било возењето 91 * Каде почнало, а каде завршило 92 * Име на возачот 93 * Потврда дека е качен (pickup_confirmed_at) 94 * Потврда дека е слезен (dropoff_confirmed_at) 95 * Колку платил 96 * Неговата оценка за возачот (ако ја дал) 97 97 98 Секоја резервација е редок во view-ot. Апликацијата може лесно да филтрира по статус (`completed`, `canceled`) или да го пагинира.98 Секоја резервација е посебен ред во погледот. Апликацијата може лесно да филтрира по статус (`completed`, `canceled`) или да ги пагинира резултатите. 99 99 100 100 === v_ride_manifest — Список на патници за возење 101 101 102 Возачот одлуч и да поаѓа во 08:00. Пред да ја запали машината, отворува ја оваа листа за да вижи:103 -Кои патници се качуваат104 -Имиња и телефонски броеви105 - Каде секој вле (punkt_A_stop)106 - Каде секој слезе (punkt_B_stop)107 - Колку собира од секој 102 Возачот одлучува да тргне во 08:00 часот. Пред да го запали возилото, ја отвора оваа листа за да види: 103 * Кои патници се качуваат 104 * Имиња и телефонски броеви 105 * Каде влегува секој (point_A_stop) 106 * Каде слегува секој (point_B_stop) 107 * Колку пари треба да собере од секого 108 108 109 Прикажува само резервации со статус `confirmed`, `picked_up` или `completed`. Откажаните резервации не се прикажуваат — нема смисла да ги вижи.109 Ги прикажува само резервациите со статус `confirmed`, `picked_up` или `completed`. Откажаните резервации не се прикажуваат — нема смисла возачот да ги гледа. 110 110 111 === v_booking_details — Целос ен детај на резервација111 === v_booking_details — Целосни детали за резервација 112 112 113 Патникот кликн а на една резервација. Вижи "сё на едно место":114 -Кој е возачот (име, телефон, оцена)115 - Какво возило (марка, модел, регистарски табички)116 - Точна локација за качување (Централна станица, Скопје)117 - Точна локација за слегување (Куманово центар)118 -Точен час на поаѓање119 -Финална цена120 - Статус на резервација113 Патникот кликнува на една резервација и гледа „сè на едно место“: 114 * Кој е возачот (име, телефон, оцена) 115 * Какво возило (марка, модел, регистарски таблички) 116 * Точна локација за качување (на пр. Централна станица, Скопје) 117 * Точна локација за слегување (на пр. Куманово центар) 118 * Точен час на поаѓање 119 * Финална цена 120 * Статус на резервацијата 121 121 122 Содржи толку многу JOIN-ови што апликацијата СЕКОГАШ го вика со филтер: `WHERE booking_id = 123`. Никогаш не го вика без филтер — би ја спалил базата од JOIN-ови!122 Содржи многу JOIN-ови, па затоа апликацијата СЕКОГАШ го повикува со филтер: `WHERE booking_id = 123`. Никогаш не се повикува без филтер за да не се преоптовари базата. 123 123 124 === v_unread_notifications — Мои нови нотификации124 === v_unread_notifications — Мои нови известувања 125 125 126 Патникот или возачот отворува го "звончето". Вижи само непрочитаните нотификации:127 - Каде е написано нотификацијата (текст) 128 - Од кого (некој возач, администратор,итн.)129 - Кога (точна време или "пред 5 минути")126 Патникот или возачот го отвораат „ѕвончето“. Ги гледаат само непрочитаните известувања: 127 * Текстот на известувањето 128 * Од кого е испратено (возач, администратор итн.) 129 * Кога е испратено (точно време или „пред 5 минути“) 130 130 131 VIEW- ot пресметува "старост во минути" за да покаже "пред 5 мин" без дополнителна логика во апликацијата. Апликацијата го вика со `WHERE user_id = 42 AND read_at IS NULL`.131 VIEW-то ја пресметува „староста во минути“ за да прикаже „пред 5 мин“ без дополнителна логика во апликацијата. Апликацијата го повикува со `WHERE user_id = 42 AND read_at IS NULL`. 132 132 133 === v_driver_earnings — Мои приходи во месец133 === v_driver_earnings — Мои месечни приходи 134 134 135 Возачот кликн е "Финансиски извештај". Вижи:136 - За секој месец колку возења направил 137 - Колку резервации наплатил (можеби некој отказал во последниотмомент)138 -Вкупен приход139 -Просечен приход по резервација140 -Максимален приход141 -Минимален приход135 Возачот кликнува на „Финансиски извештај“ и гледа: 136 * Колку возења направил за секој месец 137 * Колку резервации наплатил (некои можеби биле откажани во последен момент) 138 * Вкупен приход 139 * Просечен приход по резервација 140 * Максимален приход 141 * Минимален приход 142 142 143 Администраторот го користи и за анализа — ако возачот нема приход три месеца, веројатно е неактивен. 144 145 Пресметува на основа на `bookings` со статус `completed` (само завршени) и нивните финални суми. 143 Администраторот го користи ова и за анализа — ако возачот нема приход три месеци, веројатно е неактивен. Пресметката се базира на `bookings` со статус `completed` и нивните финални суми. 146 144 147 145 === v_route_popularity — Кои рути се најпопуларни 148 146 149 Апликацијата на почетниот екран прикажува популарни рути за да го вдахновува патникот. Ова view-ot ги рангира:150 - По број на вкупни резервации151 -Просечна цена по резервација152 -Просечна цена по километар147 Апликацијата на почетниот екран прикажува популарни рути за да го мотивира патникот. Овој поглед ги рангира рутите според: 148 * Број на вкупни резервации 149 * Просечна цена по резервација 150 * Просечна цена по километар 153 151 154 Служи и како сигнал за возачите. Ако рутата Скопје↔Куманово има 50 резервации месечно, но возачот направил 10 возења и не продал ништо — сигнал е дека нешто не е окај. Можеби е превиско скапо, или нема добро рекламирано возење.152 Служи и како сигнал за возачите. Ако рутата Скопје↔Куманово има 50 резервации месечно, а возачот направил 10 возења и не продал ништо — тоа е знак дека нешто не е во ред (можеби е прескапо или возењето не е добро рекламирано). 155 153 156 154 === v_incident_summary — Безбедносни инциденти 157 155 158 Само администраторот видува ова. Прикажува:159 - Тип на инцидент (невежливост, несреќа, кршење направила)160 -Опис на инцидентот161 -Кога е пријавен162 -Лични податоци на пријавувачот (патник или возач)163 -Лични податоци на другата страна164 - Возачка дозвола број 165 - Рутата на возењето156 Ова го гледа само администраторот. Прикажува: 157 * Тип на инцидент (некултурно однесување, несреќа, кршење правила) 158 * Опис на инцидентот 159 * Кога е пријавен 160 * Лични податоци на пријавувачот (патник или возач) 161 * Лични податоци на другата страна 162 * Број на возачка дозвола 163 * Рута на возењето 166 164 167 Инцидентите мо гат да будат пријавени дури и после завршено возење, така да view-ot не филтрира по статус на возење.165 Инцидентите можат да бидат пријавени дури и по завршено возење, па затоа овој поглед не филтрира според статусот на возењето. 168 166 169 167 == Важно: NULL вредности со логика 170 168 171 Неколку полиња се NULL базиранона логика:169 Неколку полиња се NULL врз основа на одредена логика: 172 170 173 * `rides.recurrence_days` и `rides.recurrence_end_date` — се пополнуваат САМО ако `is_recurring = TRUE`. За еднократни возења се NULL. 171 * `rides.recurrence_days` и `rides.recurrence_end_date` — се пополнуваат САМО ако `is_recurring = TRUE`. За еднократни возења тие се NULL. 172 * `bookings.pickup_stop_id` и `bookings.dropoff_stop_id` — ако патникот ја резервира целата рута, стоповите се почетната и крајната точка. Ако резервира само дел, се пополнуваат конкретните стопови. 174 173 175 * `bookings.pickup_stop_id` и `bookings.dropoff_stop_id` — ако патникот резервира целата рута, стоповите се почеток и крај. Ако резервира дел, се полнат конкретни стопови. 176 177 Апликацијата треба да проверува ова пред да користи вредностите. 174 Апликацијата треба да ги проверува овие услови пред да ги користи вредностите.
