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)
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.
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.
-- 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'));
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.
// 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.
Role-gated administration panel for vehicle inventory, reservation approval queues, and fleet metrics.
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.
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
• 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.
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.