# Релационен модел ## ЕР дијаграм ![Релационен модел DriveNet](RelationalModel-drive-net.svg) ## Архитектура и главни концепти ### Користачи и нивни улоги Табелите `users`, `drivers` и `passengers` функционираат по принцип на инхеритација. Базната табела `users` содржи основни информации за сите во системот, додека `drivers` и `passengers` се специјализирани и содржат само релевантни атрибути за та улога. Јавно еден кориснички профил може да има и две улоги истовремено — да е и возач и патник. ### Возила и нивна класификација Возилата се организирани во три нивоа: `manufacturers` (производител), `vehicle_models` (модел) и `vehicles` (конкретно возило). Овој пристап спречува дупликување на податоци. Врската помеѓу возачите и возилата е моделирана преку табелата `vehicle_ownership`, која чува целосна историја на сопственост. Кога некој во возачот промени возило, новиот запис се додава, а старите се задржуваат — никогаш не бришеме историја. ### Рути и возења Табелата `routes` е шаблон — претставува дефинирана патека со нејзиниот редослед на застанувања. Табелата `rides` пак претставува конкретно возење кое возачот го организира врз база на таа рута — сакај определен датум, час и возило. Застанувањата на рутата се чувуваат во `route_stops` со редоследен број, што значи рутата може да има колку сакаш застанувања. Истата локација може да се појави повеќе пати (на пример, круговна рута). ### Сегментирање на возења и наплата За прецизна пресметка на цена, возењата се делат на сегменти: - **`route_segments`** — ја дели рутата на делови помеѓу два последователни застанувања - **`passenger_segments`** — чува колку патници биле на секој сегмент и колку треба да плати секој од нив Финалната сума за секоја резервација се чува во `booking_final_fare`. ### Условни полиња (nullable foreign keys) Неколку табели имаат nullable foreign keys, а нивното значење зависи од контекст: - **`bookings.pickup_stop_id` и `bookings.dropoff_stop_id`** — го дефинираат сегментот што го резервира патникот. Ако патникот патува на целата рута, тие се почетниот и крајниот стоп. - **`rides.recurrence_days` и `rides.recurrence_end_date`** — се пополнуваат само кога `is_recurring = TRUE`. За еднократни возења, овие полиња се NULL. ### Система за патарини Три табели работат заедно за управување со патаринските рампи: - **`toll_points`** — наплатни рампи со цена по тип возило - **`ride_tolls`** — евидентира кои рампи се поминати во одредено возење - **`toll_passenger_split`** — ја дели цената рамномерно меѓу патниците кои биле присутни на тој делот ### Готовинско плаќање Апликацијата работи исклучиво со готовина, така што **нема табела за онлајн трансакции**. Табелите `fare_splits` и `booking_final_fare` служат како референцијални алатки — возачот ги користи за да знае колку да собере од секој патник, исё. ### Оценување (Рејтинги) Оценувањето функционира преку табелата `ratings` со CHECK constraint кој спречува самооценување. Оценката на возач/патник не се чува како просто поле, туку се пресметува динамички преку `driver_ratings` и `passenger_ratings` views за да останува во синхрона. ### Историја и следливост Две табели чуваат целосна историја на промени: - **`ride_status_history`** — сите промени на статусот на возење - **`booking_status_history`** — сите промени на статусот на резервација Секоја промена има временска марка, што овозможува целосна следливост. ### Бришење на податоци За да се задржи статистика и обврски дури и кога кориснички профили се избришат, сите foreign keys кон `users` користат `ON DELETE SET NULL` или се поврзуваат со резервиран корисник со `id = 0` ("избришан кориснік"). Foreign keys кон критични табели (`rides`, `routes`, `bookings`) користат `ON DELETE RESTRICT` — не смее ништо да се избрише ако е поврзано. --- ## Прегледи (Views) Базата содржи девет прегледи кои го поедностављуваат најчестиот код во апликацијата. ### `v_available_rides` Ги прикажува сите возења со статус `scheduled` кои се отворени за резервирање. За секое возење ја обединува информацијата за возачот, возилото, марката, моделот, рутата и градовите, плус пресметана проценета цена врз база на должина на рута и цена по км. Просечната оцена на возачот е веќе вклучена. Апликацијата го користи при пребарување — просто добива WHERE за град на почеток, час, итн. ### `v_driver_profile` Комплетна слика на возачкиот профил — лични податоци, возачка дозвола, примарното возило, укупно/завршено/откажано возења и просечна оцена. Koristi ga возачот при ажурирање на своја страна и патникот при проверка со кого се сокува пред резервирање. ### `v_passenger_trip_history` Целосна историја на патувања за секој патник — резервации со статус, име на возач, почеток/крај, потврди за качување/слегување, финална цена и оценка. Секоја резервација е редок (не групиран), што го едностави филтерирањето и пагинирањето во апликацијата. ### `v_ride_manifest` Список на сите потврдени, активни и завршени патници за одредено возење — имиња, телефони, места на качување/слегување, финална цена. Возачот го гледа пред поаѓање за да знае кого чека, каде да застане и колку да наплати. ### `v_driver_earnings` Месечен преглед на приходите по возач. За секој месец прикажува број возења, број наплатени резервации, вкупен приход, просек и min/max по резервација. Корисно е и за возачот (лична финансиска контрола) и за администраторот (анализа на активност). ### `v_route_popularity` Ги рангира рутите по број на резервации. Прикажува просечна цена по резервација и просечна цена по км. Служи за препораки на почетниот екран и за анализа — ако рута има многу возења но малку резервации, сигнал е дека нешто не е окај (премногу скапо, лоша достапност). ### `v_booking_details` Целосна слика на една резервација — патник, возач, возило со регистарски табички, места (со имиња на локации и градови), време поаѓање, статус, финална цена. Користи се при потврда и при генерирање на сметка. Апликацијата секогаш го вика со `WHERE booking_id = ?` — никогаш без филтер. ### `v_unread_notifications` Само непрочитаните нотификации (каде `read_at IS NULL`), збогатени со име на корисник и „старост во минути" за лесна приказ (нпр. „пред 5 минути"). Апликацијата го вика со `WHERE user_id = ?` за конкретниот логиран корисник. ### `v_incident_summary` Административен преглед на пријавени инциденти со целосен контекст — тип, опис, време пријава, лични податоци на пријавувач и возач (вклучувајќи возачка дозвола) и рутата. Наменет исклучиво за администраторот. Прикажува инциденти без оглед на статус на возење, бидејќи инцидент може да се пријави и по завршено возење.