Skip to main content
Back to Projects ArchiveProject 03 of 04
University Engineering Project • DCIT 208Fleet Inventory & Backoffice Engine
Raku logo icon

Raku Automobiles

Vehicle Rental Management & Fleet Operations Platform

A full-stack fleet inventory, client reservations, and operations management platform engineered for a luxury automobile rental business in Ghana. Built as a collaborative university team project for DCIT 208 Software Engineering at the University of Ghana, featuring PostgreSQL btree_gist exclusion constraints to mathematically prevent double-bookings and an asynchronous Supabase identity bridge.

My Role

Product/Client Manager & Contributor

Academic Context

DCIT 208 Software Engineering

Team Structure

SEG26-08 (7 Team Members)

Real Client

Raku Automobiles (Eric Asante, CEO)

React 19ViteReact Router v7Express API (Serverless)PostgreSQL (Supabase)btree_gist ConstraintsSupavisor PoolerSupabase AuthRechartsNode.js Test Runner (11 Tests)
https://raku-rentals.vercel.app
Verified Staging Deployment
Raku Automobiles vehicle rental discovery portal landing hero
01 • EXECUTIVE SUMMARY

Project Overview & Client Context

01

The Client Challenge

Operating purely on Instagram and Snapchat (@raku.mgr), Raku lacked a central booking registry, causing frequent overlapping reservations and uncoordinated manual pricing.

02

The Engineering Solution

Engineered a decoupled React 19 frontend with an Express API on Vercel Serverless and PostgreSQL, enforcing physical reservation non-overlap via GiST exclusion constraints at the database tier.

03

Customer Self-Service

Transparent vehicle catalogue browsing across SUVs, luxury sedans, and economy tiers with instant server-calculated rental quotes, Supabase Auth verification, and personal booking history.

04

Operational Fleet Control

Role-gated fleet management backoffice featuring vehicle CRUD, Supabase Storage photo uploads, Recharts analytics, reservation lifecycle state transitions, and vehicle maintenance status tracking.

02 • THE PROBLEM

Client Bottlenecks: Operating an Automobile Business Without a Platform

Direct findings from the initial client discovery interview with CEO Eric Kweku Asante.

Raku Automobiles operates in the competitive Ghanaian vehicle sales and rental market, supplying economy sedans, executive SUVs, and luxury wedding/event rentals to private individuals and corporate clients. Despite commanding high-value vehicle inventory (including Range Rovers and Honda Accords), the enterprise operated entirely without a central digital web presence. Inventory was marketed through social media posts on Instagram and Snapchat (@raku.mgr), and all customer inquiries, date checks, and bookings were negotiated manually through phone calls and fragmented WhatsApp chats.

Double-Booking Collisions on Peak Dates

High-demand weekend slots (weddings, executive delegations, regional travel) frequently resulted in staff committing the same vehicle to different clients in parallel WhatsApp conversations. Discovering overlaps at pickup required awkward client cancellations or emergency vehicle swaps.

Fragmented Identity Records & Lost History

Driver verification documents, phone numbers, and rental receipts were decentralized across staff phones. The business had no ledger to verify customer return histories, track repeat client discounts, or trace past damage incidents.

Information Asymmetry & Enquiries Fatigue

Prospective customers could not view real-time fleet availability, vehicle specifications, or daily rates without initiating direct messaging. Staff spent hours answering repetitive availability inquiries instead of managing vehicle readiness.

Operational Blindness on Fleet Utilization

Management had no visibility into fleet utilization metrics, maintenance rollover schedules, or overdue returns. Vehicle turnaround maintenance occurred reactively rather than proactively.

03 • INDIVIDUAL CONTRIBUTION

My Role: Product/Client Manager & Hands-On Contributor

Bridging client business requirements with concrete software engineering implementation.

In team projects of this scale, engineering success is determined as much by disciplined requirements definition and scope management as by code syntax. As Product/Client Manager for team SEG26-08, I held primary responsibility for managing the client relationship with Raku CEO Eric Kweku Asante while actively developing core backend logic, automated test suites, and operational dashboards.

01

Stakeholder Discovery & Client Communication

Spearheaded the initial discovery call with CEO Eric Kweku Asante, transcribed operational pain points, and maintained weekly progress touchpoints throughout the 4 sprint cycles.

