Last active
November 2, 2025 19:54
-
-
Save isocroft/5c69a1e2e349c17fad33486719240c9d to your computer and use it in GitHub Desktop.
A database schema for an InDrive-clone ride hailing app that helps link riders to drivers on frequently-travelled transport routes (pricing based on a fair bargain) based on OpenStreet Maps info using either MySQL, SQLite or PostgreSQL as primary database
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- MySQL v8.0.16 | |
| -- PostgresSQL v16.9.2 | |
| CREATE DATABASE IF NOT EXISTS `test` | |
| DEFAULT CHARACTER SET utf8 -- utf8mb4 | |
| DEFAULT COLLATE utf8_general_ci; -- utf8mb4_unicode_ci | |
| SET default_storage_engine = INNODB; | |
| CREATE TABLE rider_details ( | |
| id bigint NOT NULL, | |
| first_name varchar(90) NOT NULL, | |
| last_name varchar(90) NOT NULL, | |
| email varchar(50) NOT NULL UNIQUE, | |
| profile_avatar_url varchar(130), -- start with value of NULL and use background job to upload image to `cloudinary` OR `aws-s3` an then later write url value back | |
| gender enum('male', 'female') NOT NULL, | |
| date_of_birth date NOT NULL, | |
| registered_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
| CONSTRAINT riderunq UNIQUE (id, first_name, last_name), | |
| PRIMARY KEY (id) | |
| ); | |
| CREATE TABLE driver_details ( | |
| id bigint NOT NULL, | |
| first_name varchar(90) NOT NULL, | |
| last_name varchar(90) NOT NULL, | |
| email varchar(50) NOT NULL UNIQUE, | |
| insurance_policy_number varchar(10) NOT NULL, | |
| insurance_policy_broker varchar(40) NOT NULL, | |
| profile_avatar_url varchar(130), -- start with value of NULL and use background job to upload image to `cloudinary` OR `aws-s3` an then later write url value back | |
| gender enum('male', 'female') NOT NULL, | |
| date_of_birth date NOT NULL, | |
| years_of_experience char(2) NOT NULL, | |
| CONSTRAINT driverunq UNIQUE (id, first_name, last_name, date_of_birth), | |
| PRIMARY KEY (id) | |
| ); | |
| CREATE TABLE user_accounts ( | |
| id bigint NOT NULL, | |
| email varchar(50) NOT NULL UNIQUE, -- data redundancy for easier access | |
| full_name varchar(150) NOT NULL, -- data redundancy for easier access | |
| password varchar(36) NOT NULL, | |
| last_login_at timestamp, | |
| profile_avatar_url varchar(130), -- start with value of NULL and use background job to upload image to `cloudinary` OR `aws-s3` an then later write url value back | |
| email_verified tinyint(1) NOT NULL DEFAULT 0, | |
| account_type enum('driver', 'rider') NOT NULL, | |
| rider_id bigint UNIQUE NULL, -- if `account_type` is 'driver' then this column is NULL else it contains a valid rider id | |
| driver_id bigint UNIQUE NULL, -- if `account_type` is 'rider' then this column is NULL else it contains a valid rider id | |
| PRIMARY KEY(id), | |
| FOREIGN KEY(rider_id) REFERENCES rider_details(id) ON DELETE CASCADE, | |
| FOREIGN KEY(driver_id) REFERENCES driver_details(id) ON DELETE CASCADE | |
| ); | |
| ALTER TABLE user_accounts ADD CONSTRAINT chk_accounttype_driver_rider_null_on_rows CHECK (account_type = 'driver' AND rider_id IS NULL AND driver_id IS NOT NULL); | |
| ALTER TABLE user_accounts ADD CONSTRAINT chk_accounttype_rider_driver_null_on_rows CHECK (account_type = 'rider' AND driver_id IS NULL AND rider_id IS NOT NULL); | |
| CREATE TABLE vehicles ( | |
| id bigint NOT NULL, | |
| vehicle_type enum('car', 'suv-jeep') NOT NULL, | |
| owner_id bigint NOT NULL, | |
| maker_specs enum('toyota-camry', 'toyota-corolla', 'toyota-4runner', 'honda-city', 'lexus-es350', 'nissan-patrol', 'honda-accord', 'peugeot-406', 'honda-civic', 'peugeot-302', 'audi-', 'benz-C-class', 'benz-S-class', 'bmw', 'toyota-siena') NOT NULL, | |
| engine_specs enum('v6-single-transmission_4cyl', 'v8-double-transmission_6cyl') NOT NULL, | |
| fueltank_specs enum('100l-guage', '120l-guage') NOT NULL, | |
| plate_number varchar(10) NOT NULL, | |
| color enum('red', 'black', 'white', 'green', 'cream', 'gray', 'blue') NOT NULL, | |
| model_year char('4'), | |
| particulars_status json NOT NULL DEFAULT (JSON_OBJECT()), -- e.g. '{ "valid_driver_license": true, "valid_vio-inspection_kits": false }' | |
| enrolled_at timstamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
| PRIMARY KEY(id), | |
| FOREIGN KEY(owner_id) REFERENCES driver_details(id) ON DELETE CASCADE | |
| ); | |
| CREATE TABLE rides ( | |
| id bigint NOT NULL, | |
| vehicle_id bigint NOT NULL, | |
| status_started tinyint(1) NOT NULL DEFAULT 0, | |
| status_completed tinyint(1) NOT NULL DEFAULT 0, | |
| status_cancelled tinyint(1) NOT NULL DEFAULT 0, | |
| departure_time DATETIME, | |
| arrival_time DATETIME, | |
| PRIMARY KEY(id), | |
| FOREIGN KEY(vehicle_id) REFERENCES rider_vehicles(id) ON DELETE CASCADE | |
| ); | |
| ALTER TABLE rides ADD CONSTRAINT chk_ride_req_stats_startd CHECK (status_cancelled <> 1 AND (status_started = 1 OR status_started = 0)); | |
| ALTER TABLE rides ADD CONSTRAINT chk_ride_req_stats_cancld CHECK (status_completed <> 1 AND (status_cancelled = 0 OR status_cancelled = 1)); | |
| ALTER TABLE rides ADD CONSTRAINT chk_ride_req_stats_compltd CHECK (status_started = 1 AND (status_completed = 0 OR status_completed = 1)); | |
| CREATE TABLE booking_requests ( | |
| id bigint NOT NULL, | |
| booker_id bigint NOT NULL, | |
| status_cancelled tinyint(1) NOT NULL DEFAULT 0, | |
| status_confirmed tinyint(1) NOT NULL DEFAULT 0, | |
| status_executed tinyint(1) NOT NULL DEFAULT 0, | |
| payment_type enum('cash', 'card', 'bank-transfer') NOT NULL, | |
| booked_on DATETIME NOT NULL, | |
| has_multiple_stops tinyint(1) NOT NULL DEFAULT 0, | |
| payment_currency enum('NGN-kobo', 'USD-cents', 'KSH-cents') NOT NULL, | |
| estimated_base_fare bigint NOT NULL DEFAULT 0, | |
| surge_multiplier decimal(1, 1) NOT NULL DEFAULT 0, | |
| route_info json NOT NULL DEFAULT(JSON_OBJECT()), -- ('{ "pickup_location_latlng": null, "dropoff_location_latlng": null, "ETA": "0-seconds", "total_distance_travelled": "0-metres", "departure_time": null, "arrival_time": null, "traffic_conditions": { "status": "conjested" }, "intermediate_stops": [{ lat_lng }, {lat_lng}] }') | |
| PRIMARY KEY(id), | |
| CONSTRAINT idbookedonunq UNIQUE(id, booker_id, booked_on), | |
| FOREIGN KEY(booker_id) REFERENCES rider_details(id) ON DELETE CASCADE | |
| ); | |
| ALTER TABLE booking_requests ADD CONSTRAINT chk_bkng_req_stats_cancld CHECK (status_confirmed <> 1 AND (status_cancelled = 0 OR status_cancelled = 1)); | |
| ALTER TABLE booking_requests ADD CONSTRAINT chk_bkng_req_stats_confmd CHECK (status_cancelled <> 1 AND (status_confirmed = 0 OR status_confirmed = 1)); | |
| ALTER TABLE booking_requests ADD CONSTRAINT chk_bkng_req_stats_exectd CHECK (status_confirmed = 1 AND (status_executed = 0 OR status_executed = 1)); | |
| CREATE TABLE ride_bookings ( | |
| booking_id bigint NOT NULL, | |
| ride_id bigint NOT NULL, | |
| driver_id bigint NOT NULL, | |
| rider_and_payer_id bigint NOT NULL, | |
| amount_paid bigint, | |
| payment_currency enum('NGN-kobo', 'USD-cents', 'KSH-cents') NOT NULL, | |
| status enum('assigned', 'en_route-to-arrival', 'en_route-to-destination', 'ended') NOT NULL, | |
| created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
| PRIMARY KEY(booking_id, ride_id), | |
| CONSTRAINT bookingsunq UNIQUE (booking_id), | |
| CONSTRAINT ridesunq UNIQUE (ride_id), | |
| FOREIGN KEY(booking_id) REFERENCES bookings(id) ON DELETE CASCADE, | |
| FOREIGN KEY(ride_id) REFERENCES rides(id) ON DELETE CASCADE, | |
| FOREIGN KEY(driver_id) REFERENCES driver_detailsn(id) ON DELETE CASCADE, | |
| FOREIGN KEY(rider_and_payer_id) REFERENCES rider_details (booker_id) ON DELETE CASCADE | |
| ); | |
| -- This table is populated after the fact (i.e. after the peer-to-peer exchange) | |
| CREATE TABLE cached_ride_booking_convo_thread_messages ( | |
| id bigint NOT NULL, | |
| booking_id bigint NOT NULL, | |
| ride_id bigint NOT NULL, | |
| parent_id bigint, | |
| author_id bigint NOT NULL, | |
| content text, | |
| created_at datetime NOT NULL, | |
| PRIMARY KEY(id), | |
| FOREIGN KEY(parent_id) REFERENCES ride_booking_convo_thread_messages (id) ON DELETE NO ACTION, | |
| FOREIGN KEY(author_id) REFERENCES user_accounts (id) ON DELETE CASCADE, | |
| -- @SEE: 👇🏾 https://stackoverflow.com/a/10566463 | |
| FOREIGN KEY (booking_id, ride_id) REFERENCES ride_bookings (booking_id, ride_id) ON DELETE CASCADE | |
| ); | |
| CREATE TABLE ride_reviews ( | |
| id bigint NOT NULL, | |
| ride_id bigint NOT NULL, | |
| reviewer_id bigint NOT NULL. | |
| rating enum('1-star', '2-star', '3-star', '4-star', '5-star') NOT NULL, | |
| comment text, | |
| PRIMARY KEY(id), | |
| FOREIGN KEY(reviewer_id) REFERENCES rider_details(id) ON DELETE NO ACTION, | |
| FOREIGN KEY(ride_id) REFERENCES rides(id) ON DELETE CASCADE, | |
| ); | |
| CREATE TABLE ride_routes ( | |
| id bigint NOT NULL, | |
| ride_id bigint NOT NULL, | |
| driver_id bigint NOT NULL, | |
| rider_id bigint NOT NULL, | |
| country varchar(20) NOT NULL, | |
| origin_latlng point NOT NULL, | |
| destination_latlng point NOT NULL, | |
| PRIMARY KEY (id), | |
| SPATIAL INDEX `SPATIAL` (origin_latlng), | |
| SPATIAL INDEX `SPATIAL` (destination_latlng) | |
| FOREIGN KEY (ride_id) REFERENCES rides (id) ON DELETE CASCADE, | |
| FOREIGN KEY (driver_id) REFERENCES driver_details (id) ON DELETE CASCADE, | |
| FOREIGN KEY (rider_id) REFERENCES rider_details (id) ON DELETE CASCADE, | |
| ); | |
| CREATE TABLE ride_routes_telemetry ( | |
| id bigint NOT NULL, | |
| ride_id bigint NOT NULL UNIQUE, | |
| speed_kmh decimal(5, 2), | |
| altitude_m decimal(7, 2), | |
| avg_speed_kmh decimal(5, 2), | |
| max_speed_kmh decimal(5, 2), | |
| cadence_rpm int, | |
| PRIMARY KEY (id), | |
| FOREIGN KEY (ride_id) REFERENCES rides (id) ON DELETE CASCADE | |
| ); | |
| CREATE TABLE ride_routes_telemetry_metrics ( | |
| id bigint NOT NULL, | |
| telemetry_id bigint NOT NULL, | |
| metric_key varchar(40) NOT NULL, | |
| metric_value decimal(8, 2) NOT NULL, | |
| PRIMARY KEY (id), | |
| FOREIGN KEY (telemetry_id) REFERENCES ride_routes_telemetry (id) ON DELETE CASCADE | |
| ); | |
| INSERT INTO rider_details (id, first_name, last_name, profile_avatar_url, gender, email, date_of_birth) VALUES | |
| (6, 'Okuns', 'Babatunde', 'https://res.cloudinary.com/rider_avatars/image/upload/w_250,h_250,c_fill/headshot_1.jpg', 'male', 'okunsb@gmail.com', '1989-11-20'), | |
| (2, 'Steven', 'Okafor', 'https://res.cloudinary.com/rider_avatars/image/upload/w_250,h_250,c_fill/headshot_2.jpg', 'male', 'steve.okaffor@gmail.com', '1991-08-17'), | |
| (8, 'Chidinma', 'Okondor', 'https://res.cloudinary.com/rider_avatars/image/upload/w_250,h_250,c_fill/headshot_3.jpg', 'female', 'chisweete@yahoo.com', '1991-05-30'), | |
| (5, 'Tania', 'Beyshima', 'https://res.cloudinary.com/rider_avatars/image/upload/w_250,h_250,c_fill/headshot_4.jpg', 'female', 'beyshim.tania2hotmail.com', '1995-03-26'); | |
| INSERT INTO driver_details (id, first_name, last_name, insurance_policy_number, insurance_policy_broker, profile_avatar_url, gender, email, date_of_birth, years_of_experience) VALUES | |
| (2, 'Rueben', 'George', '5940044883', 'ARK-AIICO', 'https://res.cloudinary.com/driver_avatars/image/upload/w_250,h_250/sample_1.jpg', 'male', 'reuby445@gmail.com', '1997-11-14', '4'), | |
| (4, 'Adeolu', 'Obalende', '9901237754', 'Applus-Leadway', 'https://res.cloudinary.com/driver_avatars/image/upload/w_200,h_200/sample_2.jpg', 'male', 'adeobale.nde@example.com', '1999-03-22', '3'), | |
| (1, 'Felix', 'Obioha', '6543280117', 'NorthLink-NEM', 'https://res.cloudinary.com/driver_avatars/image/upload/w_250,h_250/sample_3.jpg', 'male', 'felix23@gmail.com', '1990-08-15', '5'), | |
| (5, 'Sandra', 'Arubojah', '9840021365', 'ARK-AIICO', 'https://res.cloudinary.com/driver_avatars/image/upload/w_260,h_260/sample_4.jpg', 'female', 'sandra.arubo@yahoo.com', '1993-12-06', '2'); | |
| INSERT INTO user_accounts (id, email, password, full_name, profile_avatar_url, last_login_at, email_verified, account_type, rider_id, driver_id) VALUES | |
| (3, 'felix23@gmail.com', 'hash_passw_z3', 'Felix Obioha', 'https://res.cloudinary.com/driver_avatars/image/upload/w_250,h_250/sample_3.jpg', '2025-09-12 13:47:10', 1, 'driver', NULL, 1), | |
| (6, 'sandra.arubo@yahoo.com', 'hash_pasw_q0', 'Sandra Arubojah', 'https://res.cloudinary.com/driver_avatars/image/upload/w_260,h_260/sample_4.jpg', '2025-11-02 08:12:56', 1, 'driver', NULL, 5), | |
| (7, 'reuby445@gmail.com', 'hash_pass_e8', 'Rueben George', 'https://res.cloudinary.com/driver_avatars/image/upload/w_250,h_250/sample_1.jpg', '2024-12-11 15:40:16', 0, 'driver', NULL, 2), | |
| (11, 'adeobale.nde@example.com', 'hash_pass_t5', 'Adeolu Obalende', 'https://res.cloudinary.com/driver_avatars/image/upload/w_200,h_200/sample_2.jpg', '2025-10-31 10:24:22', 1, 'driver', NULL, 4), | |
| (10, 'chisweete@yahoo.com', 'hash_pass_k9', 'Chidinma Okondor', 'https://res.cloudinary.com/rider_avatars/image/upload/w_250,h_250,c_fill/headshot_3.jpg', '2025-11-02 16:33:11', 1, 'rider', 8, NULL); | |
| INSERT INTO vehicles (id, vehicle_type, owner_id, maker_specs, engine_specs, fueltank_specs, plate_number, color, model_year) VALUES | |
| (2, 'car', 1, 'toyota-corolla', 'v6-single-transmission_4cyl', '100l-guage', 'BEN-315HM', 'red', '2019'), | |
| (3, 'car', 5, 'honda-civic', 'v6-single-transmission_4cyl', '120l-guage', 'KJA-193AA', 'black', '2014'), | |
| (10, 'car', 4, 'toyota-camry', 'v6-single-transmission_4cyl', '100l-guage', 'GAK-874XH', 'cream', '2012'); | |
| INSERT INTO rides (id, vehicle_id, status_cancelled, status_completed, status_started, departure_time, arrival_time) VALUES | |
| (3, 3, 0, 1, 1, '2025-11-02 17:26:50', '2025-11-02 18:12:08'); | |
| INSERT INTO booking_requests (id, booker_id, status_confirmed, status_cancelled, status_executed, payment_type, booked_on, has_multiple_stops, payment_currency, surge_multiplier, estimated_base_fare) VALUES | |
| (2, 8, 1, 0, 1, 'card', '2025-11-02 17:04:19', 0, 'NGN-kobo', 0.1, 150000); | |
| INSERT INTO ride_bookings (booking_id, ride_id, driver_id, rider_and_payer_id, amount_paid, payment_currency, estimated_payable_fare, status) VALUES | |
| (2, 3, 5, 2, 250000, 'NGN-kobo', JSON_ARRAY(150000, 320000), 'ended'); | |
| INSERT INTO ride_routes (id, ride_id, driver_id, rider_id, country, origin_latlng, destination_latlng) VALUES | |
| (1, 3, 5, 8, 'Nigeria', POINT(40.71727401 -74.00898606), POINT(42.71924401 -64.02896677)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.