02

Requirements Engineering & MoSCoW Prioritization

Authored user stories and acceptance criteria. Applied MoSCoW prioritization to isolate Must-Haves (double-booking exclusion constraint, fleet catalogue) from Could-Haves (live MoMo checkout, automated hold timers).

03

Backend Reservation Creation & Server Pricing

Engineered the POST /api/bookings route handler in Express. Enforced authoritative server-calculated pricing from vehicle daily rates (daily_rate * nights), rejecting client-supplied totals.

04

Identity-Bridge Implementation

Designed and built the POST /api/auth/register endpoint to bridge Supabase Auth accounts to PostgreSQL customer records idempotently, extracting verified names and phones from JWT metadata.

05

Concurrency Conflict & Authorization Testing

Authored automated tests in Node.js test runner and Supertest verifying SQLSTATE 23P01 conflict trapping (409 Conflict), invalid date ranges (400), and customer-scoped data access gates (401/403).

06

Client UAT & Final Handoff Pack

Structured user acceptance test scenarios for the client demo, managed issue remediation, compiled the deployment operations manual, and prepared presentation materials for the final defense.

04 • ARCHITECTURE & STACK

Decoupled Multi-Tier System Architecture

Clean separation of concerns across presentation, serverless routing, and relational data guarantees.

1. Client TierSPA

React 19, Vite, React Router v7, Tailwind CSS, Framer Motion transitions, and Recharts analytics.

2. API GatewayExpress

Express 4 on Vercel Serverless Functions. Auth middleware, structured JSON logging, and Resend email alerts.

3. Connection PoolSupavisor

Supavisor transaction pooler on port 6543 via pg pool, preventing connection exhaustion on serverless scale.

4. Database TierPostgres

PostgreSQL (Supabase) with btree_gist exclusion constraint, Row-Level Security, and Supabase Storage.

Key Architecture Decision Records (ADRs)

ADR-001: GiST Exclusion

Delegate reservation concurrency completely to PostgreSQL GiST exclusion rather than fragile application-tier checks.

ADR-002: Identity Bridge

Decouple customer profiles from auth accounts via user_account, enabling walk-in records and safe signup verification.

ADR-003: Supavisor Pooling

Connect Express serverless invocations through Supavisor port 6543 to eliminate Postgres connection timeouts during bursts.

05 • DEEP DIVE: CONCURRENCY

Eliminating Double-Bookings with PostgreSQL GiST Constraints

Why application-level availability queries fail under concurrency, and how database-tier intervals guarantee mutual exclusion.

The Race Condition Flaw in Application-Tier Checks

In conventional booking systems, availability is checked with an application-tier query like SELECT COUNT(*) FROM booking WHERE vehicle_id = X AND dates_overlap, followed by an INSERT. Under simultaneous traffic (two customers reserving the Range Rover for the same weekend), both requests check availability at the exact same millisecond, both read 0 conflicts, and both insert reservations. This classic Time-of-Check to Time-of-Use (TOCTOU) race condition renders application-level validation fundamentally unreliable.

The Database-Level Solution: btree_gist and Half-Open Intervals

To solve this permanently, we enabled the PostgreSQL btree_gist extension and created an exclusion constraint on the booking table. Rental periods are modeled using tstzrange with half-open [) semantics (inclusive start, exclusive end).

Half-open intervals mean an abutting booking ending at 10:00 AM does not overlap with a new booking starting at 10:00 AM on the same day. If any concurrent transaction attempts to insert an overlapping interval for the same vehicle, the PostgreSQL storage engine aborts the insert with error SQLSTATE 23P01 (exclusion_violation), which the Express backend cleanly maps to an HTTP 409 Conflict.

supabase/migrations/0001_init_schema.sql — Authoritative Exclusion Constraint
-- Enable btree_gist for equality '=' operator on UUID alongside range overlap '&&'
create extension if not exists btree_gist;

-- Booking entity with half-open timestamp range
create table booking (
    booking_id    uuid primary key default gen_random_uuid(),
    customer_id   uuid not null references customer (customer_id) on delete restrict,
    vehicle_id    uuid not null references vehicle (vehicle_id) on delete restrict,
    rental_period tstzrange not null,
    status        text not null check (status in ('Hold', 'Confirmed', 'Active', 'Completed', 'Cancelled')),
    total_amount  numeric(10,2),
    created_at    timestamptz not null default now(),
    constraint booking_period_nonempty check (not isempty(rental_period))
);

-- ADR-001: The authoritative physical non-overlap guarantee.
-- Abutting rentals (end_ts == next start_ts) do NOT collide under '[)' bounds.
-- Cancelled/Completed bookings immediately free the slot via the partial predicate.
alter table booking
    add constraint exclude_vehicle_double_booking
    exclude using gist (
        vehicle_id    with =,
        rental_period with &&
    )
    where (status in ('Confirmed', 'Active', 'Hold'));
backend/api/index.js — Conflict Trapping & HTTP 409 Mapping
// Source: raku-rentals/backend/api/index.js
try {
  const { rows } = await pool.query(
    `insert into booking
       (customer_id, vehicle_id, rental_period, status, total_amount)
     values
       ($1, $2, tstzrange($3::timestamptz, $4::timestamptz, '[)'), 'Hold', $5)
     returning booking_id, customer_id, vehicle_id, rental_period, status, total_amount`,
    [req.customerId, vehicle_id, start_ts, end_ts, total_amount]
  );
  return res.status(201).json(rows[0]);

} catch (err) {
  if (err.code === '23P01') {
    // GiST exclusion constraint (exclude_vehicle_double_booking) triggered
    return res.status(409).json({
      error: 'booking_conflict',
      message: 'This car is already booked for those dates. Please choose different dates.',
    });
  }
  console.error('POST /api/bookings failed:', err.code, err.message);
  return res.status(500).json({ error: 'database_error' });
}
06 • DEEP DIVE: AUTHENTICATION

The Asynchronous Supabase Identity Bridge

Solving the authentication timing gap when email verification delays session issuance.

The Registration Timing Challenge

Supabase Auth enforces email confirmation before issuing a valid authenticated JWT session. When a prospective customer signs up on the frontend, supabase.auth.signUp() creates an unconfirmed record in auth.users, but no active session is returned. Consequently, the frontend cannot execute an authenticated API call to create a customer profile in the database at signup time.

We solved this by retaining customer metadata (full_name and phone) in the Supabase user metadata payload during signup. Upon email confirmation or first login, the frontend invokes our identity bridge: POST /api/auth/register.

Idempotency, Concurrency & Tamper-Proof Metadata

The backend bridge extracts full_name and phone directly from the cryptographically verified JWT payload, preventing client request spoofing. A database transaction checks whether user_account.supabase_auth_id already exists. If found, it returns the customer ID immediately (idempotent no-op). If new, it creates the customer and user_account link.

If a concurrent request races to register, the ON CONFLICT (supabase_auth_id) constraint triggers a rollback of the duplicate customer insert, guaranteeing zero orphan profile records.

backend/api/index.js — Idempotent Identity Bridge Handshake
// Source: raku-rentals/backend/api/index.js
app.post('/api/auth/register', requireAuth, async (req, res) => {
  const uid   = req.authUser.id;
  const email = req.authUser.email;
  // Trust only verified JWT claims — client request body is not trusted
  const meta  = req.authUser.user_metadata || {};
  const fullName = (meta.full_name || '').trim() || 'Unknown';
  const phone    = (meta.phone    || '').trim();

  const client = await pool.connect();
  try {
    await client.query('BEGIN');

    // 1. Fast path: bridge already exists (idempotent on repeat logins)
    const existing = await client.query(
      'select customer_id from user_account where supabase_auth_id = $1',
      [uid]
    );
    if (existing.rows.length) {
      await client.query('COMMIT');
      return res.status(200).json({ customer_id: existing.rows[0].customer_id, created: false });
    }

    // 2. Slow path: create customer profile then link to user_account
    const cust = await client.query(
      'insert into customer (full_name, phone, email) values ($1, $2, $3) returning customer_id',
      [fullName, phone, email]
    );
    const customerId = cust.rows[0].customer_id;

    const ua = await client.query(
      `insert into user_account (supabase_auth_id, customer_id, role)
       values ($1, $2, 'Customer')
       on conflict (supabase_auth_id) do nothing
       returning user_account_id`,
      [uid, customerId]
    );

    if (ua.rows.length === 0) {
      // Concurrent race condition won by another request: roll back customer insert
      await client.query('ROLLBACK');
      const winner = await client.query(
        'select customer_id from user_account where supabase_auth_id = $1',
        [uid]
      );
      return res.status(200).json({ customer_id: winner.rows[0].customer_id, created: false });
    }

    await client.query('COMMIT');
    return res.status(201).json({ customer_id: customerId, created: true });
  } catch (err) {
    await client.query('ROLLBACK');
    return res.status(500).json({ error: 'bridge_failed' });
  } finally {
    client.release();
  }
});
07 • CUSTOMER PORTAL

Customer Journey & Fleet Booking Experience

From vehicle catalog discovery to authenticated reservation tracking.

01

Vehicle Discovery & Filters

Filter fleet inventory by category (SUV, Luxury, Economy, Sedan), daily rate, and seat capacity. Vehicle cards display real-time status badges and high-res photography.

02

Date Range & Authoritative Quotes

Customers choose pickup and return timestamps. The backend calculates total nights and costs authoritatively; browsing does not lock a vehicle until the reservation is committed.

03

Customer Booking Dashboard

Authenticated clients track their booking status (Hold, Confirmed, Active, Completed) with customer-scoped data access.

Featured Fleet Inventory Models

2019 Land Rover Range Rover
2019 Range Rover

Luxury SUV • GH₵ 1,200/day

2020 Honda Accord
2020 Honda Accord

Executive Sedan • GH₵ 450/day

2019 Honda Civic
2019 Honda Civic

Economy Sedan • GH₵ 350/day

Customer Wireframes & Booking Architecture

Customer interface wireframe specificationCustomer UI Wireframes
Customer booking lifecycle and status flow diagramBooking Decision Flow Diagram
08 • FLEET OPERATIONS

Fleet Operations, Management Backoffice & Analytics

Role-gated administration panel for vehicle inventory, reservation approval queues, and fleet metrics.

Raku vehicle rental management dashboard and analytics

Executive KPI Cards & Recharts Trends

Real-time visualization of fleet utilization rate, active bookings count, monthly revenue projections, and category distribution charts powered by Recharts.

Raku fleet manager inventory CRUD and pricing controls

Fleet Inventory CRUD & Status Toggles

Managers create new vehicle profiles, adjust daily rates, upload photos to Supabase Storage, and switch operational statuses between Available, Unavailable, and Maintenance.

Reservation Approval Lifecycle
1. Hold (Submitted)2. Confirmed (Approved)3. Active (Handover)4. Completed (Returned)5. Cancelled (Released)
09 • QUALITY ASSURANCE

Automated Testing Suite & Security Validation

Zero-dependency automated testing running via native Node.js test runner and Supertest.

11 Tests Passing Across 2 Test Suites

Command: npm test (node --test test/bookings.test.js test/auth.test.js) • Zero Failures

Duration: ~8.0s
Reservation & Conflict Tests (bookings.test.js • 6 tests)
  • • POST /api/bookings → 201 with booking_id on happy path
  • • POST /api/bookings with 23P01 exclusion violation → 409 booking_conflict
  • • POST /api/bookings missing end_ts → 400 missing_fields
  • • POST /api/bookings end_ts before start_ts → 400 invalid_period
  • • POST /api/bookings unexpected database error → 500 database_error
  • • GET /api/bookings returns customer-scoped rows (200 OK)
Authentication & Role Tests (auth.test.js • 5 tests)
  • • POST /api/bookings without Authorization header → 401 missing_token
  • • POST /api/bookings with invalid token → 401 invalid_token
  • • POST /api/bookings valid JWT but no customer record → 403 no_customer_record
  • • GET /api/manager/stats with non-manager role → 403 forbidden
  • • GET /api/manager/stats with no role claim → 403 forbidden
Testing Boundary Disclosure

These automated test suites run in isolation using mocked database queries to verify HTTP status codes, JSON response schemas, and authorization middleware logic without requiring live cloud database access. While functional and security gates were verified under unit conditions, a formal third-party penetration test or statutory Ghana Data Protection Act (Act 843) audit was not conducted.

10 • HONEST EVALUATION

Known Limitations & Future Engineering Backlog

Documenting the boundary between delivered MVP capabilities and deferred features.

1. Un-enforced 15-Minute Hold Expiry

When a customer submits a reservation, it enters status Hold. The product specification called for an automated 15-minute expiration timer to release abandoned holds. Because no scheduled background worker (cron) was deployed, abandoned holds remain blocking until a manager manually cancels them.

2. Driver Licence & Ghana Card Collection

The database schema provides columns for drivers_license_no and ghana_card_no in the customer table. However, the customer-facing registration interface does not collect them online; physical driver verification remains handled off-system during vehicle handover.

3. Live Mobile Money Payment Integration

A relational payment table and MoMo reference schema were defined in SQL. However, live API integration with a payment gateway (e.g., Paystack or Hubtel) was scoped out of the frontend checkout flow. Rental charges are collected manually upon vehicle pickup.

4. Mobile Manager Usability Constraints

The manager dashboard was architected for desktop operations. Dense reservations management tables and multi-column Recharts analytics require horizontal scrolling on viewports under 640px, posing usability constraints on mobile devices.

5. Database Backup & Disaster Recovery Tier

The project relies on standard Supabase free-tier daily automated database snapshots. High-availability multi-region replication and automated point-in-time recovery (PITR) were not provisioned under the academic project hosting budget.

11 • TEAM COLLABORATION

Academic Engineering Team • SEG26-08

A collaborative university engineering group for DCIT 208 Software Engineering at the University of Ghana.

Delivering Raku Automobiles required coordinated teamwork across 7 students, governed by a formal Team Charter with weekly Tuesday sprint planning, GitHub pull request code reviews, and transparent AI usage disclosures documented in AI_USAGE_LOG.md.

Godwin Apedo

Product/Client Manager & Contributor

Client discovery, booking route, identity bridge, tests

Lawrence Eklah

DevOps & Release Lead

Vercel deployments, CI workflow, architecture review

Edward Junior Amoah

Documentation & Evidence Lead

Deliverable preparation, user manuals, sprint evidence

Nana Kwabena Boakye Duah

Implementation Lead

Frontend page styling, component architecture, UI integration

Lester Nartey Opata

Validation & QA Lead

Test plan design, quality gates, feature validation

Philip Kese Boadu

Architecture & Context Lead

C4 diagrams, system context, ERD modeling

Abdul-Raziq Nyaaba

UX & Implementation Lead

User flow diagrams, customer wireframes, UI implementation

12 • RETROSPECTIVE

Client Acceptance, Demo Walkthrough & Lessons Learned

Delivering Raku Automobiles as a working staging deployment provided invaluable software engineering lessons in client communication, concurrency modeling, and scope discipline:

1. Grounding Design in Client Reality

Real clients do not communicate in database schemas; they communicate in operational pain points like lost bookings and chaotic weekend handovers. Engineering begins with listening, distilling constraints, and building software that directly eliminates operational risks.

2. Enforcing Invariants at the Database Tier

Relying on application code to prevent concurrency collisions is a trap. Leveraging PostgreSQL storage engine primitives like btree_gist exclusion constraints turns critical business rules into mathematical guarantees that cannot be bypassed by race conditions.

3. Authentication Lifecycle Awareness

Third-party auth providers like Supabase Auth introduce asynchronous verification flows. Designing an explicit identity bridge taught me how to handle distributed state and preserve user metadata without creating orphan records.

4. Scope Discipline & Honest Trade-offs

Academic timelines force hard trade-offs. Shipping a robust core MVP that reliably eliminates double-bookings while openly documenting deferred items (such as the 15-minute hold timer and live payment gateway) is the hallmark of honest software engineering.

Final Demo Video WalkthroughWatch on YouTube ↗
Project 01 • Luxury E-Commerce & Spatial Logistics

MENSAH

Luxury tailoring, deterministic virtual sizing & Haversine courier dispatch prototype.

• Case Study AvailableRead Case Study
Project 02 • Commercial Platform

Chef Apedo Foods

Full-cycle food ordering, real-time kitchen operations & courier dispatch platform.

• Case Study AvailableRead Case Study
Project 04 • Nonprofit Platform & Health Hub

Davcie Foundation

Paediatric diabetes health education, emblem motion physics & authenticated admin portal.

• Case Study AvailableRead Case Study